5 symbols ... file test type EXEC (Executable file) canary false nx true crypto false va true class ELF32 lang c arch x86 bits 32 machine Intel 80386 os linux subsys linux endian little strip false static false ... [Header fields] ...
When run, it outputs a few non-printable chars on stdout, breaking the console.
Hexdump of the program’s stdout:
1 2 3 4 5
./7fcdb7907692cbd6ea87600ab11377b3 | hexdump -C 00000000 63 db 7d db 97 ea 4c c9 26 0e 07 b7 0d 69 ae 1f |c.}...L.&....i..| 00000010 b7 1f fc db fc b7 1f fc db fc b7 a6 fc 69 51 0e |.............iQ.| 00000020 c9 46 0a |.F.| 00000023
Writeup
We suspect that the program pre-processes the flag and outputs the result. It’s time for a radare session!
Analysis (radare)
1
$ radare2 -d ./7fcdb7907692cbd6ea87600ab11377b3
Once inside radare, we prepare for the analysis:
1 2 3 4
V :db main :dc :af
Then, in visual mode cycle with p to reach the disassembled view:
Main
We suspect that function[1] is actually doing the pre-processing responsible of the weird outputs by printf.
function[1] structure
The function[1] has a jmp ecx trampoline which lands in a xor between two bytes, followed by a ret.
main - function[1] interactions
Each time the main calls function[1] with a small index as argument. Moving in radare is really fast! Follow the calls with [] and back to caller by pressing “u”.
0x8048583 f 0x8048605 -> 0x804b040 -> 0x6c (l) 0xb7 (dirty char) 0x8048535 a 0x80484cd -> 0x804b028 -> 0x67 (g) 0xbc (dirty char) 0x8048687 { 0x8048639 -> 0x804b044 -> 0x73 (s) 0x99 (dirty char) 0x804866d w 0x804859d -> 0x804b038 -> 0x69 (i) 0xa0 (dirty char) 0x8048653 t 0x8048501 -> 0x804b02c -> 0x63 (c) 0x6d (dirty char) 0x80485b7 3a 68 6f h 0x80484b3 26 20 97 (space) 0x80485d1 3c 6a 67 j 0x804851b 2e 75 1c u 0x80485eb 3e 6d c3 m 0x80484e7 2a 70 6f p 0x80484b3 26 20 97 (space) 0x80484e7 2a 70 6f p 0x8048499 24 6f 93 o 0x80484cd g 0x8048499 o 0x80484b3 (space) 0x80484e7 p 0x8048499 o 0x80484cd g 0x8048499 o 0x80484b3 (space) 0x804854f 32 62 c4 b 0x8048499 o 0x804851b u 0x804861f 42 6e 3f n 0x80485d1 j <-- it's a c, but we found a j at the first try 0x8048569 34 65 ac e 0x80486a1 }
gdb-peda
automation!
There are tons of way to to so:
GDB with python
First of all check configuration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
(gdb) show configuration This GDB was configured as follows: configure --host=x86_64-unknown-linux-gnu --target=x86_64-unknown-linux-gnu --with-auto-load-dir=$debugdir:$datadir/auto-load --with-auto-load-safe-path=$debugdir:$datadir/auto-load --with-expat --with-gdb-datadir=/usr/local/share/gdb (relocatable) --with-jit-reader-dir=/usr/local/lib/gdb (relocatable) --without-libunwind-ia64 --with-lzma --with-python=/usr --with-separate-debug-dir=/usr/local/lib/debug (relocatable) --with-zlib --without-babeltrace
("Relocatable" means the directory can be moved with the GDB installation tree, and GDB will still find it.)
Note --with-python Now set python print-stack full, first tries verbose is useful. Damn is a long run…. something else?
GDB commands
1 2 3 4 5 6
break *0x8048497 commands si 2 printf "%c",$eax c end
And at the end the best method ever….PATCHING!
1 2 3 4 5 6 7
#!/usr/bin/python addr = [0x4a7,0x4c1,0x4db,0x4f5,0x50f,0x529,0x543,0x55d,0x577,0x591,0x5ab,0x5c5,0x5df,0x5f9,0x613,0x62d,0x647,0x661,0x67b,0x695,0x6af] with file('switchy','r+b') as f: for i in addr: f.seek(i) f.write(chr(0x90)+chr(0x90)) f.closed