讲在前面
命令行注入漏洞的存在,一般需要web应用有调用系统可执行命令的函数,并且输入参数是可控的,这时候如果拼接了注入命令,就可以进行非法操作了。
本人实验所用操作系统为kali linux,在web应用中会调用bash命令行工具进行操作。(在Windows中则是调用DOS命令行)
一、Low
1.1 服务器代码
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
代码十分简单,就是在接收输入值之后直接拼接命令,没有做任何过滤
1.2 漏洞利用
由于没有任何过滤,直接拼接一个最简单的语句:
127.0.0.1 && ls
结果成功执行
不过也不意味着所有命令都可以执行,例如:
127.0.0.1 && cat /etc/shadow
执行结果如下:
拼接的命令并没有执行,因为当前系统用户的权限不够。
二、Medium
2.1 服务器代码
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Set blacklist
$substitutions = array(
'&&' => '',
';' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
在这个等级下,服务器会将&&
和;
直接去掉(本质上就是设立了黑名单),对于其他特殊字符依旧没有进行过滤。
所以最简单的办法就是直接用&
。
&&
和&
的区别在于,举个例子:A && B
是在A执行成功之后才执行B,若A执行失败则不执行B;而A & B
是无论A的执行成不成功都会执行B。
2.2 漏洞利用
构造命令1 & ls
,执行结果如下:
还有另一个方法,就是构建语句:127.0.0.1 &;& ls
:
注入成功。
三、High
3.1 服务器代码
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_REQUEST[ 'ip' ]);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
High等级增加了对更多符号的过滤,但是这份黑名单不够完善,仔细观察发现|
后面是带着个空格的,也就是说无法过滤单独一个|
。
Command 1 | Command 2
“|”是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2执行的结果。
3.2 漏洞利用
构造语句1|ls
,执行结果如下:
成功执行。
四、Impossible
4.1 服务器代码
if( isset( $_POST[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$target = $_REQUEST[ 'ip' ];
$target = stripslashes( $target );
// Split the IP into 4 octects
$octet = explode( ".", $target );
// Check IF each octet is an integer
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// If all 4 octets are int's put the IP back together.
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
else {
// Ops. Let the user name theres a mistake
echo '<pre>ERROR: You have entered an invalid IP.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
这里加入了token机制,可以有效阻止CSRF,但是对防止命令注入的作用十分局限。
其次还用了stripslashes()
过滤了反斜线,防止转义。
最后是将输入的东西根据IP地址的小圆点.
切分为四个部分,逐一验证每一个部分是不是纯数字,最后再将四个部分拼接成一个IP地址。
从本质来讲,这里采取的是白名单机制,只有数字.数字.数字.数字
才可被执行,也就基本可以防止命令注入的发生。
五、最后说点废话
在实际中,其实很少有web程序会去调用系统命令行,存在命令行注入漏洞的则会更少。
其次上面的Medium和High本质上完全一样,只是黑名单的完善程度不一样而已。