Command Injection
文章目录
类比SQL Injection
既然漏洞类型中都有"injection",我们考虑啥叫injection
在sql注入中我们通过使用Union等套路数据库,让它说出"不该说"的话.
在命令执行漏洞中同样的道理,我们需要使用一些逻辑运算符使得服务端额外执行一些命令
About
The purpose of the command injection attack is to inject and execute commands specified by the attacker in the vulnerable application. In situation like this, the application, which executes unwanted system commands, is like a pseudo system shell, and the attacker may use it as any authorized system user. However, commands are executed with the same privileges and environment as the web service has.
命令注入攻击的目的是在存在漏洞的应用上注入并执行攻击者指定的命令.
在这种情况下,被迫营业的应用就像一个伪shell,攻击者可以像该应用的管理员一样使用它.
但是,命令的权限与web服务器相同(可能不能获取服务器所在主机的管理员权限,但是一定可以获得服务器的管理权限)
Command injection attacks are possible in most cases because of lack of correct input data validation, which can be manipulated by the attacker (forms, cookies, HTTP headers etc.).
当对输入的数据没有检验时,命令注入攻击就容易发生,以表单,cookies,HTTP请求头等等方式
The syntax and commands may differ between the Operating Systems (OS), such as Linux and Windows, depending on their desired actions.
不同操作系统的符号和命令可能有区别,比如说windows的ipconfig和linux的ifconfig
This attack may also be called “Remote Command Execution (RCE)”.
这种攻击又可以称为远程命令执行
Objective
Remotely, find out the user of the web service on the OS, as well as the machines hostname via RCE.
目标:找到web服务器在其操作系统上的用户是谁,远程主机的hostname是多少
漏洞的发生
DVWA Command Injection low
页面逻辑分析
前端代码
<div class="vulnerable_code_area">
<h2>Ping a device</h2>
<form name="ping" action="#" method="post">
<p>
Enter an IP address:
<input type="text" name="ip" size="30">
<input type="submit" name="Submit" value="Submit">
</p>
</form>
</div>
前端以text形式获取用户输入的一个ip地址然后使用post方法将表单发送给后端
服务端代码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];//$_REQUEST超级全局变量可以获取$_POST和$_GET的所有数据,这里实际上可以用$_POST
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {//php_uname函数的作用是返回
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
php_uname()
返回php运行所在的操作系统信息,参数与返回值的关系:
‘a’:此为默认。包含序列 “s n r v m” 里的所有模式。
‘s’:操作系统名称。例如: Windows NT。
‘n’:主机名。例如: localhost.example.com。
‘r’:版本名称,例如: 5.1.2-RELEASE。
‘v’:版本信息。操作系统之间有很大的不同。
‘m’:机器类型。例如:i386。
if( stristr( php_uname( 's' ), 'Windows NT' ) )
检查服务端所在的操作系统是否是Windows NT系统
如果是则直接执行``ping $target`命令,
如果不是Windows NT操作系统则执行ping -c 4 $target
命令
为什么要特判一下windows系统呢?
在linux上使用不带任何命令行参数的ping命令则会无休止地ping下去
但是windows的ping命令默认只ping四次
然后$cmd
承载了ping命令的返回值被echo回显到前端
漏洞分析
观察这句话:
$target = $_REQUEST[ 'ip' ];
$cmd = shell_exec( 'ping ' . $target );
$target
是用户的输入,这里没有经过任何过滤,直接丢给shell_exec函数执行系统函数了,
当我们$target
是老老实实地输入一个IP地址比如127.0.0.1
则一切和和气气,没有问题
但是当$target=127.0.0.1&&whoami
这样会执行两条命令,一个ping,一个whoami,都会回显到前端被攻击者观察到
明显可以看到回显的最后一行是whoami返回的位于executor主机上的deutschball用户
这与sql注入中$id=-1' union select database()#
有异曲同工的感觉?
类似的,也可以用更加粗暴的命令比如||ipconfig
,这样前件就是ping
ping了个寂寞,后件就是ipconfig,由于是逻辑或,因此两个都会执行
并且前件根本执行不起来,回显不需要等待四次ping之后才显示
防御与绕过
DVWA Command Injection 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
echo "<pre>{$cmd}</pre>";
}
?>
替换防御
'&&' => '',
';' => '',
根据以前的绕过替换的经验,可能的绕过方式:
1.双写绕过空字符替换
输入127.0.0.1&&&&whoami
是无效的,因为前面两个&和后面两个&恰好匹配两对都被替换掉了,
但是输入127.0.0.1&;&
是有效的,str_replace函数只会执行一次,把两个&中间的分号;替换掉了,此时两个分号恰好组成逻辑与
2.逻辑或||等其他逻辑运算符没有被替换
DVWA Command Injection 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
echo "<pre>{$cmd}</pre>";
}
?>
"严格"的双写防御和黑名单防御
这里替换方式是单个字符就替换成空字符,显然双写绕过是不可能了,又黑名单全了,再找一个没有被ban的逻辑运算符也是不可能的
侥幸绕过
这里"严格"是加了引号的
注意黑名单中:
'| ' => '',
这里管道运算符|后面貌似有个空格.
那么直接写|whoami
就能够执行
管道命令
管道命令能够将一个命令的执行结果经过筛选,只保留我们需要的信息。
如 dir 命令会显示目录下所有文件夹和文件,可以使用管道命令| findstr “” 将dir的结果进行筛选,只保留需要的信息比如要查询当前活动的进程中谁在占用8080端口
C:\Users\86135>netstat -n|findstr "8080" TCP 192.168.43.44:65068 120.232.67.218:8080 ESTABLISHED
比如要查询当前所有任务中和phpstudy有关的
C:\Users\86135>tasklist|findstr "phpstudy" phpstudy_pro.exe 22080 Console 1 66,528 K
即管道符|后面的操作是基于前面命令的结果上的
绝对防御
DVWA Command Injection impossible
<?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();
?>
$target = stripslashes( $target );
这里为什么要取掉反斜杠?估计涉及命令行的一些性质,待补上了命令行的知识后回头研究
后面将ip按点号.分成四份,并且要求每份都是整数,这意味着最后一份中写啥命令都给扬了