打开环境后给了一串代码
117.136.0.16 <?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__);
简单的代码审计一下,第一个if为了是确保$_SERVER['REMOTE_ADDR']里面获得的是真实ip,而不是代理ip,接着创建了一个文件,文件的路径是sandbox/(orange加ip值)的md5加密,然后切换到了这个文件路径。不难理解shell_exec是执行shell代码的意思,escapeshellarg可以百度,可这个GET并没有看懂。
GET是perl(一种语言)里面的语法,在shell里是可以执行的,当GET后面加文件路径的时候,意为读取该文件或目录的内容。而GET也可以进行命令执行,因为GET底层实现使用的是perl里面的open函数,而open函数可以执行命令,所以我们可以用GET来执行命令。要让GET执行命令,当GET使用file协议的时候就会调用到perl的open函数,这就是我们要利用的点。
pathinfo就是以数组的形式返回文件路径的信息
- [dirname] //路径名
- [basename] //文件名
- [extension] //扩展名
basename() 函数返回路径中的文件名部分。
比如$_GET["filename"]=/123/321,经过$info["dirname"]后等于/123,在经过basename后等于123,然后再此目录下创建一个123文件,进入到文件里,把$data的内容写入到文件里。
那意思就是url我可以传入一个想要读取的文件路径,然后shell_exec执行(GET 文件路径),最后会把执行的结果写入我传入的filename里面,然后我就可以去读取filename里面的内容,去查看结果了。方法明确后,开始构造payload
先看看根目录/
?url=/&filename=coconut
然后去查看文件(注意md5加密要用小写,因为大写打不开。。。)
可以看到有个flag和readflag,因为之前遇到过,猜想基本都是直接读flag打不开,读readflag是个二进制的,所以readflag应该是个程序,要执行它让它去读flag。
果然是这样的,因为传入/readflag后GET只是打开文件,把文件内容写到了coconut里面,所以是乱码。
注意:
Perl的open函数会执行给open函数所传递的文件名参数中的系统命令,但是前提是这个文件名是需要存在的。这道题因为文件名是可以控制的,所以就先生成一个以读取flag命令命名的文件。因为perl里的GET函数底层就是调用了open处理,而首先得满足前面的文件存在, 才会继续到open语句, 所以在执行命令前得保证有相应的同名文件。
这里又要用到让GET去执行程序,构造payload
?url=&filename=|/readflag //要有个管道符,我也不知道为啥,可能open函数命令执行的时候就需要吧0.0有大佬请指教~
?url=file:|/readflag&filename=coconut
最后得到flag