├── LICENSE
├── README.md
├── WINspect.ps1
└── captures
├── 1.PNG
├── 2.PNG
└── 3.PNG
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
4 | WINspect is part of a larger project for auditing different areas of Windows environments. 5 | It focuses on enumerating different parts of a Windows machine to identify security weaknesses 6 | and point to components that need further hardening. 7 | 8 |9 | 10 | ## Features 11 | 12 | This current version of the script supports the following features : 13 | 14 | - Checking for installed security products. 15 | - Checking for DLL hijackability (Authenticated Users security context). 16 | - Checking for User Account Control settings. 17 | - Checking for unattended installs leftovers. 18 | - Enumerating world-exposed local filesystem shares. 19 | - Enumerating domain users and groups with local group membership. 20 | - Enumerating registry autoruns. 21 | - Enumerating local services that are configurable by Authenticated Users group members. 22 | - Enumerating local services for which corresponding binary is writable by Authenticated Users group members. 23 | - Enumerating non-system32 Windows Hosted Services and their associated DLLs. 24 | - Enumerating local services with unquoted path vulnerability. 25 | - Enumerating non-system scheduled tasks. 26 | 27 | ## TODO-LIST 28 | - Local Security Policy controls. 29 | - Administrative shares configs. 30 | - User-defined COM. 31 | - Suspicious loaded DLLs. 32 | - Established/listening connections. 33 | - Exposed GPO scripts. 34 | 35 | ## Supported Powershell Version 36 | 37 | This version was tested in a powershell v2.0 environment. 38 | 39 | 40 | ## Contributions 41 | 42 | You are welcome to contribute and suggest any improvements. 43 | If you want to point to an issue, Please [file an issue](https://github.com/A-mIn3/WINspect/issues). 44 | 45 | ## Direct contributions 46 | 47 | Fork the repository && File a pull request && You are good to go ;) 48 | 49 | ## Need Help 50 | 51 | If you have questions or need further guidance on using the tool, please [file an issue](https://github.com/A-mIn3/WINspect/issues). 52 | 53 | ## License 54 | This project is licensed under The GPL terms. 55 | -------------------------------------------------------------------------------- /WINspect.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Spect 3 | # # # # # # # # # 4 | # # # # # # 5 | # # # # # # # 6 | # # # # # # # # 7 | # # # # # # # 8 | 9 | beta version 10 | Author : A-mIn3 11 | 12 | #> 13 | 14 | [Console]::ForegroundColor="White" 15 | [Console]::BackGroundColor="Black" 16 | 17 | [System.String]$scriptDirectoryPath = split-path -parent $MyInvocation.MyCommand.Definition 18 | [System.String]$secpolFilePath = join-path $scriptDirectoryPath "secedit.log" 19 | [System.String]$reportFilePath = join-path $scriptDirectoryPath "report-$env:COMPUTERNAME.txt" 20 | [System.String]$exceptionsFilePath = join-path $scriptDirectoryPath "exceptions-$env:COMPUTERNAME.txt" 21 | 22 | [System.String]$culture=(Get-Culture).Name 23 | 24 | $PSVersion=$PSVersionTable.PSVersion.Major 25 | 26 | [int]$systemRoleID = $(get-wmiObject -Class Win32_ComputerSystem).DomainRole 27 | 28 | 29 | 30 | $systemRoles = @{ 31 | 0 = " Standalone Workstation " ; 32 | 1 = " Member Workstation " ; 33 | 2 = " Standalone Server " ; 34 | 3 = " Member Server " ; 35 | 4 = " Backup Domain Controller " ; 36 | 5 = " Primary Domain Controller " 37 | } 38 | 39 | 40 | $permissionFlags = @{ 41 | 0x1 = "Read-List"; 42 | 0x2 = "Write-Create"; 43 | 0x4 = "Append-Create Subdirectory"; 44 | 0x20 = "Execute file-Traverse directory"; 45 | 0x40 = "Delete child" 46 | 0x10000 = "Delete"; 47 | 0x40000 = "Write access to DACL"; 48 | 0x80000 = "Write Onwer" 49 | } 50 | 51 | 52 | 53 | $aceTypes = @{ 54 | 0 = "Allow"; 55 | 1 = "Deny" 56 | } 57 | 58 | 59 | 60 | 61 | 62 | function initialize-audit { 63 | 64 | clear-host 65 | 66 | SecEdit.exe /export /cfg $secpolFilePath /quiet 67 | 68 | $start = get-date 69 | 70 | sleep 1 71 | 72 | write-host "Starting Audit at", $start 73 | "-------------------------------------`n" 74 | 75 | sleep 2 76 | 77 | Write-Host "[?] Checking for administrative privileges ..`n" -ForegroundColor black -BackgroundColor white 78 | 79 | $isAdmin = ([System.Security.Principal.WindowsPrincipal][System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) 80 | 81 | if(!$isAdmin){ 82 | 83 | Write-Warning "[-] Some of the operations need administrative privileges.`n" 84 | 85 | Write-Warning "[*] Please run the script using an administrative account.`n" 86 | 87 | Read-Host "Type any key to continue .." 88 | 89 | exit 90 | } 91 | 92 | write-host "[?] Checking for Default PowerShell version ..`n" -ForegroundColor black -BackgroundColor white 93 | 94 | if($PSVersion -lt 2){ 95 | 96 | Write-Warning "[!] You have PowerShell v1.0.`n" 97 | 98 | Write-Warning "[!] This script only supports Powershell verion 2 or above.`n" 99 | 100 | read-host "Type any key to continue .." 101 | 102 | exit 103 | } 104 | 105 | write-host " [+] -----> PowerShell v$PSVersion`n" 106 | 107 | write-host "[?] Detecting system role ..`n" -ForegroundColor black -BackgroundColor white 108 | 109 | $systemRoleID = $(get-wmiObject -Class Win32_ComputerSystem).DomainRole 110 | 111 | write-host " [+] ----->",$systemRoles[[int]$systemRoleID],"`n" 112 | 113 | 114 | get-LocalSecurityProducts 115 | 116 | get-WorldExposedLocalShares 117 | 118 | if($systemRoleID -eq 1){ 119 | check-LocalMembership 120 | } 121 | 122 | check-UACLevel 123 | 124 | check-autoruns 125 | 126 | get-BinaryWritableServices -display 127 | 128 | get-ConfigurableServices -display 129 | 130 | get-UnquotedPathServices -display 131 | 132 | check-HostedServices -display 133 | 134 | check-DLLHijackability 135 | 136 | check-UnattendedInstallFiles 137 | 138 | check-scheduledTasks 139 | 140 | $fin = get-date 141 | 142 | "`n[!]Done`n" 143 | 144 | "Audit completed in {0} seconds. `n" -f $(New-TimeSpan -Start $start -End $fin ).TotalSeconds 145 | 146 | } 147 | 148 | function get-LocalSecurityProducts 149 | { 150 | <# 151 | .SYNOPSIS 152 | Gets Windows Firewall Profile status and checks for installed third party security products. 153 | 154 | .DESCRIPTION 155 | This function operates by examining registry keys specific to the Windows Firewall and by using the 156 | Windows Security Center to get information regarding installed security products. 157 | 158 | .NOTE 159 | The documentation in the msdn is not very clear regarding the productState property provided by 160 | the SecurityCenter2 namespace. For this reason, this function only uses available informations that were obtained by testing 161 | different security products againt the Windows API. 162 | 163 | .LINK 164 | http://neophob.com/2010/03/wmi-query-windows-securitycenter2 165 | #> 166 | 167 | 168 | $firewallPolicySubkey="HKLM:\SYSTEM\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy" 169 | 170 | Write-host "`n[?] Checking if Windows Firewall is enabled ..`n" -ForegroundColor black -BackgroundColor white 171 | 172 | Write-host " [?] Checking Firewall Profiles ..`n" -ForegroundColor black -BackgroundColor white 173 | 174 | try{ 175 | 176 | if(Test-Path -Path $($firewallPolicySubkey+"\StandardProfile")){ 177 | 178 | $enabled = $(Get-ItemProperty -Path $($firewallPolicySubkey+"\StandardProfile") -Name EnableFirewall).EnableFirewall 179 | 180 | if($enabled -eq 1){$standardProfile="Enabled"}else{$standardProfile="Disabled"} 181 | 182 | " [*] Standard Profile Firewall : {0}.`n" -f $standardProfile 183 | }else{ 184 | 185 | Write-Warning " [-] Could not find Standard Profile Registry Subkey.`n" 186 | 187 | } 188 | 189 | if(Test-Path -Path $($firewallPolicySubkey+"\PublicProfile")){ 190 | 191 | $enabled = $(Get-ItemProperty -Path $($firewallPolicySubkey+"\PublicProfile") -Name EnableFirewall).EnableFirewall 192 | 193 | if($enabled -eq 1){$publicProfile="Enabled"}else{$publicProfile="Disabled"} 194 | 195 | " [*] Public Profile Firewall : {0}.`n" -f $publicProfile 196 | }else{ 197 | Write-Warning " [-] Could not find Public Profile Registry Subkey.`n" 198 | 199 | } 200 | 201 | if(Test-Path -Path $($firewallPolicySubkey+"\DomainProfile")){ 202 | 203 | $enabled = (Get-ItemProperty -Path $($firewallPolicySubkey+"\DomainProfile") -Name EnableFirewall).EnableFirewall 204 | 205 | if($enabled -eq 1){$domainProfile="Enabled"}else{$domainProfile="Disabled"} 206 | 207 | " [*] Domain Profile Firewall : {0}.`n`n" -f $domainProfile 208 | }else{ 209 | Write-Warning " [-] Could not find Private Profile Registry Subkey.`n`n" 210 | } 211 | 212 | 213 | 214 | 215 | }catch{ 216 | $errorMessage = $_.Exception.Message 217 | 218 | $failedItem = $_.Exception.ItemName 219 | 220 | "[-] Exception : "| Set-Content $exceptionsFilePath 221 | 222 | "[*] Error Message : `n",$errorMessage | Set-Content $exceptionsFilePath 223 | 224 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 225 | 226 | Write-Warning -Message "[-] Error : Could not check Windows Firewall registry informations .`n`n" 227 | } 228 | 229 | 230 | $SecurityProvider=@{ 231 | "00" = "None"; 232 | "01" = "Firewall"; 233 | "02" = "AutoUpdate_Settings"; 234 | "04" = "AntiVirus"; 235 | "08" = "AntiSpyware"; 236 | "10" = "Internet_Settings"; 237 | "20" = "User_Account_Control"; 238 | "40" = "Service" 239 | } 240 | 241 | 242 | $RealTimeBehavior = @{ 243 | "00" = "Off"; 244 | "01" = "Expired"; 245 | "10" = "ON"; 246 | "11" = "Snoozed" 247 | } 248 | 249 | 250 | $DefinitionStatus = @{ 251 | "00" = "Up-to-date"; 252 | "10" = "Out-of-date" 253 | 254 | } 255 | 256 | $role = $(get-wmiObject -Class Win32_ComputerSystem).DomainRole 257 | 258 | if($role -ne 0 -and $role -ne 1){ 259 | return 260 | } 261 | 262 | if(Get-WmiObject -Namespace root -class __NAMESPACE -filter "name='SecurityCenter2'"){ 263 | 264 | $securityCenterNS="root\SecurityCenter2" 265 | 266 | }else{ 267 | 268 | $securityCenterNS="root\SecurityCenter" 269 | } 270 | 271 | 272 | 273 | # checks for third party firewall products 274 | 275 | Write-host "`n[?] Checking for third party Firewall products .. `n" -ForegroundColor Black -BackgroundColor White 276 | 277 | 278 | try { 279 | 280 | $firewalls= @(Get-WmiObject -Namespace $securityCenterNS -class FirewallProduct) 281 | 282 | if($firewalls.Count -eq 0){ 283 | 284 | " [-] No other firewall installed.`n" 285 | }else{ 286 | 287 | " [+] Found {0} third party firewall products.`n" -f $($firewalls.Count) 288 | 289 | Write-host " [?] Checking for product configuration ...`n" -ForegroundColor black -BackgroundColor white 290 | 291 | $firewalls| % { 292 | 293 | # The structure of the API is different depending on the version of the SecurityCenter Namespace 294 | if($securityCenterNS.endswith("2")){ 295 | 296 | [int]$productState=$_.ProductState 297 | 298 | $hexString=[System.Convert]::toString($productState,16).padleft(6,'0') 299 | 300 | $provider=$hexString.substring(0,2) 301 | 302 | $realTimeProtec=$hexString.substring(2,2) 303 | 304 | $definition=$hexString.substring(4,2) 305 | 306 | " [+] Product Name : {0}." -f $_.displayName 307 | " [+] Service Type : {0}." -f $SecurityProvider[[String]$provider] 308 | " [+] State : {0}.`n`n" -f $RealTimeBehavior[[String]$realTimeProtec] 309 | 310 | }else{ 311 | 312 | " [+] Company Name : {0}." -f $_.CompanyName 313 | " [+] Product Name : {0}." -f $_.displayName 314 | " [+] State : {0}.`n`n" -f $_.enabled 315 | 316 | } 317 | 318 | } 319 | 320 | } 321 | 322 | sleep 2 323 | 324 | # checks for antivirus products 325 | 326 | Write-host "`n[?] Checking for installed antivirus products ..`n"-ForegroundColor Black -BackgroundColor white 327 | 328 | $antivirus=@(Get-WmiObject -Namespace $securityCenterNS -class AntiVirusProduct) 329 | 330 | if($antivirus.Count -eq 0){ 331 | 332 | " [-] No antivirus product installed.`n`n" 333 | 334 | }else{ 335 | " [+] Found {0} AntiVirus solutions.`n" -f $($antivirus.Count) 336 | 337 | Write-host " [?] Checking for product configuration ..`n" -ForegroundColor black -BackgroundColor white 338 | 339 | $antivirus|%{ 340 | if($securityCenterNS.endswith("2")){ 341 | 342 | [int]$productState=$_.ProductState 343 | 344 | $hexString=[System.Convert]::toString($productState,16).padleft(6,'0') 345 | 346 | $provider=$hexString.substring(0,2) 347 | 348 | $realTimeProtec=$hexString.substring(2,2) 349 | 350 | $definition=$hexString.substring(4,2) 351 | 352 | " [+] Product Name : {0}." -f $_.displayName 353 | " [+] Service Type : {0}." -f $SecurityProvider[[String]$provider] 354 | " [+] Real Time Protection : {0}." -f $RealTimeBehavior[[String]$realTimeProtec] 355 | " [+] Signature Definitions : {0}.`n`n" -f $DefinitionStatus[[String]$definition] 356 | 357 | }else{ 358 | 359 | " [+] Company Name : {0}." -f $_.CompanyName 360 | " [+] Product Name : {0}." -f $_.displayName 361 | " [+] Real Time Protection : {0}." -f $_.onAccessScanningEnabled 362 | " [+] Product up-to-date : {0}.`n`n" -f $_.productUpToDate 363 | } 364 | 365 | } 366 | 367 | 368 | } 369 | 370 | 371 | # Checks for antispyware products 372 | 373 | Write-host "`n[?] Checking for installed antispyware products ..`n"-ForegroundColor Black -BackgroundColor white 374 | 375 | $antispyware=@(Get-WmiObject -Namespace $securityCenterNS -class AntiSpywareProduct) 376 | 377 | if($antispyware.Count -eq 0){ 378 | 379 | " [-] No antiSpyware product installed.`n`n" 380 | 381 | }else{ 382 | " [+] Found {0} antiSpyware solutions.`n" -f $($antiSpyware.Count) 383 | 384 | Write-host " [?] Checking for product configuration ..`n" -ForegroundColor black -BackgroundColor white 385 | 386 | $antispyware| % { 387 | 388 | if($securityCenterNS.endswith("2")){ 389 | 390 | [int]$productState=$_.ProductState 391 | 392 | $hexString=[System.Convert]::toString($productState,16).padleft(6,'0') 393 | 394 | $provider=$hexString.substring(0,2) 395 | 396 | $realTimeProtec=$hexString.substring(2,2) 397 | 398 | $definition=$hexString.substring(4,2) 399 | 400 | " [+] Product Name : {0}." -f $_.displayName 401 | " [+] Service Type : {0}." -f $SecurityProvider[[String]$provider] 402 | " [+] Real Time Protection : {0}." -f $RealTimeBehavior[[String]$realTimeProtec] 403 | " [+] Signature Definitions : {0}.`n`n" -f $DefinitionStatus[[String]$definition] 404 | 405 | }else{ 406 | 407 | " [+] Company Name : {0}." -f $_.CompanyName 408 | " [+] Product Name : {0}." -f $_.displayName 409 | " [+] Real Time Protection : {0}." -f $_.onAccessScanningEnabled 410 | " [+] Product up-to-date : {0}.`n`n" -f $_.productUpToDate 411 | 412 | } 413 | 414 | } 415 | 416 | } 417 | 418 | 419 | }catch{ 420 | 421 | $errorMessage = $_.Exception.Message 422 | 423 | $failedItem = $_.Exception.ItemName 424 | 425 | "[-] Exception : "| Set-Content $exceptionsFilePath 426 | 427 | "[*] Error Message : `n",$errorMessage | Set-Content $exceptionsFilePath 428 | 429 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 430 | 431 | 432 | 433 | } 434 | 435 | } 436 | 437 | 438 | function get-WorldExposedLocalShares 439 | { 440 | <# 441 | .SYNOPSIS 442 | Gets informations about local shares and their associated DACLs. 443 | 444 | .DESCRIPTION 445 | This function checks local file system shares and collects informations about each 446 | Access Control Entry (ACE) looking for those targeting the Everyone(Tout le monde) group. 447 | 448 | .NOTE 449 | This function can be modified in a way that for each share we 450 | return its corresponding ace objects for further processing. 451 | 452 | .LINK 453 | https://msdn.microsoft.com/en-us/library/windows/desktop/aa374862(v=vs.85).aspx 454 | 455 | #> 456 | 457 | 458 | $exists = $false 459 | 460 | $rules=@() 461 | 462 | Write-Host "`n[?] Checking for World-exposed local shares ..`n" -ForegroundColor black -BackgroundColor White 463 | 464 | try{ 465 | 466 | Get-WmiObject -class Win32_share -Filter "type=0"|%{ 467 | 468 | $rules=@() 469 | 470 | $shareName = $_.Name 471 | 472 | $shareSecurityObj = Get-WmiObject -class Win32_LogicalShareSecuritySetting -Filter "Name='$shareName'" 473 | 474 | $securityDescriptor = $shareSecurityObj.GetSecurityDescriptor().Descriptor 475 | 476 | ForEach($ace in $securityDescriptor.dacl){ 477 | 478 | # Looking for Everyone group (SID="S-1-1-0") permissions 479 | $trusteeSID = (New-Object System.Security.Principal.SecurityIdentifier($ace.trustee.SID, 0)).Value.ToString() 480 | 481 | 482 | if($trusteeSID -eq "S-1-1-0" -and $aceTypes[[int]$ace.aceType] -eq "Allow"){ 483 | 484 | $accessMask = $ace.accessmask 485 | 486 | $permissions ="" 487 | 488 | foreach($flag in $permissionFlags.Keys){ 489 | 490 | if($flag -band $accessMask){ 491 | 492 | $permissions+=$permissionFlags[$flag] 493 | 494 | $permissions+="$" 495 | } 496 | } 497 | 498 | $rule = New-Object PSObject -Property @{ 499 | 500 | "ShareName" = $shareName 501 | "Trustee" = $ace.trustee.Name 502 | "Permissions" = $permissions 503 | } 504 | 505 | $rules+=$rule 506 | 507 | $exists=$true 508 | 509 | } 510 | 511 | } 512 | 513 | if($rules.Count -gt 0){ 514 | 515 | "[*]-----------------------------------------------------------------------------[*]" 516 | 517 | $rules| fl ShareName,Trustee,Permissions 518 | 519 | } 520 | 521 | } 522 | 523 | if(!$exists){ 524 | 525 | " [-] No local World-exposed shares were found .`n`n" 526 | } 527 | 528 | 529 | 530 | 531 | }catch{ 532 | 533 | $errorMessage = $_.Exception.Message 534 | 535 | $failedItem = $_.Exception.ItemName 536 | 537 | "[-] Exception : "| Set-Content $exceptionsFilePath 538 | 539 | "[*] Error Message : `n",$errorMessage | Set-Content $exceptionsFilePath 540 | 541 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 542 | 543 | "[-] Unable to inspect local shares. " 544 | } 545 | 546 | } 547 | 548 | 549 | 550 | 551 | 552 | $global:local_member = $false 553 | 554 | function check-LocalMembership 555 | { 556 | <# 557 | .SYNOPSIS 558 | Gets domain users and groups with local group membership. 559 | 560 | .DESCRIPTION 561 | This function checks local groups on the machine for domain users/groups who are members in a local group. 562 | It uses ADSI with the WinNT and LDAP providers to access user and group objects. 563 | 564 | .NOTE 565 | The machine must be a domain member. This is needed in order to resolve 566 | the identity references of domain members. 567 | 568 | #> 569 | 570 | try{ 571 | 572 | write-host "`n[?] Checking for domain users with local group membership ..`n" -ForegroundColor Black -BackgroundColor White 573 | 574 | $adsi = [ADSI]"WinNT://$env:COMPUTERNAME" 575 | 576 | $adsigroups= $adsi.Children|? {$_.SchemaClassName -eq "group"} 577 | 578 | $adsigroups|%{ 579 | 580 | check-GroupLocalMembership $_ 581 | } 582 | 583 | if($global:local_member -eq $false){ 584 | 585 | " [-] Found no domain user or group with local group membership." 586 | } 587 | 588 | "`n`n" 589 | 590 | }catch{ 591 | 592 | $errorMessage = $_.Exception.Message 593 | 594 | $failedItem = $_.Exception.ItemName 595 | 596 | "[-] Exception : "| Set-Content $exceptionsFilePath 597 | 598 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 599 | 600 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 601 | 602 | 603 | } 604 | 605 | } 606 | 607 | 608 | function check-GroupLocalMembership($group) 609 | { 610 | <# 611 | .SYNOPSIS 612 | Given a specific ADSI group object, it checks whether it is a local or domain 613 | group and looks fro its members. 614 | 615 | .DESCRIPTION 616 | This function is used by the get-LocalMembership function for inspecting nested 617 | groups membership. 618 | 619 | #> 620 | 621 | $groupName=$group.GetType.Invoke().InvokeMember("Name","GetProperty", $null, $group, $null) 622 | 623 | $GroupMembers = @($group.invoke("Members")) 624 | 625 | $GroupMembers|% { 626 | 627 | $adspath = $_.GetType.Invoke().InvokeMember("ADsPath", "GetProperty", $null, $_, $null) 628 | 629 | $sidBytes = $_.GetType.Invoke().InvokeMember("ObjectSID", "GetProperty", $null, $_, $null) 630 | 631 | $subjectName = (New-Object System.Security.Principal.SecurityIdentifier($sidBytes,0)).Translate([System.Security.Principal.NTAccount]) 632 | 633 | if($_.GetType.Invoke().InvokeMember("class", "GetProperty", $null, $_, $null) -eq "group"){ 634 | 635 | # check if we have a local group object 636 | if($adspath -match "/$env:COMPUTERNAME/") { 637 | 638 | check-LocalGroupMembership $_ 639 | 640 | }else{ 641 | # It is a domain group, no further processing needed 642 | Write-Host " [+] Domain group ",$subjectName," is a member in the",$groupName,"local group.`n" 643 | 644 | $global:local_member=$true 645 | } 646 | 647 | 648 | }else{ 649 | # if not a group, then it must be a user 650 | if( !($adspath -match $env:COMPUTERNAME) ){ 651 | 652 | Write-Host " [+] Domain user ",$subjectName,"is a member of the",$groupName,"local group.`n" 653 | 654 | $global:local_member=$true 655 | } 656 | } 657 | 658 | } 659 | 660 | 661 | 662 | 663 | } 664 | 665 | function check-UACLevel 666 | { 667 | <# 668 | .SYNOPSIS 669 | Checks current configuration of User Account Control. 670 | 671 | .DESCRIPTION 672 | This functions inspects registry informations related to UAC configuration 673 | and checks whether UAC is enabled and which level of operation is used. 674 | 675 | #> 676 | 677 | try{ 678 | 679 | Write-Host "`n[?] Checking for UAC configuration ..`n" -ForegroundColor Black -BackgroundColor White 680 | 681 | $UACRegValues = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System 682 | 683 | if([int]$UACRegValues.EnableLUA -eq 1){ 684 | 685 | " [+] UAC is enabled.`n" 686 | }else{ 687 | 688 | " [-] UAC is disabled.`n" 689 | 690 | } 691 | 692 | Write-Host " [?]Checking for UAC level ..`n" -ForegroundColor black -BackgroundColor white 693 | 694 | $consentPrompt=$UACregValues.ConsentPromptBehaviorAdmin 695 | 696 | $secureDesktop=$UACregValues.PromptOnSecureDesktop 697 | 698 | if( $consentPrompt -eq 0 -and $secureDesktop -eq 0){ 699 | 700 | " [*] UAC Level : Never Notify.`n`n" 701 | 702 | }elseif($consentPrompt -eq 5 -and $secureDesktop -eq 0){ 703 | 704 | " [*] UAC Level : Notify only when apps try to make changes (No secure desktop).`n`n" 705 | 706 | }elseif($consentPrompt -eq 5 -and $secureDesktop -eq 1){ 707 | 708 | " [*] UAC Level : Notify only when apps try to make changes (secure desktop on).`n`n" 709 | 710 | }elseif($consentPrompt -eq 5 -and $secureDesktop -eq 2){ 711 | 712 | " [*] UAC Level : Always Notify with secure desktop.`n`n" 713 | } 714 | 715 | 716 | 717 | }catch{ 718 | 719 | $errorMessage = $_.Exception.Message 720 | 721 | $failedItem = $_.Exception.ItemName 722 | 723 | "[-] Exception : "| Set-Content $exceptionsFilePath 724 | 725 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 726 | 727 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 728 | 729 | 730 | } 731 | 732 | 733 | } 734 | 735 | 736 | function check-DLLHijackability{ 737 | 738 | <# 739 | .SYNOPSIS 740 | Checks DLL Search mode and inspects permissions for directories in system %PATH% 741 | and checks write access for Authenticated Users group on these directories. 742 | 743 | .DESCRIPTION 744 | This functions tries to identify if DLL Safe Search is used and inspects 745 | write access to directories in the path environment variable . 746 | It also looks for any DLLs loaded by running processes (#TODO) 747 | 748 | #> 749 | 750 | Write-host "`n[?] Checking for DLL hijackability ..`n" -ForegroundColor Black -BackgroundColor White 751 | 752 | Write-host " [?] Checking for Safe DLL Search mode ..`n" -ForegroundColor Black -BackgroundColor White 753 | 754 | try{ 755 | 756 | $value = Get-ItemProperty 'HKLM:\SYSTEM\ControlSet001\Control\Session Manager\' -Name SafeDllSearchMode -ErrorAction SilentlyContinue 757 | 758 | if($value -and ($value.SafeDllSearchMode -eq 0)){ 759 | 760 | " [+] DLL Safe Search is disabled !`n" 761 | }else{ 762 | 763 | " [+] DLL Safe Search is enabled !`n" 764 | } 765 | 766 | Write-Host " [?] Checking directories in PATH environment variable ..`n" -ForegroundColor black -BackgroundColor white 767 | 768 | $systemPath = (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).PATH 769 | 770 | $systemPath.split(";")| %{ 771 | 772 | $directory = $_ 773 | 774 | $writable=$false 775 | 776 | # We are inspecting write access for the Authenticated Users group 777 | 778 | $sid = "S-1-5-11" 779 | 780 | $dirAcl = Get-Acl $($directory.trim('"')) 781 | 782 | foreach($rule in $dirAcl.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])){ 783 | 784 | if($rule.IdentityReference -eq $sid){ 785 | 786 | $accessMask = $rule.FileSystemRights.value__ 787 | 788 | # Here we are checking directory write access in UNIX sense (write/delete/modify permissions) 789 | # We use a combination of flags 790 | 791 | if($accessMask -BAND 0xd0046){ 792 | 793 | $writable=$true 794 | } 795 | } 796 | } 797 | 798 | $item = New-Object psobject -Property @{ 799 | 800 | "Directory" = $directory 801 | "Writable" = $writable 802 | 803 | } 804 | 805 | $item 806 | 807 | 808 | }| ft Directory,Writable 809 | 810 | "`n`n" 811 | 812 | }catch{ 813 | 814 | $errorMessage = $_.Exception.Message 815 | 816 | $failedItem = $_.Exception.ItemName 817 | 818 | "[-] Exception : "| Set-Content $exceptionsFilePath 819 | 820 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 821 | 822 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 823 | 824 | 825 | 826 | } 827 | 828 | 829 | } 830 | 831 | 832 | function get-BinaryWritableServices 833 | { 834 | param([switch]$display) 835 | 836 | <# 837 | .SYNOPSIS 838 | Gets services whose binaries are writable by Authenticated Users and Everyone group members. 839 | 840 | .DESCRIPTION 841 | This function checks services that have writable binaries and returns an array 842 | containing service objects. 843 | 844 | .RETURNS 845 | When invoked without the $display switch, returns a hashtable of {name : pathname} 846 | couples. 847 | 848 | #> 849 | 850 | 851 | 852 | [array]$writableServices=@() 853 | 854 | # We are inspecting write access for Authenticated Users group members (SID = "S-1-5-11") and Everyone (SID = "S-1-1-0") 855 | $sids = @("S-1-5-11", "S-1-1-0") 856 | # Services to be ignored are those in system32 subtree 857 | $services = Get-WmiObject -Class Win32_Service|?{$_.pathname -ne $null -and $_.pathname -notmatch ".*system32.*"} 858 | 859 | Write-Host "`n[?] Checking for binary-writable services ..`n" -ForegroundColor Black -BackgroundColor White 860 | 861 | try{ 862 | 863 | if($services){ 864 | 865 | $services | % { 866 | 867 | $service = $_ 868 | 869 | $pathname = $($service.pathname.subString(0, $service.pathname.toLower().IndexOf(".exe")+4)).trim('"') 870 | 871 | $binaryAcl = Get-Acl $pathname -ErrorAction SilentlyContinue 872 | 873 | if($binaryAcl){ 874 | 875 | foreach($rule in $binaryAcl.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])){ 876 | 877 | $sids | %{ 878 | 879 | $sid = $_ 880 | 881 | if($rule.IdentityReference -eq $sid){ 882 | 883 | $accessMask = $rule.FileSystemRights.value__ 884 | 885 | if($accessMask -band 0xd0006){ 886 | 887 | $writableServices+=$service 888 | } 889 | } 890 | } 891 | } 892 | 893 | } 894 | 895 | } 896 | 897 | } 898 | 899 | if($display){ 900 | 901 | if($writableServices.Count -gt 0){ 902 | 903 | $writableServices|ft @{Expression={$_.name};Label="Name";width=12}, ` 904 | @{Expression={$_.pathname};Label="Path"} 905 | 906 | }else{ 907 | 908 | " [-] Found no binary-writable service." 909 | } 910 | 911 | }else{ 912 | 913 | return $writableServices 914 | 915 | } 916 | 917 | "`n`n" 918 | 919 | 920 | }catch{ 921 | 922 | $errorMessage = $_.Exception.Message 923 | 924 | $failedItem = $_.Exception.ItemName 925 | 926 | "[-] Exception : "| Set-Content $exceptionsFilePath 927 | 928 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 929 | 930 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 931 | 932 | } 933 | 934 | 935 | } 936 | 937 | 938 | 939 | function get-UnquotedPathServices 940 | { 941 | param([switch]$display) 942 | 943 | <# 944 | .SYNOPSIS 945 | Looks for services with unquoted path vulnerability . 946 | 947 | .DESCRIPTION 948 | This function gets all non-system32 services with unquotted pathnames. 949 | If display switch is used, it displays the name, state, start mode and pathname information, 950 | otherwise it returns a array of the vulnerable services. 951 | 952 | .RETURNS 953 | When invoked without the $display switch, returns a hashtable of {name: pathname} 954 | couples. 955 | 956 | #> 957 | 958 | Write-Host "`n[?] Checking for unquoted path services ..`n" -ForegroundColor Black -BackgroundColor White 959 | 960 | try{ 961 | 962 | [array]$services = Get-WmiObject -Class Win32_Service| ? { 963 | 964 | $_.pathname.trim() -ne "" -and 965 | 966 | $_.pathname.trim() -notmatch '^"' -and 967 | 968 | $_.pathname.subString(0, $_.pathname.IndexOf(".exe")+4) -match ".* .*" 969 | 970 | } 971 | 972 | 973 | if($display){ 974 | 975 | if($services.Count -gt 0){ 976 | 977 | $services|ft @{Expression={$_.name};Label="Name";width=12}, ` 978 | 979 | @{Expression={$_.state};Label="Sate";width=12}, ` 980 | 981 | @{Expression={$_.StartMode};Label="Start Mode";width=12}, ` 982 | 983 | @{Expression={$_.pathname};Label="Path"} ; 984 | 985 | "" 986 | }else{ 987 | 988 | " [-] Found no service with unquoted pathname." 989 | } 990 | 991 | "`n`n" 992 | 993 | }else{ 994 | 995 | return $services 996 | 997 | } 998 | 999 | 1000 | }catch{ 1001 | 1002 | $errorMessage = $_.Exception.Message 1003 | 1004 | $failedItem = $_.Exception.ItemName 1005 | 1006 | "[-] Exception : "| Set-Content $exceptionsFilePath 1007 | 1008 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 1009 | 1010 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 1011 | 1012 | 1013 | 1014 | } 1015 | 1016 | 1017 | } 1018 | 1019 | 1020 | 1021 | function get-ConfigurableServices{ 1022 | 1023 | param([Switch]$display) 1024 | 1025 | <# 1026 | .SYNOPSYS 1027 | Gets all services that the current user can configure 1028 | 1029 | .DESCRIPTION 1030 | This function tries to enumerate services for which configuration 1031 | properties can be modified by the Authenticated Users group members. 1032 | It uses the sc utility with the sdshow command to inspect the security 1033 | descriptor of the service object. 1034 | 1035 | 1036 | .RETURNS 1037 | When invoked without the $display switch, returns a hashtable of {name: pathname} 1038 | couples. 1039 | 1040 | #> 1041 | 1042 | 1043 | $configurable=@{} 1044 | 1045 | Write-Host "`n[?] Checking for configurable services ..`n" -ForegroundColor Black -BackgroundColor White 1046 | 1047 | try{ 1048 | 1049 | Get-WmiObject -Class Win32_Service | % { 1050 | 1051 | # get the security descriptor of the service in SDDL format 1052 | 1053 | $sddl = [String]$(sc.exe sdshow $($_.Name)) 1054 | 1055 | if($sddl -match "S:"){ 1056 | 1057 | $dacl = $sddl.substring(0,$sddl.IndexOf("S:")) 1058 | 1059 | }else{ 1060 | 1061 | $dacl = $sddl 1062 | 1063 | } 1064 | 1065 | # We are interested in permissions related to Authenticated Users and Everyone group which are assigned 1066 | # well known aliases ("AU", "WD" respectively) in the security descriptor sddl string. 1067 | 1068 | $permissions = [regex]::match($dacl, '\(A;;[A-Z]+;;;(AU|WD)\)') 1069 | 1070 | if($permissions){ 1071 | 1072 | if($permissions.value.split(';')[2] -match "WD"){ 1073 | 1074 | $configurable[$_.Name] = $($_.pathname.substring(0, $_.pathname.toLower().indexOf(".exe")+4)).trim('"') 1075 | 1076 | } 1077 | } 1078 | 1079 | } 1080 | 1081 | if($display){ 1082 | 1083 | if($configurable.Count -gt 0){ 1084 | 1085 | $configurable.GetEnumerator() | ft @{Expression={$_.name};Label="Name"}, ` 1086 | @{Expression={$_.value};Label="Path"} ; 1087 | 1088 | }else{ 1089 | 1090 | " [-] Found no configurable services." 1091 | 1092 | } 1093 | 1094 | "`n`n" 1095 | 1096 | }else{ 1097 | 1098 | return $configurable 1099 | 1100 | } 1101 | 1102 | 1103 | }catch{ 1104 | 1105 | 1106 | $errorMessage = $_.Exception.Message 1107 | 1108 | $failedItem = $_.Exception.ItemName 1109 | 1110 | "[-] Exception : "| Set-Content $exceptionsFilePath 1111 | 1112 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 1113 | 1114 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 1115 | 1116 | 1117 | } 1118 | 1119 | 1120 | } 1121 | 1122 | 1123 | function check-HostedServices { 1124 | 1125 | param([Switch]$display) 1126 | <# 1127 | .SYNOPSIS 1128 | Checks hosted services running DLLs not located in the system32 subtree. 1129 | 1130 | .DESCRIPTION 1131 | This functions tries to identify whether there are any configured hosted 1132 | services based on DLLs not in system32. 1133 | 1134 | .RETURNS 1135 | When invoked without the $display switch, returns 1136 | PSobject array containing the service name, service groupname 1137 | and the service DLL path. 1138 | 1139 | #> 1140 | 1141 | 1142 | $exits=$false 1143 | 1144 | $svcs=@() 1145 | 1146 | try{ 1147 | 1148 | $services = Get-WmiObject -Class Win32_service | ?{ $_.pathname -match "svchost\.exe" -and $(Test-Path $("HKLM:\SYSTEM\CurrentControlSet\Services\"+$_.Name+"\Parameters")) -eq $true} 1149 | 1150 | Write-Host "`n[?] Checking hosted services (svchost.exe) ..`n" -ForegroundColor Black -BackgroundColor White 1151 | 1152 | if($services){ 1153 | 1154 | foreach($service in $services){ 1155 | 1156 | $serviceName = $service.Name 1157 | 1158 | $serviceGroup = $service.pathname.split(" ")[2] 1159 | 1160 | $serviceDLLPath=$(Get-ItemProperty $("HKLM:\SYSTEM\CurrentControlSet\Services\"+$service.Name+"\Parameters") -Name ServiceDLL).ServiceDLL 1161 | 1162 | if($serviceDLLPath -ne $null -and $serviceDLLPath -notmatch ".*system32.*"){ 1163 | 1164 | $svcs+= New-Object psobject -Property @{ 1165 | 1166 | serviceName = $serviceName 1167 | serviceGroup = $serviceGroup 1168 | serviceDLLPath = $serviceDLLPath 1169 | 1170 | } 1171 | 1172 | $exits=$true 1173 | 1174 | } 1175 | 1176 | } 1177 | 1178 | if($display){ 1179 | 1180 | $svcs|ft * 1181 | 1182 | "`n`n" 1183 | }else{ 1184 | return $svcs 1185 | 1186 | } 1187 | 1188 | } 1189 | 1190 | if(! $exits){ 1191 | 1192 | " [-] Found no user hosted services.`n" 1193 | 1194 | } 1195 | 1196 | 1197 | 1198 | 1199 | }catch{ 1200 | 1201 | $errorMessage = $_.Exception.Message 1202 | 1203 | $failedItem = $_.Exception.ItemName 1204 | 1205 | "[-] Exception : "| Set-Content $exceptionsFilePath 1206 | 1207 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 1208 | 1209 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 1210 | 1211 | } 1212 | 1213 | 1214 | } 1215 | 1216 | function check-autoruns { 1217 | 1218 | <# 1219 | .SYNOPSIS 1220 | Looks for autoruns specified in different places in the registry. 1221 | 1222 | .DESCRIPTION 1223 | This function inspects common registry keys used for autoruns. 1224 | It examines the properties of these keys and report any found executables along with their pathnames. 1225 | 1226 | #> 1227 | 1228 | 1229 | $RegistryKeys = @( 1230 | "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute", 1231 | "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify", 1232 | "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit", 1233 | "HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\\Shell", 1234 | "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\\Shell", 1235 | "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad", 1236 | "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\", 1237 | "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce\", 1238 | "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\", 1239 | "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\", 1240 | "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce\", 1241 | "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run\", 1242 | "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run\", 1243 | "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices\", 1244 | "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices", 1245 | "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce", 1246 | "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce", 1247 | "HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\load", 1248 | "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows", 1249 | "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler", 1250 | "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs" # DLLs specified in this entry can hijack any process that uses user32.dll 1251 | 1252 | # not sure if it is all we need to check! 1253 | ) 1254 | 1255 | 1256 | 1257 | $exits=$false 1258 | 1259 | Write-Host "`n[?] Checking registry keys for autoruns ..`n" -ForegroundColor Black -BackgroundColor White 1260 | 1261 | try{ 1262 | 1263 | $RegistryKeys | %{ 1264 | 1265 | $key = $_ 1266 | 1267 | if(Test-Path -Path $key){ 1268 | 1269 | $executables = @{} 1270 | 1271 | [array]$properties = get-item $key | Select-Object -ExpandProperty Property 1272 | 1273 | if($properties.Count -gt 0){ 1274 | 1275 | " [*] $key : " 1276 | 1277 | foreach($exe in $properties) { 1278 | 1279 | $executables[$exe]=$($($(Get-ItemProperty $key).$exe)).replace('"','') 1280 | 1281 | } 1282 | 1283 | $executables | ft @{Expression={$_.Name};Label="Executable"}, ` 1284 | @{Expression={$_.Value};Label="Path"} 1285 | 1286 | $exits=$true 1287 | } 1288 | } 1289 | } 1290 | 1291 | 1292 | 1293 | if($exits -eq $false){ 1294 | 1295 | " [-] Found no autoruns ." 1296 | } 1297 | 1298 | "`n`n" 1299 | 1300 | }catch{ 1301 | 1302 | $errorMessage = $_.Exception.Message 1303 | 1304 | $failedItem = $_.Exception.ItemName 1305 | 1306 | "[-] Exception : "| Set-Content $exceptionsFilePath 1307 | 1308 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 1309 | 1310 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 1311 | 1312 | 1313 | 1314 | } 1315 | 1316 | 1317 | } 1318 | 1319 | 1320 | 1321 | 1322 | function check-UnattendedInstallFiles{ 1323 | 1324 | <# 1325 | .SYNOPSIS 1326 | Checks for remaining files used by unattended installs . 1327 | 1328 | .DESCRIPTION 1329 | This functions checks for remaining files used during Windows deployment 1330 | by searching for specific files . 1331 | 1332 | #> 1333 | 1334 | $found = $false 1335 | 1336 | $targetFiles = @( 1337 | "C:\unattended.xml", 1338 | "C:\Windows\Panther\unattend.xml", 1339 | "C:\Windows\Panther\Unattend\Unattend.xml", 1340 | "C:\Windows\System32\sysprep.inf", 1341 | "C:\Windows\System32\sysprep\sysprep.xml" 1342 | 1343 | ) 1344 | 1345 | Write-Host "[?] Checking for unattended install leftovers ..`n" -ForegroundColor Black -BackgroundColor White 1346 | 1347 | try{ 1348 | 1349 | $targetFiles | ? {$(Test-Path $_) -eq $true} | %{ 1350 | 1351 | $found=$true; " [+] Found : $_" 1352 | 1353 | } 1354 | 1355 | 1356 | 1357 | if(!$found){ 1358 | 1359 | " [-] No unattended install files were found.`n" 1360 | } 1361 | 1362 | "`n" 1363 | 1364 | }catch{ 1365 | 1366 | $errorMessage = $_.Exception.Message 1367 | 1368 | $failedItem = $_.Exception.ItemName 1369 | 1370 | "[-] Exception : "| Set-Content $exceptionsFilePath 1371 | 1372 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 1373 | 1374 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 1375 | 1376 | 1377 | } 1378 | 1379 | 1380 | } 1381 | 1382 | 1383 | 1384 | function check-scheduledTasks { 1385 | 1386 | <# 1387 | .SYNOPSIS 1388 | Checks for scheduled tasks whose binaries are not in *.system32.* 1389 | 1390 | .DESCRIPTION 1391 | This function looks for scheduled tasks invoking non-system executables. 1392 | 1393 | .NOTE 1394 | This functions uses the schtasks.exe utility to get informations about 1395 | scheduled task and then tries to parse the results. Here I choose to parse XML output from the command. 1396 | Another approach would be using the ScheduledTask Powershell module that was introduced starting from version 3.0 . 1397 | 1398 | #> 1399 | 1400 | 1401 | $found=$false 1402 | 1403 | Write-Host "[?] Checking scheduled tasks.." -ForegroundColor Black -BackgroundColor white 1404 | 1405 | try{ 1406 | [xml]$tasksXMLobj = $(schtasks.exe /query /xml ONE) 1407 | 1408 | $tasksXMLobj.Tasks.Task | %{ 1409 | 1410 | $taskCommandPath = [System.Environment]::ExpandEnvironmentVariables($_.actions.exec.command).trim() 1411 | 1412 | if($taskCommandPath -ne $null -and $taskCommandPath -notmatch ".*system32.*"){ 1413 | 1414 | $sid = New-Object System.Security.Principal.SecurityIdentifier($_.Principals.Principal.UserID) 1415 | 1416 | $taskSecurityContext = $sid.Translate([System.Security.Principal.NTAccount]) 1417 | 1418 | $task = New-Object psobject -Property @{ 1419 | 1420 | TaskCommand = $taskCommandPath 1421 | 1422 | SecurityContext = $taskSecurityContext 1423 | 1424 | } 1425 | 1426 | $found=$true 1427 | 1428 | $task 1429 | } 1430 | 1431 | 1432 | }| fl taskCommand,SecurityContext 1433 | 1434 | if($found -eq $false){ 1435 | 1436 | " [-] No suspicious scheduled tasks were found.`n`n" 1437 | } 1438 | 1439 | 1440 | }catch{ 1441 | 1442 | $errorMessage = $_.Exception.Message 1443 | 1444 | $failedItem = $_.Exception.ItemName 1445 | 1446 | "[-] Exception : "| Set-Content $exceptionsFilePath 1447 | 1448 | '[*] Error Message : `n',$errorMessage | Set-Content $exceptionsFilePath 1449 | 1450 | "[*] Failed Item : `n",$failedItem | Set-Content $exceptionsFilePath 1451 | 1452 | } 1453 | 1454 | } 1455 | 1456 | 1457 | 1458 | initialize-audit 1459 | 1460 | -------------------------------------------------------------------------------- /captures/1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A-mIn3/WINspect/e7ee29fc9e7f7d7d25cad7b914ad7c638273a8a6/captures/1.PNG -------------------------------------------------------------------------------- /captures/2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A-mIn3/WINspect/e7ee29fc9e7f7d7d25cad7b914ad7c638273a8a6/captures/2.PNG -------------------------------------------------------------------------------- /captures/3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A-mIn3/WINspect/e7ee29fc9e7f7d7d25cad7b914ad7c638273a8a6/captures/3.PNG --------------------------------------------------------------------------------