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();
image-20211216095104137
「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()
image-20211216095811342
image-20211216095831786
「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();
image-20211216100045884
image-20211216100104065
「注意」
在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']); ?>
image-20211216102125344
「其他函数」
- 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'); ?>
image-20211216103658807
exec函数
用于执行一个外部程序
<?php echo exec('whoami');?>
image-20211216104234914
执行时加上echo
才会输出whoami
的结果
shell_exec函数
通过shell环境执行命令 且将完整的输出以字符串方式返回
<?php echo shell_exec('whoami');?>
image-20211216104413488
执行时加上echo
才会输出whoami
的结果
反单引号
反单引号是php执行运算符 php将尝试将反单引号中的内容作为shell命令来执行 并将输出信息返回
<?php echo `whoami`;?>
image-20211216105352842
2.2 Windows下的命令执行漏洞
Windows系统支持的管道符
| 命令连接符
如果前语句为假则直接报错,后边不执行 如果前语句为真,执行后边的语句
image-20211216110239864
||命令连接符
如果前面命令是错的那么就执行后面的语句,否则只执行前面的语句
image-20211216110216879
&命令连接符
&前面和后面命令都要执行,无论前面真假
image-20211216111446269
&&命令连接符
&&如果前面为假,后面的命令也不执行,如果前面为真则执行两条命令
image-20211216111723501
例:
<?php header("Content-type:text/html;charset=utf-8"); $ip=$_GET['ip']; system("ping ".$ip); ?>
正常输入?ip=127.0.0.1会返回ping的结果
image-20211216110720924
输入?ip=127.0.0.1| whoami 会返回whoami的结果
image-20211216111835472
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:\windows\win.ini