├── LICENSE └── Rps_Http-IOC.ps1 /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 CrowdStrike 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Rps_Http-IOC.ps1: -------------------------------------------------------------------------------- 1 | # Rps_Http ClientInfo IOC search 2 | # 3 | # Credits: CrowdStrike, Inc. (Erik Iker, Sean Palka, Brian Pitchford, Nicolas Zilio) 4 | # 5 | # Summary: Analysis of ClientInfo value in Rps_Http logs indicated that attempted 6 | # exploitation via proxied requests would result in an entry with the TA UserAgent for the 7 | # ClientInfo value. Normal usage would have predictable ClientInfo value of '', 8 | # 'Microsoft WinRM Client', or 'Exchange BackEnd Probes'. 9 | # The original external IP is often included in this log entry, and so the script will 10 | # identify the network path from original source and subsequent proxied hosts used 11 | # to target the vulnerability. 12 | # 13 | # This script assumes the column headers for the Rpc_Http logs have not been modified from their 14 | # original order/format. 15 | # 16 | # Usage: powershell .\Rps_Http-IOC.ps1 'C:\Program Files\Microsoft\Exchange Server\V15\Logging\CmdletInfra\Powershell-Proxy\Http' 17 | 18 | 19 | #Read path to files 20 | $path = $args[0]; 21 | if($path -eq $null){ 22 | write-host "Usage: powershell .\Rps_Http-IOC.ps1 " 23 | write-host "Example: powershell .\Rps_Http-IOC.ps1 'C:\Program Files\Microsoft\Exchange Server\V15\Logging\CmdletInfra\Powershell-Proxy\Http'" 24 | exit; 25 | } 26 | if (-Not (Test-Path -Path $path)) { 27 | write-host "Usage: powershell .\Rps_Http-IOC.ps1 " 28 | write-host "Example: powershell .\Rps_Http-IOC.ps1 'C:\Program Files\Microsoft\Exchange Server\V15\Logging\CmdletInfra\Powershell-Proxy\Http'" 29 | exit; 30 | } 31 | #Header info for Rps_Http logs 32 | $headers = 'DateTime','StartTime','RequestId','MajorVersion','MinorVersion','BuildVersion','RevisionVersion','ClientRequestId','UrlHost','UrlStem','AuthenticationType','IsAuthenticated','AuthenticatedUser','Organization','ManagedOrganization','ClientIpAddress','ServerHostName','FrontEndServer','HttpStatus','SubStatus','ErrorCode','Action','CommandId','CommandName','SessionId','ShellId','FailFast','ContributeToFailFast','RequestBytes','ClientInfo','CPU','Memory','ActivityContextLifeTime','TotalTime','UrlQuery','GenericLatency','GenericInfo','GenericErrors' 33 | 34 | #Tracking variables 35 | $success = 0; 36 | $fail = 0; 37 | $logs = @(); 38 | $paths = @(); 39 | $users = @(); 40 | 41 | #Recurse through directory, only look at Rps_Http logs 42 | write-host "Finding Rps_Http logs in $path..." 43 | $files = Get-ChildItem $path -Filter "*Rps_Http_20*" -Recurse 44 | Foreach ($file in $files) 45 | { 46 | Import-Csv -Path $file.FullName -Header $headers -Delimiter ","| Foreach-Object { 47 | #Get the ClientInfo column 48 | $ua = $_.PSObject.Properties["ClientInfo"].Value 49 | #Detect entries that aren't headers, empty, 'Microsoft WinRM Client' or 'Exchange BackEnd Probes' 50 | if(($ua -ne "ClientInfo") -and ($ua -ne "Microsoft WinRM Client") -and ($ua -ne "Exchange BackEnd Probes") -and ($ua -match '\w')){ 51 | #Get other column details for lines matching the IOC 52 | $time = $_.PSObject.Properties["DateTime"].Value 53 | $src = $_.PSObject.Properties["ClientIPAddress"].Value 54 | $src = $src.replace(' ' , ' -> ') 55 | $server = $_.PSObject.Properties["ServerHostName"].Value 56 | $frontend = $_.PSObject.Properties["FrontEndServer"].Value 57 | $status = $_.PSObject.Properties["HttpStatus"].Value 58 | $user = $_.PSObject.Properties["AuthenticatedUser"].Value 59 | #Check status, 200 indicates possible successful RCE, otherwise attempt was made but failed 60 | if($status -ne 200){ 61 | write-host "$time [FAILURE: $status] Path: $src -> $frontend -> $server as User: [$user]" 62 | $fail++ 63 | } else { 64 | write-host "$time [SUCCESS: $status] Path: $src -> $frontend -> $server as User: [$user] " 65 | $success++ 66 | } 67 | $paths += "$src -> $frontend -> $server" 68 | if($user -match '\w'){ 69 | $users += $user 70 | } 71 | $logs += $file.FullName 72 | } 73 | } 74 | } 75 | $paths = $paths | sort -unique 76 | $users = $users | sort -unique 77 | $logs = $logs | sort -unique 78 | 79 | #Print results 80 | if(($success -gt 0) -or ($fail -gt 0)){ 81 | write-host "#######################################################" 82 | write-host "Summary:" 83 | write-host " $success instances of possible successful proxied exploitation found using UA indicator" 84 | write-host " $fail instances of failed proxied exploitation attempts found using UA indicator" 85 | write-host "#######################################################" 86 | write-host "Network paths used for exploitation attempts:" 87 | Foreach ($path in $paths) 88 | { 89 | write-host " "$path 90 | } 91 | write-host "#######################################################" 92 | write-host "Compromised users:" 93 | Foreach ($user in $users) 94 | { 95 | write-host " "$user 96 | } 97 | write-host "#######################################################" 98 | write-host "The following files contained relevant information:" 99 | Foreach ($log in $logs) 100 | { 101 | write-host " "$log 102 | } 103 | } else { 104 | write-host "No proxied UA indicators found" 105 | } 106 | --------------------------------------------------------------------------------