DVWA练习之Command Injection
本博客将记录在web安全问题中一种常见的漏洞——“命令注入”漏洞的实践演练。首先阐述命令注入漏洞的概念,原理,最后展示基于DVWA的各种等级的命令注入过程。
命令注入
概念:通过web应用程序在服务器上拼接系统命令。也就是说命令注入中的命令指的是系统命令,而注入是通过拼接来完成注入。
系统 | 命令 |
---|---|
windows | DOS |
Linux | Bash |
常见的DOS命令:
命令 | 功能 |
---|---|
ipconfig | 查看本地网络 |
net user | 查看系统用户 |
dir “./” | 查看当前目录 |
常见的命令拼接符:(假设A与B两个命令)
- A成功则执行B A && B
- 简单A与B的拼接 A & B
- A的输出作为B的输入 A | B
- A失败则执行B A || B
命令注入步骤
(1):判断是否调用系统命令
(2):函数或函数的参数是否可控
(3):拼接注入命令
DVWA命令注入
DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法的环境,帮助web开发者更好的理解web应用安全防范的过程。
部署好DVWA后,登陆DVWA首先选择练习的难度等级。DVWA中共分为四种安全级别:Low,Medium,High,Impossible。然后选择练习的模块,这里我们选择Command Injection(命令行注入)模块。
LOW等级
选好等级后,进入Command Injection(命令行注入)模块。
首先按照正常的流程进行操作,这里输入IP address:127.0.0.1 后
发现显示的结果和系统的ping命令类似,在自己的cmd中输入ping 127.0.0.1
因此判断该web应用有调用系统命令ping,而且ping函数的参数可变。
然后就可以利用ping命令中可变的参数来拼接命令注入内容了。
比如使用拼接符&&构造命令127.0.0.1&&net user后输出的结果发生了改变
多了蓝框中的内容,其内容与系统命令net user结果相同,说明命令注入成功!
Medium等级
在Medium等级中low等级的方法不能直接使用了
使用后显示的结果是找不到主机127.0.0.1net请重试。我们发现之前输入的命令127.0.0.1&&net user中的&&不见了,所以猜测是不是web应用把&&列入了黑名单直接将&&屏蔽导致注入失败。
为了验证猜想我们查看下DVWA的源代码:
<?php
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>";
}
?>
我们可以看到重点标注部分的代码
$substitutions = array( '&&' => '', ';' => '', );
这行代码的含义就是定义一个数组并赋值给变量$substitutions
,数组中包括2个键:&&和;,它们对应的值都是NULL。
$target = str_replace( array_keys( $substitutions ), $substitutions, $target
这行语句是用str_replace函数对$target
变量中的字符进行替换,替换的方法是将array_keys( $substitutions
)替换成$substitutions
,也就是将&&和;都替换成空值。
DVWA通过上述代码完成了对符号&&和;的过滤,也就是设置了黑名单。因此我们可以尝试使用其他拼接符对命令完成拼接。
比如使用&构造命令127.0.0.1&net user输出结果发生了改变
输出的结果是两个命令的拼接,也就是说命令注入成功!
High等级
在High等级中low等级和medium等级的方法都无法使用了。
我们直接查看源代码
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
发现high等级相对medium等级过滤的符号多了很多,也就是说黑名单增大了。因此之前的方法都不能使用了。而high等级的黑名单看似滤过了所有的非法字符但是仔细观察我们发现代码中过滤的|后面还有一个空格因此可以用管道符|来拼接两个命令。
比如使用|构造127.0.0.1|net user输出结果
这表明命令注入成功!
Impossible等级
在impossible等级中前面三中方法都行不通了。
我们查看DVWA的源代码
<?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();
?>
其中(1)stripslashes(string)函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串;
(2)explode(separator,string,limit)函数会把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目;
(3)is_numeric(string)函数能检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。
可以看出impossible等级将用户输入的IP格式进行了严格的设计只有“数字.数字.数字.数字”格式的输入才会被执行。也就是白名单的方法相较于黑名单更加有效,安全等级更高。
实战小技巧
(1)敏感命令过滤怎么办?(黑名单)
如:过滤了whoami命令时,可以加入双引号来跳过命令。
如:who”“ami或who”“am”“i都可以跳过。
(2)不显示输出结果怎么办?
延时注入:输入命令时再多拼接一条延时命令来检验是否成功注入。
如:ping 127.0.0.1 -n 5>nul