命令注入的目标是通过易受攻击的应用程序在主机操作系统上执行任意命令。当应用程序将不安全的用户提供的数据(表单、cookie、HTTP 标头等)传递到系统 shell 时,可能会发生命令注入攻击。在这种攻击中,攻击者提供的操作系统命令通常以易受攻击的应用程序的权限执行。命令注入攻击的可能性很大程度上是由于输入验证不足。
此攻击与代码注入不同,代码注入允许攻击者添加自己的代码,然后由应用程序执行。
(1)输入127.0.0.1,看看是否有回显。
(2)尝试用命令连接符拼接命令,payloa:127.0.0.1 && whoami
原理:由于在操作系统中,“&”、“&&”、“|”、“||”都可以作为命令连接符使用,由于网页没有对参数进行任何过滤,因此可以用连接符后面接上其他指令来执行。
常见的命令连接符:
a && b
:代表首先执行前者命令a再执行后命令b,但是前提条件是命令a执行正确才会执行命令b,在a执行失败的情况下不会执行b命令。所以又被称为短路运算符。
前面的命令执行成功后,它后面的命令才被执行
a & b
:代表首先执行命令a再执行命令b,如果a执行失败,还是会继续执行命令b。也就是说命令b的执行不会受到命令a的干扰。
表示简单的拼接,A命令语句和B命令语句没有制约关系
a || b
:代表首先执行a命令再执行b命令,如果a命令执行成功,就不会执行b命令,相反,如果a命令执行不成功,就会执行b命令。
前面的命令执行失败,它后面的命令才被执行
a | b
:代表首先执行a命令,再执行b命令,不管a命令成功与否,都会去执行b命令。
当第一条命令失败时,它仍然会执行第二条命令,表示A命令语句的输出,作为B命令语句的输入执行。
通过数据包,可以看到客户端以POST方式进行请求。
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 "{$cmd}
";
}
?>
几个函数:
stristr()
:搜索字符串在另一字符串中的第一次出现。php_uname()
:返回运行 PHP 的系统的有关信息。 分析:php_uname(mode)
函数会返回运行php的操作系统的相关描述,当参数是 “s” 时,返回操作系统名称。stristr()
函数搜索字符串在另一字符串中的第一次出现,返回字符串的剩余部分(从匹配点),未找到所搜索的字符串返回 FALSE。使用该函数的目的是为了区分 DVWA 搭建在什么系统上。不过,对于最重要的传入的 ping 命令的参数 target,并没有进行任何过滤。
直接输入127.0.0.1 & whoami
,发现仍然可以执行命令。
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 "{$cmd}
";
}
?>
几个函数:
array_keys()
:返回包含数组中所有键名的一个新数组。str_replace()
:替换字符串中的一些字符(区分大小写)。语法:str_replace(find,replace,string,count)
分析:medium 级别的代码加入了对“&&”和“;”的过滤。
payload:127.0.0.1|ifconfig
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 "{$cmd}
";
}
分析:虽然是把所有的连接符都过滤了,但是开发者在|
后面加了个空格,因此我们还是能够用 |
连接符进行绕过。
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 "{$cmd}
";
}
else {
// Ops. Let the user name theres a mistake
echo 'ERROR: You have entered an invalid IP.
';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
分析:
一些 Web 程序中需要调用一些执行系统命令的函数,例如 PHP 的system
、exec
、shell_exec
函数等。当攻击者能够直接操作命令执行的参数,并且没有代码对传入的参数进行过滤时,攻击者就能将用于搞破坏的系统命令夹带进来让系统执行。
在 Windows 系统和 Linux 系统中都有一些管道符,这些管道符可以被用来拼接攻击指令:
&&
:前面的语句正确执行时,才执行后面的语句;&
:前面的语句执行出错时,执行后面的语句;|
:将前面的语句运行的结果,当做后面语句的输入,显示后面语句的执行结果;||
:前面的语句出错时,执行后面的语句。对于指令注入漏洞,比较好的防御方式是尽可能别用命令执行函数,对于输入的参数要做好黑名单过滤或者白名单验证。