文前小谈
最近一直在做知识总结,细心的师傅估计在之前的文章中也看到了,之前一直有一些总结类的文章发到公众号上。
等过段时间空下来了,我在把这种总结类的文章全部放在一个专栏里面,供师傅们翻阅查找。
这篇文章也是最近写的RCE中的一个Perl中open命令执行的小点,RCE总结完整版估计需要一段时间才能写完,因为没有找到一些比较完整且比较好的靶场环境,所以要自己一个一个知识点去搭建靶场找真题,有点费时间。
环境
这题环境我是在BUUCTF里面打开的,师傅们有想复现的直接在BUUCTF里面搜[HITCON 2017]SSRFme这个题目就好了。
源码
192.168.122.180 <?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__);
代码审计
首先$_SERVER方式把HTTP_X_FORWARDED_FOR给请求过来,然后通过explode函数分割,在把ip地址截取出来,在用echo函数输出出来,这就是我们第一行看到的IP地址
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
sandbox变量为sandbox/后面拼接一个(orange拼接输出的ip)的MD5值在通过
@mkdir($sandbox);
@chdir($sandbox);
创建sandbox这个目录
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
这里的GET不是我么平常的GET方法传参,这里的GET是Lib for WWW in Perl中的命令 目的是模拟http的GET请求,GET函数底层就是调用了open处理
首先我们到kali里面去测试一下这个GET有什么作用
这里GET一个根目录,功能类似于ls把它给列出来
可以读取文件
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
那么这句代码的意思就是,把shell_exec中GET过来的结果保存到escapeshellarg中用get(此处get为get请求)接收的参数中,并且这个参数是可以在shell命令里使用的参数。
然后用pathinfo函数分割get过来的filename,最后替换点,截取前面目录,最终用file_put_contents函数把之前$data给写进这个目录里面。知道了代码的流程我们就可以构造我们的参数了。
构造参数
首先我们GET根目录且让其放进test目录里
然后我们对其访问,路径是sandbox+拼接的MD5值+test
根目录下有flag和readflag文件,但是打不开,我们要利用readflag去读取flag,接下来就到我们标题所说的
Perl中open命令执行(GET)内容了。
因为GET的底层是使用open函数的,如下
file.pm84: opendir(D, $path) or132: open(F, $path) or returnnew
而这个open函数会导致我们的RCE,最终造成GET的RCE
因为GET使用file协议时候会调用perl中的open函数
所以我们这题就需要利用file来进行绕过了。
这里够造了好久也没构造出来,看了下wp,执行命令需要满住如下条件
要执行的命令先前必须要有以命令为文件名的文件存在(这里不是很理解,大佬可以告知一下)
既然要满住这个条件,那我们构造的payload如下
1、?url=&filename=|/readflag2、?url=file:|/readflag&filename=test
最终访问拿到flag