This writeup describes the solution for the easy-math challenge in Hackover CTF 2015 held by Chaos Computer Club Hamburg.
The task describes some basic arithmetics to warm up:
This file was published: easy-math.tar.gz. It is a 32bit ELF executable. Running the file shows this output:
ruport@zentaur:~/hackover2015$ ./easy_math Warmup: sh0w m3 h0w 1337 y0u 4r3> rup0rt
It reads some data and does stuff with it. I gonna try GDB to have a detailed look in the operations.
So lets set a breakpoint after the read() functions and single step (si).
(gdb) b *0x0804855d Breakpoint 1 at 0x804855d (gdb) display /i $eip (gdb) run Starting program: /home/ruport/hackover2015/easy_math Warmup: sh0w m3 h0w 1337 y0u 4r3> AAAABBBBCCCC (gdb) CC Undefined command: "CC". Try "help". 1: x/i $eip => 0x804855d <main+153>: add esp,0x10
We already recognize that the binary only takes 10 bytes of input because, 2 bytes of our input (CC) is already passed back to GDB. Then the program does some compares. One of them is very interesting because it checks our input data:
0x0804858b in main () 1: x/i $eip => 0x804858b <main+199>: cmp eax,DWORD PTR [ebp-0x10] (gdb) i r eax eax 0xe8ab4dca -391426614 (gdb) x/1x $ebp-0x10 0xffffd3e8: 0x42424141
Okay, so file checks our first part of input data (AABB) for 0xe8ab4dca. Lets fake this step as if our input data was correct and see what happens next:
(gdb) p/x $ebp-0x10 $1 = 0xffffd3e8 (gdb) set *((int*)0xffffd3e8)=0xe8ab4dca (gdb) si 0x0804858e in main () 1: x/i $eip => 0x804858e <main+202>: je 0x8048597 <main+211> (gdb) 0x08048597 in main () 1: x/i $eip => 0x8048597 <main+211>: cmp DWORD PTR [ebp-0xc],0x1337b00b (gdb) x/1x $ebp-0xc 0xffffd3ec: 0x43434242
Ah, the second part of our input data (BBCC) is checked for 0x1337b00b. Lets fake this part too.
(gdb) p/x $ebp-0xc $2 = 0xffffd3ec (gdb) set *((int*)0xffffd3ec)=0x1337b00b (gdb) si 0x0804859e in main () 1: x/i $eip => 0x804859e <main+218>: jne 0x80485ac <main+232> (gdb) 0x080485a0 in main () 1: x/i $eip => 0x80485a0 <main+220>: call 0x80484ab <shell> (gdb) c Continuing. $
After this check the “shell” function is called an we get a shell. So all we have to do is to submit 2 bytes of trash data, 0xe8ab4dca and 0x1337b00b to the server. Because this contains binary data, I wrote a python script:
#!/usr/bin/env python import socket import sys import struct import time trash = "XX" cmp1 = 0xe8ab4dca cmp2 = 0x1337b00b server = ("easymath.hackover.h4q.it", 1337) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(server) data = sock.recv(2048) print data c1 = struct.pack("<I", cmp1) c2 = struct.pack("<I", cmp2) sock.send(trash + c1 + c2) while True: input = raw_input("CMD> ") sock.sendall(input + "\n") data = sock.recv(2048) print data sock.close()
When executing this script, we get a shell on the hackover CTF 2015 server:
Warmup: sh0w m3 h0w 1337 y0u 4r3>
CMD> ls
easy_math
easy_math.start
CMD> ls /home
ctf
CMD> cd /home/ctf
CMD> ls
flag.txt
CMD> cat flag.txt
hackover15{YaY_SiMpLe_diSasM_aNd_mAtH_iS_sImpLe}
The solution is “hackover15{YaY_SiMpLe_diSasM_aNd_mAtH_iS_sImpLe}“.