├── README.md ├── fastcheck.ps1 ├── find_bad_pews_iis.ps1 ├── healthcheck.ps1 ├── ipcheck.ps1 ├── ips.txt └── patch2016cu18.ps1 /README.md: -------------------------------------------------------------------------------- 1 | # ExchangeMarch2021IOCHunt 2 | Really fast knock up use at own risk etc. 3 | 4 | Please read the guidance here: This is not to replace the MS scripts etc. it's meannt as a more detailed view on some of the areas of investiation. 5 | https://www.pwndefend.com/2021/03/07/checking-for-hafnium-or-other-groups-impact-from-exchange-abuse/ 6 | 7 | 08/03/2021 13:59 GMT 8 | Ther's a bug in fastcheck.ps1 the bad IP matching where it's matching a some log data that isn't an IP address. I'm just working on fixing that. 9 | Also it's not fast if there are alot of logs to check! it takes a while! 10 | -------------------------------------------------------------------------------- /fastcheck.ps1: -------------------------------------------------------------------------------- 1 | # IOC CHECKS 2 | # mRr3b00t - use at own risk i don't have an infected system to test on 3 | # uses default paths 4 | # tested on a clean exchange 2016 server 5 | # run with admin rights as you need them to get to the paths 6 | 7 | #check this folder for asp files \inetpub\wwwroot\aspnet_client\system_web 8 | 9 | #using SHA256 for file hash checking 10 | 11 | #Enable following line to see the progress step through this scripts. Not required for automation. 12 | #$verbosepreference = "Continue" 13 | 14 | #Requires -RunAsAdministrator 15 | 16 | 17 | ############################# GET EXCHANGE PATH ############################### 18 | #where is excahnge insatlled? borrowed from MS fanks MS peeps 19 | $exchangepath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup -ErrorAction SilentlyContinue).MsiInstallPath 20 | if ($null -eq $exchangepath) { 21 | $exchangepath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v14\Setup -ErrorAction SilentlyContinue).MsiInstallPath 22 | } 23 | 24 | if($exchangepath -ne ''){ 25 | write-host "Exchange Found" -ForegroundColor Green 26 | write-host $exchangepath 27 | 28 | } 29 | else { 30 | write-host "Exchange not found" -ForegroundColor Magenta 31 | break Uknown 32 | 33 | } 34 | 35 | ############################ END OF GET EXCHANGE PATH ############################### 36 | 37 | read-host "Press ENTER to Continue" 38 | 39 | ##############################CHECK WINDOWS EVENT LOGS############################### 40 | 41 | Write-host "############Checking for suspect events in the Windows event logs#############" -ForegroundColor Cyan 42 | #there should be no events 43 | Write-host "Checking IIS-W3SVC-WP event logs" -ForegroundColor Cyan 44 | Get-EventLog -LogName Application -Source IIS-W3SVC-WP -InstanceId 2303 -ErrorAction SilentlyContinue 45 | Write-host "Checking IIS-APPHOSTSVC event logs" -ForegroundColor Cyan 46 | Get-EventLog -LogName Application -Source IIS-APPHOSTSVC -InstanceId 9009 -ErrorAction SilentlyContinue 47 | 48 | 49 | #CHECK UNIFIED MESSAGING LOGS 50 | 51 | #there should be no events 52 | Write-host "Checking Unified Message event logs" -ForegroundColor Cyan 53 | Get-EventLog -LogName Application -Source "MSExchange Unified Messaging" -EntryType Error -ErrorAction SilentlyContinue | Where-Object { $_.Message -like "*System.InvalidCastException*" } 54 | 55 | ##############################CHECK WINDOWS EVENT LOGS END ############################### 56 | 57 | 58 | ###################################### 59 | #CHECK PROXY LOGS 60 | ###################################### 61 | 62 | #IOC check from mS blog CVE-2021-26855 63 | Write-host "############################################################################" -ForegroundColor Cyan 64 | Write-host "Checking for CVE-2021-26855 in the HttpProxy logs" -ForegroundColor Cyan 65 | 66 | read-host "Press ENTER to Continue" 67 | 68 | #Import-Csv -Path (Get-ChildItem -Recurse -Path "$env:PROGRAMFILES\Microsoft\Exchange Server\V15\Logging\HttpProxy" -Filter '*.log').FullName | Where-Object { $_.AuthenticatedUser -eq '' -and $_.AnchorMailbox -like 'ServerInfo~*/*' } | select DateTime, AnchorMailbox 69 | # this totally broke on a live exchange box so i re-wrote my own detection method (tread carefully) 70 | 71 | #HTTP Proxy path 72 | 73 | $proxylogpath = $exchangepath + "Logging\HttpProxy\*.log" 74 | $proxylogpath 75 | 76 | $files = Get-ChildItem -Recurse $proxylogpath 77 | 78 | foreach($file in $files) 79 | { 80 | #read the file contents into memory 81 | write-host "Reading files" -foregroundcolor Blue 82 | write-host $file.Name -foregroundcolor Yellow 83 | 84 | $readfile = Get-Content -Path $file 85 | 86 | if($readfile -like "*ServerInfo~*/*"){ 87 | #write-host $file.FullName -foregroundcolor cyan 88 | #write-host "SUSPICIOUS LOG DETECTED" -foregroundcolor red 89 | #write-host "investigate further look for if the AuthenticatedUser is '' / NULL and if so its a sign of attempted exploit" 90 | 91 | $suspect = $readfile | Select-String -Pattern "ServerInfo" 92 | 93 | #yoinked this from microsoft (thanks MS luv mRr3b00t) 94 | 95 | $fileResults = @(Import-Csv -Path $file.FullName -ErrorAction SilentlyContinue | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox, HttpStatus) 96 | ForEach($item in $fileResults){ 97 | write-host "THANKS MICROSOFT ##" -ForegroundColor Gray 98 | write-host "Suspicious item detected in : $file.FullName" -foregroundcolor red 99 | write-host $item -ForegroundColor White 100 | read-host -Prompt "press enter to continue" 101 | } 102 | 103 | 104 | 105 | } 106 | 107 | } 108 | 109 | 110 | ###################################### 111 | #STOP CHECKING HTTP PROXY LOGS 112 | ###################################### 113 | 114 | 115 | ###################################### 116 | # CHECK OAB LOGS 117 | ###################################### 118 | ########REMOTE CODE EXECUTION ################## 119 | # THE RCE IS IN THE Set-OabVirtualDirectory.ExternalUrl cmdlet 120 | ############# IF YOU HAVE HAD RCE THIS WILL HAVE BEEN ABUSED ############### 121 | 122 | write-host "########################################################" 123 | Write-host "Checking OABGenerator logs" -ForegroundColor Cyan 124 | 125 | $frontendpath = $exchangepath + "FrontEnd\HttpProxy\owa\auth\" 126 | $frontendpath 127 | 128 | read-host "Press ENTER to Continue" 129 | 130 | Write-host "Check for odd aspx files and odd timestamps in $frontendpath" -ForegroundColor Cyan 131 | 132 | Get-ChildItem -Path $frontendpath -Recurse -Filter "*.aspx*" 133 | 134 | ###################################### 135 | # STOP CHECKING OAB LOGS 136 | ###################################### 137 | 138 | 139 | ###################################################### 140 | # CHECK IIS LOGS FOR KNOWN BAD IPS 141 | #Check for known bad IPS - this is already in the repo in a ipcheck.ps1 script but i've moved it here as well 142 | ###################################################### 143 | 144 | Write-host "Checking IIS logs for known bad IPs associated with Hafnium" -ForegroundColor Cyan 145 | read-host "Press ENTER to Continue" 146 | 147 | #this list is taken from veloxity and privately reported Ips - you need to check what they traffic is doing not just assume 148 | $badips = "103.77.192.219","104.140.114.110","104.250.191.110","108.61.246.56","149.28.14.163","157.230.221.198","167.99.168.251","185.250.151.72","192.81.208.169","203.160.69.66","211.56.98.146","5.254.43.18","80.92.205.81","165.232.154.116","104.248.49.97","5.2.69.13","91.192.103.43","161.35.45.41","45.77.252.175","1.36.203.86","1.65.152.106","103.212.223.210","104.225.219.16","108.172.93.199","110.36.235.230","110.36.238.2","110.39.189.202","112.168.90.84","114.205.37.150","116.49.101.143","117.146.53.162","119.197.26.38","119.231.129.222","121.154.50.51","121.174.31.220","121.176.145.25","122.213.178.102","123.16.231.247","124.5.24.161","139.59.56.239","161.35.76.1","167.179.67.3","170.10.228.74","172.105.87.139","179.1.65.54","182.165.53.4","185.171.166.188","185.224.83.137","200.52.177.138","201.17.196.211","201.208.18.226","202.182.118.99","209.58.163.131","211.177.182.80","213.219.235.158","218.39.251.104","219.100.37.239","219.100.37.243","219.78.205.63","23.95.80.191","31.182.197.163","31.28.31.132","34.87.189.145","39.123.17.120","46.101.232.43","46.23.196.21","49.36.47.211","58.126.135.235","58.190.46.175","61.82.150.49","78.188.104.84","78.189.225.136","86.105.18.116","89.147.119.227","90.230.190.92" 149 | 150 | 151 | 152 | #find IIS logs path 153 | 154 | foreach($WebSite in $(get-website)) 155 | { 156 | $logFilePaths="$($Website.logFile.directory)\w3svc$($website.id)".replace("%SystemDrive%",$env:SystemDrive) 157 | Write-host "$($WebSite.name) [$logFilePaths]" 158 | $WebSite.physicalPath 159 | #$logFilePaths 160 | 161 | 162 | #check for aspx files 163 | 164 | 165 | #look for odd aspx files 166 | # REMMED OUT AS WE DO THIS AGAIN LATER 167 | #Get-ChildItem -Path $WebSite.physicalPath -Recurse -Filter "*.aspx" 168 | 169 | 170 | 171 | $files = Get-ChildItem -Recurse "$logFilePaths\*.log" 172 | 173 | foreach($file in $files) 174 | { 175 | #read the file contents into memory 176 | write-host "Reading files" 177 | write-host $file.Name 178 | write-host $file.FullName 179 | $readfile = Get-Content -Path $file 180 | 181 | 182 | foreach($badIP in $badips){ 183 | write-host "Hunting for string $BadIP" -ForegroundColor Cyan 184 | 185 | $found = $readfile -cmatch $badIP 186 | 187 | if($found) 188 | { 189 | write-host $found -ForegroundColor Red 190 | write-host "########WARNING##############" -ForegroundColor Red 191 | write-host "whilst hunting for $BadIp in $file we found a match." -ForegroundColor Gray 192 | 193 | if($readfile | Select-String -Pattern $badIP -SimpleMatch){Read-Host -Prompt "YOu might want to investigate this event! Press enter to continue..."} 194 | 195 | Read-Host -Prompt "Review this - it's a bit buggy! Press enter to continue..." 196 | } 197 | 198 | } 199 | 200 | } 201 | 202 | 203 | } 204 | 205 | 206 | ###################################################### 207 | # STOP CHECKING IIS LOGS FOR KNOWN BAD IPS 208 | ####################################################### 209 | 210 | 211 | 212 | Write-host "Check for odd aspx files and odd timestamps in web content sites " -ForegroundColor Cyan 213 | write-host "################### WARNING THIS GENERATES QUITE A BIT OF CONTENT TO REVIEW but reviewing it is a good idea ###################" 214 | 215 | Read-Host "Press enter to continue" 216 | 217 | #look for odd aspx files 218 | # look for odd aspx files (deafult names are "errorFE.aspx", "ExpiredPassword.aspx","frowny.aspex","logoff.aspx","logon.aspx","OutlookCN.aspx"."RedirSuiteServiceProxy.aspx",signout.aspx" 219 | 220 | #this spits out alot of data - the timestamps should be OLD (they are at least in RTM version - 2018) 221 | #get rid of this hard coded path 222 | 223 | foreach($WebSite in $(get-website)) 224 | { 225 | $logFilePaths="$($Website.logFile.directory)\w3svc$($website.id)".replace("%SystemDrive%",$env:SystemDrive) 226 | Write-host "$($WebSite.name) [$logFilePaths]" 227 | $WebSite.physicalPath 228 | 229 | #replace %SystemDrive% with actual path 230 | if( $WebSite.physicalPath -like '*%SystemDrive%*'){ 231 | 232 | 233 | $osdrive = (Get-WmiObject Win32_OperatingSystem).SystemDrive 234 | 235 | $newpath = $WebSite.physicalPath -replace "%SystemDrive%", "$osdrive" 236 | (Get-WmiObject Win32_OperatingSystem).SystemDrive 237 | write-host "environment var detected" -ForegroundColor DarkRed 238 | write-host $newpath 239 | } 240 | else 241 | { 242 | 243 | $newpath = $WebSite.physicalPath 244 | 245 | } 246 | 247 | Get-ChildItem $newpath -Recurse -filter "*.aspx" 248 | 249 | 250 | 251 | $badhash = "b75f163ca9b9240bf4b37ad92bc7556b40a17e27c2b8ed5c8991385fe07d17d0","097549cf7d0f76f0d99edf8b2d91c60977fd6a96e4b8c3c94b0b1733dc026d3e","2b6f1ebb2208e93ade4a6424555d6a8341fd6d9f60c25e44afe11008f5c1aad1","65149e036fff06026d80ac9ad4d156332822dc93142cf1a122b1841ec8de34b5","511df0e2df9bfa5521b588cc4bb5f8c5a321801b803394ebc493db1ef3c78fa1","4edc7770464a14f54d17f36dc9d0fe854f68b346b27b35a6f5839adf1f13f8ea","811157f9c7003ba8d17b45eb3cf09bef2cecd2701cedb675274949296a6a183d","1631a90eb5395c4e19c7dbcbf611bbe6444ff312eb7937e286e4637cb9e72944" 252 | Write-host "Checking inetpub\wwwroot\aspnet_client for extra files" 253 | $enumfiles = Get-ChildItem -Path $newpath -filter "*.aspx" -Recurse -File 254 | foreach($file in $enumfiles){ 255 | write-host $file.DirectoryName 256 | write-host $file.FullName 257 | write-host $file.Name 258 | $filehash = Get-FileHash -Path $file.FullName -Algorithm SHA256 259 | 260 | write-host $filehash.Hash -ForegroundColor Gray 261 | 262 | if($badhash.Contains($filehash.Hash)){write-host "BAD HASH DETECTED ASSUME BREACH" -ForegroundColor Red} 263 | else 264 | { 265 | #do nothing as it's very noisy 266 | } 267 | 268 | } 269 | 270 | 271 | 272 | } 273 | 274 | 275 | ###################################################### 276 | # HARD CODED CHECKS FOR SPECIFIC IOCS 277 | ###################################################### 278 | 279 | ####CHECK THE ISS LOGS for POST Requests to /owa/auth/Current/themes/resources 280 | 281 | #read all the IIS logs looking for POST requests to /owa/auth/Current/themes/resources/ 282 | Write-host "Checking for theme resource indicators" 283 | 284 | #FIX THIS HARD CODED PATH 285 | $parse1 = Select-String -Path "C:\inetpub\logs\LogFiles\W3SVC1\*.log" -Pattern 'POST /owa/auth/Current/themes/resources/' 286 | 287 | foreach($line in $parse1){ 288 | 289 | write-host "Might want to investigate this" -ForegroundColor DarkRed 290 | write-host $line -ForegroundColor DarkYellow 291 | 292 | 293 | } 294 | 295 | #CHECK OAB LOGS 296 | 297 | $oabpath = $exchangepath + "Logging\OABGeneratorLog\*.log" 298 | $oabpath 299 | Write-host "Checking OABGenerator logs" -ForegroundColor Cyan 300 | 301 | #findstr /snip /c:"192.81.208.169" C:\inetpub\logs\LogFiles\W3SVC1\*.log 302 | findstr /snip /c:"Download failed and temporary file" $oabpath 303 | 304 | 305 | #this should be blank 306 | Write-host "Checking for Set-VirtualDirectory indicators" 307 | $ecppath = $exchangepath + "Logging\ECP\Server\*.log" 308 | $ecppath 309 | 310 | 311 | ##################THIS IS THE RCE ################################### 312 | Select-String -Path $ecppath -Pattern 'Set-.+VirtualDirectory' 313 | 314 | ###################################################### 315 | # END OF HARD CODED CHECKS FOR SPECIFIC IOCS 316 | ###################################################### 317 | 318 | 319 | 320 | ###################################################### 321 | # END OF SCRIPT MESSAGE 322 | ###################################################### 323 | 324 | write-host "if anytihng is found then investigate - this is not a fully developed script - use at own risk. check the MS docs." -ForegroundColor Red 325 | write-host "###########################################################" -ForegroundColor Red 326 | 327 | write-host "IOC Hunting development script made by mRr3b00t. Fight the bad pews, save the world! Hax4Good" -ForegroundColor Red 328 | -------------------------------------------------------------------------------- /find_bad_pews_iis.ps1: -------------------------------------------------------------------------------- 1 | findstr /S /snip /c:"/x.js" C:\inetpub\logs\LogFiles\*.log > hunt.txt 2 | findstr /S /snip /c:"/y.js" C:\inetpub\logs\LogFiles\*.log >> hunt.txt 3 | 4 | $regex=‘(?
((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))’ 5 | 6 | $Matched = select-string -Path hunt.txt -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value } 7 | 8 | 9 | 10 | $uniques = $Matched |Select-Object -Unique |Sort-Object 11 | 12 | $uniquesS 13 | -------------------------------------------------------------------------------- /healthcheck.ps1: -------------------------------------------------------------------------------- 1 | #Runs the microsoft exchange health check script 2 | #just speeds this process up 3 | 4 | #Requires -RunAsAdministrator 5 | Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn 6 | 7 | $TLS12Protocol = [System.Net.SecurityProtocolType] 'Tls12' 8 | [System.Net.ServicePointManager]::SecurityProtocol = $TLS12Protocol 9 | 10 | wget https://github.com/dpaulson45/HealthChecker/releases/download/v3.3.2/HealthChecker.ps1 -OutFile HealthChecker.ps1 11 | 12 | .\HealthChecker.ps1 13 | .\HealthChecker.ps1 -BuildHtmlServersReport 14 | -------------------------------------------------------------------------------- /ipcheck.ps1: -------------------------------------------------------------------------------- 1 | #Hunt for bad ips in IIS logs 2 | # mRr3b00t 3 | # crappy detection script made in a rush 03/03/2021 4 | # version 0.1 5 | 6 | 7 | #Requires -RunAsAdministrator 8 | 9 | 10 | 11 | 12 | $badips = "103.77.192.219","104.140.114.110","104.250.191.110","108.61.246.56","149.28.14.163","157.230.221.198","167.99.168.251","185.250.151.72","192.81.208.169","203.160.69.66","211.56.98.146","5.254.43.18","80.92.205.81","165.232.154.116","104.248.49.97","5.2.69.13","91.192.103.43","161.35.45.41","45.77.252.175" 13 | 14 | $files = Get-ChildItem -Recurse "C:\inetpub\logs\LogFiles\*.log" 15 | 16 | foreach($file in $files) 17 | { 18 | #read the file contents into memory 19 | write-host "Reading files" 20 | write-host $file.Name 21 | $readfile = Get-Content -Path $file 22 | 23 | 24 | foreach($badIP in $badips){ 25 | write-host "Hunting for string $BadIP" -ForegroundColor Cyan 26 | 27 | $found = $readfile -match $badIP 28 | if($found){write-host $found -ForegroundColor Red 29 | 30 | Read-Host -Prompt "YOu might want to investigate this event! Press enter to continue..." 31 | } 32 | 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /ips.txt: -------------------------------------------------------------------------------- 1 | 165.232.154[.]116 2 | 157.230.221[.]198 3 | 104.248.49[.]97 4 | 103.77.192[.]219 5 | 104.140.114[.]110 6 | 104.250.191[.]110 7 | 108.61.246[.]56 8 | 149.28.14[.]163 9 | 167.99.168[.]251 10 | 185.250.151[.]72 11 | 192.81.208[.]169 12 | 203.160.69[.]66 13 | 211.56.98[.]146 14 | 5.254.43[.]18 15 | 5.2.69[.]14 16 | 80.92.205[.]81 17 | 91.192.103[.]43 18 | 161.35.45[.]41 19 | 45.77.252[.]175 20 | -------------------------------------------------------------------------------- /patch2016cu18.ps1: -------------------------------------------------------------------------------- 1 | #quick and dirty download hotfix and install msp file for exchange 2016 cu 18 2 | 3 | $TLS12Protocol = [System.Net.SecurityProtocolType] 'Tls12' 4 | [System.Net.ServicePointManager]::SecurityProtocol = $TLS12Protocol 5 | 6 | wget -Uri https://download.microsoft.com/download/0/e/4/0e4056bd-0d6d-4738-a43b-bf9e23b14298/Exchange2016-KB5000871-x64-en.msp -OutFile Exchange2016-KB5000871-x64-en.msp 7 | 8 | msiexec /p Exchange2016-KB5000871-x64-en.msp /qb! 9 | --------------------------------------------------------------------------------