Unicorn模拟执行RTOS固件
Unicorn模拟执行RTOS固件
unicorn是一种指令级cpu模拟器,可以支持多架构二进制程序的执行。由于RTOS固件通常难以进行调试,因此采用通过unicorn模拟器的方式来完成模拟调试。
实验对象
Fast 1900R设备,RTOS,ARM架构
测试漏洞
CVE-2022-26987
漏洞位置:
tWlanTask
函数中接受最大长度为3072的输入,随后调用MmtAtePrase
函数将输入复制给长度548的栈上变量。导致存在栈溢出漏洞。
tWlanTask
函数:

MmtAtePrase
函数:

其中spliter
相当于strcpy函数,将分隔符'\n'
前的字符串复制给v11栈上变量。
模拟片段
使用binwalk,010Editor等工具查看该固件的加载基址。该固件为
0x40205000
,常见RTOS固件的加载基址如何确定可见另一篇文章使用IDA查看
tWlanTask
函数的加载函数栈:查看调用
tWlanTask
函数的apps_init
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61int apps_init()
{
int v0; // r0
int v1; // r0
const char *v2; // r0
unsigned int v3; // r0
bool v4; // cc
_DWORD v6[4]; // [sp+2Ch] [bp-28h] BYREF
int v7[6]; // [sp+3Ch] [bp-18h] BYREF
memset(1079933252, 0, 8236);
v0 = apps_wpsInit(1079933516);
apps_upnpInit(v0);
v7[0] = 1;
v1 = socket(2, 2, 17);
MEMORY[0x405E7944] = v1;
if ( v1 == -1 )
{
if ( (MEMORY[0x4061657C] & 2) != 0 )
{
v2 = "Unable to create wlan event socket\n";
LABEL_12:
my_printf(v2);
}
}
else if ( setsockopt(v1, 0xFFFF, 512, v7, 4) >= 0 )
{
memset(v6, 0, sizeof(v6));
v6[0] = 604242448;
v6[1] = 0;
if ( bind(MEMORY[0x405E7944], v6, 16) < 0 && (MEMORY[0x4061657C] & 2) != 0 )
{
v2 = "Unable to bind wlan event socket\n";
goto LABEL_12;
}
}
else if ( (MEMORY[0x4061657C] & 2) != 0 )
{
v2 = "Unable to setsockopt to wlan event socket\n";
goto LABEL_12;
}
apps_ateInitSock(1079937388);
apps_wpsInitSock(1079933516);
apps_wssInit(1079937384);
bzero(1079933260, 256);
MEMORY[0x405E7948] = 0;
if ( MEMORY[0x405E7944] > 0 )
MEMORY[0x405E7948] = MEMORY[0x405E7944];
v3 = MEMORY[0x405E88CC];
*(_DWORD *)(4 * (MEMORY[0x405E7944] >> 5) + 0x405E794C) |= 1 << (MEMORY[0x405E7944] & 0x1F);
v4 = (int)v3 <= MEMORY[0x405E7948];
*(_DWORD *)(4 * (v3 >> 5) + 0x405E794C) |= 1 << (v3 & 0x1F);
if ( !v4 )
MEMORY[0x405E7948] = v3;
if ( MEMORY[0x405E896C] > MEMORY[0x405E7948] )
MEMORY[0x405E7948] = MEMORY[0x405E896C];
*(_DWORD *)(4 * (MEMORY[0x405E896C] >> 5) + 0x405E794C) |= 1 << (MEMORY[0x405E896C] & 0x1F);
taskSpawn("tWlanTask", 160, 0, 0x4000, tWlanTask, 1079933252, 0, 0, 0, 0, 0, 0, 0, 0, 0);
regAppList(4, wlanTmpHandle);
return 0;
}其创建了监听在1060端口的udp连接socket,并使用taskSpawn函数创建该任务,其中定义了该函数栈大小为0x4000。
使用unicorn加载该固件到内存:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23from unicorn import *
from unicorn.arm_const import *
from pwn import *
fast = Uc(UC_ARCH_ARM, UC_MODE_ARM)
BASE_ADDR = 0x40200000
BASE_SIZE = 0x300000
STACK_ADDR = 0x40500000
STACK_SIZE = 0x400000
fast.mem_map(BASE_ADDR, BASE_SIZE)
fast.mem_map(STACK_ADDR, STACK_SIZE)
fast.mem_write(BASE_ADDR, read('./Fast FAC 1900R/FAC1900R千兆版 V1.0升级软件20190827_2.0.2/data_10400'))
fast.reg_write(UC_ARM_REG_SP, STACK_ADDR + STACK_SIZE-1)
def hook_code(mu, address, size, user_data):
print(">>> Traceing instruction at 0x%x, instruction size = 0x%x" %(address, size))
func_source = 0x402CE868
func_ret = 0x402CE8D0
fast.hook_add(UC_HOOK_CODE, hook_code)
fast.emu_start(func_source, func_ret)使用capstone库进行反汇编辅助调试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from capstone import *
from capstone.arm import *
def bytesToOpcodeStr(curBytes):
opcodeByteStr = ''.join('{:02X} '.format(eachByte) for eachByte in curBytes)
return opcodeByteStr
def hook_code(mu, address, size, user_data):
# print(">>> Traceing instruction at 0x%x, instruction size = 0x%x" %(address, size))
opcodeBytes = mu.mem_read(address, BYTES_PER_LINE)
opcodeByteStr = bytesToOpcodeStr(opcodeBytes)
decodedInsnGenerator = cs.disasm(opcodeBytes, address)
# if gSingleLineCode:
for eachDecodedInsn in decodedInsnGenerator:
eachInstructionName = eachDecodedInsn.mnemonic
info("--- 0x%08X: %s -> %s\t%s", address, opcodeByteStr, eachInstructionName, eachDecodedInsn.op_str)
漏洞复现
从source点模拟执行到sink点,hook recvfrom
函数,当执行该函数时,向目标buffer里填充payload:
1 | def hook_recvfrom(mu, address, size, user_data): |
该漏洞利用方法为利用ROP调用strncpy(group_addr, passwd_addr, 0x21)
函数,从而实现泄露passwd目的。
passwd_addr可以在httpGetPassword
中获取到,在模拟中我们可以将该地址map为有效密码0KcgeXhc9TefbwK
。

然后通过hook recvfrom
函数写入payload,获取到目标密码。

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Small Utopia!
评论