{"id":4367,"date":"2022-11-13T19:08:42","date_gmt":"2022-11-14T03:08:42","guid":{"rendered":"https:\/\/tungle.ca\/?p=4367"},"modified":"2023-03-01T18:39:12","modified_gmt":"2023-03-02T02:39:12","slug":"count-the-number-of-failed-root-logins-by-ip-address-via-powershell","status":"publish","type":"post","link":"https:\/\/tungle.ca\/?p=4367","title":{"rendered":"Count the number of failed root login in Linux server by IP address via PowerShell"},"content":{"rendered":"\n<p>Using (e)grep, cut, awk, sed to extract specific information in Linux logs is one of the daily tasks of Linux system administrator. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">grep \"Failed\" '\/var\/log\/auth.log' | grep -v root | awk -F 'from ' '{ print $2} ' | awk '{print $1}' | sort | uniq -c | sort -nr | while read COUNT IP<\/code><\/pre>\n\n\n\n<p>However, in this article, I want to demonstrate how to use PowerShell to extract the number of failed root login in Linux server.<\/p>\n\n\n\n<p>Download the \/var\/log\/auth.log example file via github (https:\/\/github.com\/elastic\/examples\/blob\/master\/Machine%20Learning\/Security%20Analytics%20Recipes\/suspicious_login_activity\/data\/auth.log)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"983\" height=\"129\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-7.png\" alt=\"\" class=\"wp-image-4368\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-7.png 983w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-7-300x39.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-7-768x101.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-7-200x26.png 200w\" sizes=\"auto, (max-width: 983px) 100vw, 983px\" \/><\/figure>\n\n\n\n<p>Save it under Downloads directory. Querying the content of the file via Get-content command.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$inputpath = get-content \"\/Users\/tungle\/Downloads\/auth.log\"<\/code><\/pre>\n\n\n\n<p>Now, I want to explain how to use PowerShell to extract specific information in the log file. If the number of failed attempts is greater than the LIMIT, then it will display count number, IP address, and Geolocation of the IP address.<\/p>\n\n\n\n<p>Firstly, we need to know a format of the IP address via PowerShell regex.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$regex = \"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b\"<\/code><\/pre>\n\n\n\n<p>Filtering all lines are matched the regex format of the IP address in auth.log file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$output = $inputpath | Select-String -Pattern $regex -AllMatches<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"104\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-8-1024x104.png\" alt=\"\" class=\"wp-image-4369\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-8-1024x104.png 1024w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-8-300x30.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-8-768x78.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-8-1536x156.png 1536w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-8-200x20.png 200w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-8.png 1656w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Selecting all lines are matched &#8220;failed password for root&#8221;.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$output = $inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" <\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"131\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-9-1024x131.png\" alt=\"\" class=\"wp-image-4370\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-9-1024x131.png 1024w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-9-300x38.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-9-768x98.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-9-1536x197.png 1536w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-9-200x26.png 200w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-9.png 1904w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Following the MS link, I use matches method to populate the returned MatchCollection object (https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.text.regularexpressions.regex.matches?view=netframework-4.7.2). % is an alias of foreach-object.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$output = $inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" | % { $_.Matches }<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-18-1024x182.png\" alt=\"\" class=\"wp-image-4388\" width=\"518\" height=\"92\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-18-1024x182.png 1024w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-18-300x53.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-18-768x137.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-18-200x36.png 200w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-18.png 1212w\" sizes=\"auto, (max-width: 518px) 100vw, 518px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"514\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-11-1024x514.png\" alt=\"\" class=\"wp-image-4372\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-11-1024x514.png 1024w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-11-300x150.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-11-768x385.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-11-200x100.png 200w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-11.png 1356w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-10.png\" alt=\"\" class=\"wp-image-4371\" width=\"336\" height=\"250\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-10.png 774w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-10-300x223.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-10-768x572.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-10-200x149.png 200w\" sizes=\"auto, (max-width: 336px) 100vw, 336px\" \/><\/figure>\n\n\n\n<p>Next, getting IP addresses of the failed login in the log file. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$output = $inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" | % { $_.Matches } | % { $_.Value }<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-12.png\" alt=\"\" class=\"wp-image-4373\" width=\"282\" height=\"165\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-12.png 586w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-12-300x175.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-12-200x117.png 200w\" sizes=\"auto, (max-width: 282px) 100vw, 282px\" \/><\/figure>\n\n\n\n<p>Group the IP address property together.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$output = $inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" | % { $_.Matches } | % { $_.Value } `\n| Group-Object<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"273\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-13-1024x273.png\" alt=\"\" class=\"wp-image-4374\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-13-1024x273.png 1024w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-13-300x80.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-13-768x205.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-13-200x53.png 200w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-13.png 1404w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Check if the number of failed attempts is greater than the LIMIT (&gt;10 failed login attempts).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$output = $inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" | % { $_.Matches } | % { $_.Value } `\n                    | Group-Object |  Select-Object Name, Count | Where-Object { $_.Count -gt 10 }<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-14.png\" alt=\"\" class=\"wp-image-4375\" width=\"403\" height=\"132\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-14.png 708w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-14-300x98.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-14-200x66.png 200w\" sizes=\"auto, (max-width: 403px) 100vw, 403px\" \/><\/figure>\n\n\n\n<p>Using the PS script block below to detect attempted IP address, count, and country. Basically, the script will check all lines in the $output variable above and output the top IP address and county attempts.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">ForEach($line in $output){\n    $IP = $line.Name\n    #$IP\n    # Query Geolocaltion of the IP addresses via free API\n    $result = Invoke-RestMethod -Method Get -Uri http:\/\/ip-api.com\/json\/$IP\n    # Create a PSCustomObject to save Count, IP address and Country attempts \n    $myObject = [PSCustomObject]@{\n                Count = $line.Count\n                \"IP Address\" = $line.Name\n                #IP = $result.query\n                Country = $result.Country\n}\n$myObject\n}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-15.png\" alt=\"\" class=\"wp-image-4376\" width=\"376\" height=\"116\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-15.png 602w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-15-300x93.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-15-200x62.png 200w\" sizes=\"auto, (max-width: 376px) 100vw, 376px\" \/><\/figure>\n\n\n\n<p>Below is a PS script block to check the failed root attempts.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$inputpath = get-content \"\/Users\/tungle\/Downloads\/auth.log\"\n#$regex = \u2018\\b\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}\\b\u2019\n$regex = \"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b\"\n#$inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\"\n#$inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" | % { $_.Matches }\n$output = $inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" | % { $_.Matches } | % { $_.Value } `\n                    | Group-Object |  Select-Object Name, Count | Where-Object { $_.Count -gt 10 }\nForEach($line in $output){\n    $IP = $line.Name\n    #$IP\n    $result = Invoke-RestMethod -Method Get -Uri http:\/\/ip-api.com\/json\/$IP\n    # Create a PSCustomObject to save Count, IP address and Country attempts \n    $myObject = [PSCustomObject]@{\n                Count = $line.Count\n                \"IP Address\" = $line.Name\n                #IP = $result.query\n                Country = $result.Country\n}\n$myObject\n}<\/code><\/pre>\n\n\n\n<p>This is a PS script (show-attacker.PS1) to run in a cloud-based Linux virtual machine.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$inputpath = get-content \"\/var\/log\/auth.log\"\n#$inputpath = get-content \"\/Users\/tungle\/Downloads\/auth.log.txt\"\n$regex = \"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b\"\n$output = $inputpath | Select-String -Pattern $regex -AllMatches | Select-String \"failed password for root\" | % { $_.Matches } | % { $_.Value } `\n| Group-Object |  Select-Object Name, Count | Where-Object {$_.Count -gt 20}\nForEach($line in $output){\n        $IP = $line.Name\n        $result = Invoke-RestMethod -Method Get -Uri http:\/\/ip-api.com\/json\/$IP\n        # Sleep a second \n        Start-Sleep 1\n    \t#Write-Output $_count\n        $myObject = [PSCustomObject]@{\n        \tCount = $line.Count\n\t\t\"IPAddress\" = $line.Name\n            \t#IP = $result.query\n            \tCountry = $result.Country\n}\n    $myObject\n}<\/code><\/pre>\n\n\n\n<p>Run the script in Linux server.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">.\/show-attacker.PS1 | Sort-Object Count -Descending<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-16.png\" alt=\"\" class=\"wp-image-4377\" width=\"579\" height=\"580\" srcset=\"https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-16.png 1008w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-16-300x300.png 300w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-16-150x150.png 150w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-16-768x770.png 768w, https:\/\/tungle.ca\/wp-content\/uploads\/2022\/11\/image-16-200x200.png 200w\" sizes=\"auto, (max-width: 579px) 100vw, 579px\" \/><\/figure>\n\n\n\n<p>Finally, we can extract specific information of authentication logs in Linux server by using PowerShell.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using (e)grep, cut, awk, sed to extract specific information in Linux logs is one of the daily tasks of Linux system administrator. However, in this article, I want to demonstrate how to use PowerShell to extract the number of failed root login in Linux server. Download the \/var\/log\/auth.log example file via github (https:\/\/github.com\/elastic\/examples\/blob\/master\/Machine%20Learning\/Security%20Analytics%20Recipes\/suspicious_login_activity\/data\/auth.log) Save it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,9,7,11],"tags":[8,10,12,13],"class_list":["post-4367","post","type-post","status-publish","format-standard","hentry","category-linux","category-microsoft","category-powershell","category-security","tag-linux","tag-microsoft","tag-powershell","tag-security"],"_links":{"self":[{"href":"https:\/\/tungle.ca\/index.php?rest_route=\/wp\/v2\/posts\/4367","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tungle.ca\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tungle.ca\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tungle.ca\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tungle.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4367"}],"version-history":[{"count":18,"href":"https:\/\/tungle.ca\/index.php?rest_route=\/wp\/v2\/posts\/4367\/revisions"}],"predecessor-version":[{"id":4411,"href":"https:\/\/tungle.ca\/index.php?rest_route=\/wp\/v2\/posts\/4367\/revisions\/4411"}],"wp:attachment":[{"href":"https:\/\/tungle.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4367"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tungle.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4367"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tungle.ca\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4367"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}