引言
结合DVWA提供的命令注入模块,对命令注入漏洞进行学习总结。命令注入(Command Injection)是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。
在一些web应用中,某些功能可能会调用一些命令执行函数,比如php中的system、exec、shell_exec等。如果对用户输入的淑数据过滤不充分的话,很容易造成命令执行漏洞。
环境
phpstudy(搭建DVWA)
Command Injection
low
我们先分析一下漏洞源码:
<?php
if( isset( $_POST[ 'submit' ] ) ) {
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if (stristr(php_uname('s'), 'Windows NT')) {
$cmd = shell_exec( 'ping ' . $target );
echo '<pre>'.$cmd.'</pre>';
} else {
$cmd = shell_exec( 'ping -c 3 ' . $target );
echo '<pre>'.$cmd.'</pre>';
}
}
?>
stritr函数主要用来查找字符串,并返回。php_uname返回运行PHP的操作系统描述。如果是windows系统则执行 “ping + $target” ,如果是linux系统,执行“ping -c 3 + target”, 并没有对用户输入的变量ip进行过滤,而是直接执行ping + target中的内容,所以存在命令执行漏洞,管道运算符使用的会比较多。

A && B: 先执行A,如果成功,执行B;
A || B :先执行A,如果失败,执行B;
A | B:管道,先执行A后,将A的结果作为B的输入,打印的是B的结果;
A & B:先执行A,然后不管成功与否,执行B;
可以使用以下payload,注入成功。
127.0.0.1;ifconfig 127.0.0.1&ifconfig 127.0.0.1&&ifconfig 127.0.0.1|ifconfig x||ifconfig

medium
先分析一下源码:
<?php
if( isset( $_POST[ 'submit'] ) ) {
$target = $_REQUEST[ 'ip' ];
// Remove any of the charactars in the array (blacklist).
$substitutions = array(
'&&' => '',
';' => '',
);
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if (stristr(php_uname('s'), 'Windows NT')) {
$cmd = shell_exec( 'ping ' . $target );
echo '<pre>'.$cmd.'</pre>';
} else {
$cmd = shell_exec( 'ping -c 3 ' . $target );
echo '<pre>'.$cmd.'</pre>';
}
}
?>
这里创建了一个黑名单substitutions,对用户输入数据的 ‘ && ’ 和 ‘ ; ’进行了过滤。但是并没有对所有的管道运算符进行过滤,我们依然可以使用以下payload达到命令执行目的。
1270.0.1999||ls -l
127.0.0.1&ls -l
127.0.0.1|ls -l

high
分析一下源码:
<?php
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级别的源码对黑名单进行了扩充,过滤了更多可能造成命令执行的运算符,包括 ‘&’ 、‘;’ 、‘| ’ 、‘-’ 、‘$’ 、‘(’ 、‘)’ 、‘`’ 、‘||’ ,这里过滤的‘| ’中间有个空格,所以我们使用 ‘|’ 就可以绕过黑名单了。
127.0.0.1|ls
impossiable
<?php
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();
?>
explode函数

explode函数将用户输入的ip以 ‘.’ 为分隔符,分为四个字符,将这四个字符放入数组中,并判断这四个元素是否为数字或者数字字符串,如果不是则不执行命令。
命令注入的防御措施
1、采用白名单,或使用正则表达式进行过滤。
2、不要让用户可以直接控制eval()、system、exec、shell_exec等函数的参数。
3、在进入执行命令函数和方法前,对变量进行过滤,对敏感字符进行转义。