程序员使用脚本语言(如PHP)开发应用程序过程中,脚本语言开发十分快速、简介,方便,但是也伴随着一些问题,如说速度慢,或者无法接触系统底层,如果我们开发的应用,特别是企业级的一些应用需要去调用一些外部程序(系统命令或exe等可执行文件);当应用需要调用一些外部程序时就会用到一些系统命令的函数。
应用在调用这些函数执行系统命令的时候,如果将用户的输入作为系统命令的参数拼接到命令行中,在没有过滤用户的输入的情况下,就会造成命令执行漏洞。
该函数能够讲字符串作为0S命令执行,自带输出功能。
示例1:静态变量不存在漏洞
$str = "ipconfig";
system($str);
?>
运行结果:
示例2:换为变量
if(isset($_GET['cmd'])){
$str = $_GET['cmd'];
system($str);
}
?>
传入参数运行结果:
该函数能将字符串作为0S命令执行,需要输出执行结果。
示例1:
if(isset($_GET['cmd'])){
$str = $_GET['cmd'];
print(exec($str));
}
?>
传入参数运行结果:显示内容有限。
该函数能将字符串作为0S命令执行,需要输出执行结果。(广泛使用)
示例:
if(isset($_GET['cmd'])){
$str = $_GET['cmd'];
print(shell_exec($str));
}
?>
传入参数运行结果:
该函数能将字符串作为0S命令执行,自动输出执行结果。
示例:
if(isset($_GET['cmd'])){
$str = $_GET['cmd'];
passthru($str);
}
?>
传入参数运行结果:
popen() 函数打开进程文件指针。
语法:popen(command,mode)
参数:
command(要执行的命令)、mode(规定连接模式。 r: 只读。w: 只写 (打开并清空已有文件或创建一个新文件))
该函数也能够执行0S命令,但是该函数并回是返回命令结果,而是返回一个文件指针。需要导入文件中查看内容。
示例:
if(isset($_GET['cmd'])){
$str = $_GET['cmd'].">>1.txt";
popen($str,'r');
}
?>
查看导入的文件:1.txt
反引号内的字符串会被解析为OS命令。
示例:
if(isset($_GET['cmd'])){
$str = $_GET['cmd'];
print `$str`;
}
?>
传参运行:
0S命令注入漏洞,攻击者直接继承Web用户权限,在服务器上执行任意命令,危害特别大。以下命令均在windows系统下测试成功。
提交参数?cmd=type C:\windows\system32\drivers\etc\hosts
,查看系统hosts文件。
提交参数?cmd=cd
提交参数 ?cmd=echo "" > E:\phpstudy\WWW\PHP\commands\shell.php
,页面没有报错,说明文件写入成功。访问shell.php文件。
在Windows系统下的cmd命令中,有以下一些截断拼接符。
& 前面的语句为假则直接执行后面的
&& 前面的语句为假则直接出错,后面的也不执行
| 直接执行后面的语句
|| 前面出错执行后面的语句
在Linux系统下的shell命令中,有以下一些截断拼接符。
; 前面的执行完执行后面的
| 是管道符,显示后面的执行结果
|| 当前面的执行出错时执行后面的
& 无论前边语句真假都会执行
&& 只有前边语句为真,才会执行后边语句。
它是一个使用Python开发的漏洞测试工具,这个工具是为了方便的检测一个请求是否存在命令注入漏洞,并且对其进行测试,在其作者发布的最新版本中支持直接直接导入burp的历史记录进行检测,大大提高了易用性。
在kali中开启apache2服务,在html目录下新建文件:cmd.php
// 使用参数cmd执行命令:ping -c 4
$arg = $_GET["cmd"];
if($arg){
system("ping -c 4 $arg");
}
echo ""
;
?>
使用自动化工具commix检测漏洞:commix -u "http://ip地址/路径?提交参数"
尽量减少命令执行函数的使用,并在php的配置文件中的 disable_functions
中禁用(禁用完重启服务即可生效);
在进入命令执行的函数或方法之前,对参数进行过滤;
参数的值尽量使用引号包裹,并在拼接前调用 addslashes
进行转义。
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
预定义字符:
单引号(')
双引号(")
反斜杠(\)
NULL
示例:
$str = "hello,\",\\\,'";
echo $str;
echo "
";
echo addslashes($str);
?>
结果:
需要你输入一个IP地址:
注入其他命令:获取不到
使用 | 拼接注入:成功注入,或者使用&或使用127.0.0.0.0.1||whoami(||前面的命令失败后才会执行后面的命令)
查看源代码:IP没有做任何过滤。
if( isset( $_POST[ 'Submit' ] ) ) {
// 获取IP
$target = $_REQUEST[ 'ip' ];
// 判断操作系统
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// 如果是Windows执行ping命令
$cmd = shell_exec( 'ping ' . $target );
}
else {
// 如果是unix执行ping -c 4(发送4个数据包,因为linuxping命令一直执行)
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// 结果显示
$html .= "{$cmd}
";
}
?>
源代码:加了黑名单过滤 &&
和 ;
// 设置黑名单
$substitutions = array(
'&&' => '',
';' => '',
);
// 从黑名单中删除数组中的字符(从target查找如果存在黑名单数组中的键名[&&]或[;]就替换为键值[''])
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
源代码:黑名单加入新的过滤
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
if( isset( $_POST[ 'Submit' ] ) ) {
// 检查 Anti-CSRF 令牌,当客户端和服务器交互时,服务器会给客户端发送一个随机字符串,交互时要比对该字符串
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$target = $_REQUEST[ 'ip' ];
// stripslashes:删除反斜杠
$target = stripslashes( $target );
// 把IP按.分成4个octet
$octet = explode( ".", $target );
// 检查每个octet是否为整数
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// 通过检查再拼接
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
// 操作系统判断
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.
';
}
}
// 生成Anti-CSRF令牌
generateSessionToken();
?>