There is a list of (probably corporate) emails that we can quickly extract by looking at the page source:
organicfish718@fire.windcorp.thm,Antonietta Vidal
organicwolf509@fire.windcorp.thm,Britney Palmer
tinywolf424@fire.windcorp.thm,Brittany Cruz
angrybird253@fire.windcorp.thm,Carla Meyer
buse@fire.windcorp.thm,Buse Candan
Edeltraut@fire.windcorp.thm,Edeltraut Daub
Edward@fire.windcorp.thm,Edward Lewis
Emile@fire.windcorp.thm,Emile Lavoie
tinygoose102@fire.windcorp.thm,Emile Henry
brownostrich284@fire.windcorp.thm,Emily Anderson
sadswan869@fire.windcorp.thm,Hemmo Boschma
whiteleopard529@fire.windcorp.thm,Isra Saur
happymeercat399@fire.windcorp.thm,Jackson Vasquez
orangegorilla428@fire.windcorp.thm,Jaqueline Dittmer
As you can see, the icons next to each user are not loading correctly. Looking at the corresponding HTML we notice that a subdomain (fire.windcorp.thm) is used to display the status of users via XMPP protocol. We then add the following entries to the /etc/hosts file:
There is also this section on the website that report some comments of employees about corp:
Looking at the HTML source code for this section we notice that we can infer the naming convention used for Active Directory users, and in addition we also have the name of employee Lily Levesque's dog: Sparky!
fire.windcorp.thm/reset.asp
Exploitation (Lily Levesque)
Now we can try to reset the password of this user:
Great, we have an internal user account and can continue our enumeration!
Enumeration (phase 2)
Port 445
Detect version and confirm domain name using Metasploit:
Using the stealed credentials we can try to enumerate some share with smbmap:
We see that there are also some installers of Spark (an IM client) for different platforms. Let's download and try to install the client. Then login using Lily Levesque credentials.
In order to avoid some errors such as checking the hostname in the certificate, by selecting Advanced we can bypass some security checks
By going to the web page we can find the list of IT users currently online:
After Googling “Spark Instant Messenger exploit” you’ll eventually come across CVE-2020-12772
An issue was discovered in Ignite Realtime Spark 2.8.3 (and the ROAR plugin for it) on Windows. A chat message can include an IMG element with a SRC attribute referencing an external host's IP address. Upon access to this external host, the (NT)LM hashes of the user are sent with the HTTP request. This allows an attacker to collect these hashes, crack them, and potentially compromise the computer. (ROAR can be configured for automatic access. Also, access can occur if the user clicks.)
If we try to send a simple message like “hello” we get no response, but trying to exploit the vulnerability found and sending the payload so formatted we get a response on the Python server listening on our machine. This means that the URL is resolved by the Spark client of the buse user:
Privilege Escalation (Buse Candan)
So now try to steal the NTLM hash using Responder:
With these credentials we can try to access the previous inaccessible share Users and get the second Flag:
Enumeration (phase 3)
Using buse credentials we can run Bloodhound to find some Privilege Escalation path:
Note how the buse user belongs to the Account Operators group.
Account Operators can modify user objects (in particular for our interest the PASSWORD!) for any user that is not a member of one of the protected groups (Administrators, Server Operators, Account Operators, Backup Operators, or Print Operators groups).
RDP is allowed using the rdp_check.py script but then this error message is shown:
Try to access the Domain Controller using evil-winrm:
If we explore the file system a bit, we will find the classic folder inetpub containing also check.asp file with reset password code previously exploited:
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Windcorp.</title>
<!-- Bootstrap core CSS -->
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom fonts for this template -->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet">
<link href="vendor/simple-line-icons/css/simple-line-icons.css" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic" rel="stylesheet" type="text/css">
<!-- Custom styles for this template -->
<link href="css/landing-page.min.css" rel="stylesheet">
</head>
<body>
<div class="jumbotron" style="height:100vh;">
<%
Dim name, age
username = Request.Form("username")
secret = Request.Form("secret")
question = Request.Form("question")
if username = "lilyle" AND secret = "Sparky" AND question = 3 then
Response.Write("<h4 class='display-3'>Your password has been reset to: <b>ChangeMe#1234</b><br></h4>")
Response.Write("Remember to change it after logging in!")
dim fs,f
set fs=Server.CreateObject("Scripting.FileSystemObject")
set f=fs.CreateTextFile("C:\inetpub\wwwroot\32d9027af1d9c4e85e3eb65954af2cc375a25313\1",true)
f.write("1")
f.close
set f=nothing
set fs=nothing
else
Response.write "<h1 class='display-4'>Wrong username and/or secret!</h1>"
end if
%>
</div>
</body>
</html>
and there is a folder C:\Scripts with an interesting powershell in it:
# reset the lists of hosts prior to looping
$OutageHosts = $Null
# specify the time you want email notifications resent for hosts that are down
$EmailTimeOut = 30
# specify the time you want to cycle through your host lists.
$SleepTimeOut = 45
# specify the maximum hosts that can be down before the script is aborted
$MaxOutageCount = 10
# specify who gets notified
$notificationto = "brittanycr@windcorp.thm"
# specify where the notifications come from
$notificationfrom = "admin@windcorp.thm"
# specify the SMTP server
$smtpserver = "relay.windcorp.thm"
# start looping here
Do{
$available = $Null
$notavailable = $Null
Write-Host (Get-Date)
# Read the File with the Hosts every cycle, this way to can add/remove hosts
# from the list without touching the script/scheduled task,
# also hash/comment (#) out any hosts that are going for maintenance or are down.
get-content C:\Users\brittanycr\hosts.txt | Where-Object {!($_ -match "#")} |
ForEach-Object {
$p = "Test-Connection -ComputerName $_ -Count 1 -ea silentlycontinue"
Invoke-Expression $p
if($p)
{
# if the Host is available then just write it to the screen
write-host "Available host ---> "$_ -BackgroundColor Green -ForegroundColor White
[Array]$available += $_
}
else
{
# If the host is unavailable, give a warning to screen
write-host "Unavailable host ------------> "$_ -BackgroundColor Magenta -ForegroundColor White
$p = Test-Connection -ComputerName $_ -Count 1 -ea silentlycontinue
if(!($p))
{
# If the host is still unavailable for 4 full pings, write error and send email
write-host "Unavailable host ------------> "$_ -BackgroundColor Red -ForegroundColor White
[Array]$notavailable += $_
if ($OutageHosts -ne $Null)
{
if (!$OutageHosts.ContainsKey($_))
{
# First time down add to the list and send email
Write-Host "$_ Is not in the OutageHosts list, first time down"
$OutageHosts.Add($_,(get-date))
$Now = Get-date
$Body = "$_ has not responded for 5 pings at $Now"
Send-MailMessage -Body "$body" -to $notificationto -from $notificationfrom `
-Subject "Host $_ is down" -SmtpServer $smtpserver
}
else
{
# If the host is in the list do nothing for 1 hour and then remove from the list.
Write-Host "$_ Is in the OutageHosts list"
if (((Get-Date) - $OutageHosts.Item($_)).TotalMinutes -gt $EmailTimeOut)
{$OutageHosts.Remove($_)}
}
}
else
{
# First time down create the list and send email
Write-Host "Adding $_ to OutageHosts."
$OutageHosts = @{$_=(get-date)}
$Body = "$_ has not responded for 5 pings at $Now"
Send-MailMessage -Body "$body" -to $notificationto -from $notificationfrom `
-Subject "Host $_ is down" -SmtpServer $smtpserver
}
}
}
}
# Report to screen the details
$log = "Last run: $(Get-Date)"
write-host $log
Set-Content -Path C:\scripts\log.txt -Value $log
Write-Host "Available count:"$available.count
Write-Host "Not available count:"$notavailable.count
Write-Host "Not available hosts:"
$OutageHosts
Write-Host ""
Write-Host "Sleeping $SleepTimeOut seconds"
sleep $SleepTimeOut
if ($OutageHosts.Count -gt $MaxOutageCount)
{
# If there are more than a certain number of host down in an hour abort the script.
$Exit = $True
$body = $OutageHosts | Out-String
Send-MailMessage -Body "$body" -to $notificationto -from $notificationfrom `
-Subject "More than $MaxOutageCount Hosts down, monitoring aborted" -SmtpServer $smtpServer
}
}
while ($Exit -ne $True)
reading this comment:
# Read the File with the Hosts every cycle, this way to can add/remove hosts
# from the list without touching the script/scheduled task,
There would appear to be a scheduled task that runs this script but unfortunately we cannot list scheduled tasks:
The code is interesting because right in the first few lines it can be exploited because of the presence of the Invoke-Expression:
If we could control the variable $p, we could perform a command injection and get a shell with the privileges of the person who is executing the task.
The variable $p is populated using the powershell built-in variable $_, which in turn is populated with the contents of the internal hosts.txt file. Assuming that this file contains lines with the IP addresses of the machines to be verified and lines containing a # character to add comments, lines containing a # are excluded with the Where-Object. Below is an example of what the hosts.txt file may look like and what the script commands do:
Privilege Escalation (Domain Admin/Administrator)
So now let's change the domain password of user brittanycr and modify the hosts.txt file in order to get a reverse shell impersonating service principal running the scheduled task.