“命令行注入?搞点事情,嘿嘿嘿...”
前言
国庆假期一转眼就第四天了,感觉时间过得超快,不知道小伙伴们玩得怎么样呀?哈哈哈,有机会还是要好好玩耍的,天天审代码感觉真的会秃头的。。
开始之前,先讲个小插曲,今天部分小伙伴可能会出现乱码的情况。
解决这个问题的方法如下:
1. 到DVWA安装目录下(.../WWW/DVWA-master/dvwa/includes)寻找文件dvwaPage.inc.php
2. 打开这个文件,然后在全文查找charset=utf-8,将所有utf-8修改为gb2312。
注意:有好几处charset=utf-8,要全部修改成charset=gb2312。记得保存。
OK,问题解决了,闲话少说,咱们开始吧!
Command Injection 介绍
Command Injection,即命令注入,是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。PHP命令注入攻击漏洞是PHP应用程序中常见的脚本漏洞之一,国内著名的Web应用程序Discuz!、DedeCMS等都曾经存在过该类型漏洞。
具体操作
同样要先启动phpstudy,打开Apache和MySQL服务
切换难度(具体操作见上一章)
low 等级
源代码:
<?php
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
$html .= "<pre>{$cmd}</pre>";
}
?>
分析:
服务器端首先获取用户提交的ip,而后获取服务端的系统信息,根据不同操作系统选择不同的ping命令格式,但是并没有对用户的输入做任何的过滤,这样的话就会导致严重的漏洞
stristr()函数定义和用法:
>> stristr() 函数搜索字符串在另一字符串中的第一次出现。
>> 注释:该函数是二进制安全的。
>> 注释:该函数是不区分大小写的。如需进行区分大小写的搜索,请使用 strstr() 函数。
>> 语法:stristr(string,search,before_search)
php_uname(mode)函数定义和用法:
这个函数会返回运行php的操作系统的相关描述,参数mode可取值:
”a”(此为默认,包含序列”s n r v m”里的所有模式),
”s”(返回操作系统名称),
”n”(返回主机名),
“r”(返回版本名称),
”v”(返回版本信息),
”m”(返回机器类型)。
漏洞利用
无论是linux系统还是windows系统,我们都可以用&&来执行多条命令语句。所以我们执行的payload可以是127.0.0.1&&ipconfig可以发现返回了执行结果,ip详细信息:
当然,这里的127.0.0.1可以换成任何IP地址,而&&后面可以接各种命令(这样就可以搞事情了)
medium 等级
源代码:
<?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
$html .= "<pre>{$cmd}</pre>";
}
?>
分析:
通过源码我们可以看出,相对比于low等级,medium设置了黑名单,将&&和;做了过滤处理,这样的话就不能像刚才那样直接执行,但是我们可以换个方式呀,&&不行,我们可以用&
这里说明下几个符号的区别:
command1&command2&command3 三个命令同时执行
command1;command2;command3 不管前面命令执行成功没有,后面的命令继续执行
command1&&command2 只有前面命令执行成功,后面命令才继续执行
漏洞利用
我们就改用&,所以payload就变成了
127.0.0.1&ipconfig
nice,执行成功!
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
$html .= "<pre>{$cmd}</pre>";
}
?>
分析:
还以为会是多么高端的过滤方式,只不过是把黑名单稍微细化了一下,思考了好久...
发现|符号有点问题啊,黑名单限制的是“| ”,但没限制|,直接利用一波
Command 1 | Command 2
“|”是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2执行的结果。
漏洞利用
挖漏就是要细心哈哈哈,payload现在就是
127.0.0.1|ipconfig
imposible 等级
源代码:
<?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
$html .= "<pre>{$cmd}</pre>";
}
else {
// Ops. Let the user name theres a mistake
$html .= '<pre>ERROR: You have entered an invalid IP.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
分析:
通过源代码分析我们可以看到:
1、该模块中加入了Anti-CSRF token来防范CSRF攻击,同时每次随机生成了一个token,当用户提交的时候,在服务器端比对一下token值是否正确,不正确就丢弃掉,正确就验证通过。
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
2、通过加入stripslashes函数来对输入的ip信息进行删除字符串中的反斜杠操作。
$target = stripslashes( $target );
3、对输入的信息通过“.”号进行分割,分割成多个数组。
// Split the IP into 4 octects
$octet = explode( ".", $target );
4、然后采用白名单机制来验证输入的信息是不是都是数字组成,然后把所有的数字通过“.”进行拼接,这样就保证了输入的信息只能是以数字.数字.数字.数字的形式,避免了命令执行漏洞。
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];
后记
搞安全的一定要切记!!!所有的用户输入都是不可信的,秉持着这个理念,一定要对用户的输入进行处理,不然就会导致严重的漏洞!
—— 阿海 记于 2018.10.04
相关阅读: