Skip to main content

Command Palette

Search for a command to run...

Hack The Box: Appointment

Updated
10 min read
N
I write about cyber security content revolving around what I learn in reverse engineering and low-level programming, web security, cloud and network security, ethical hacking and generally anything else interesting I get to learn!

Appointment is a box that is mostly web-application oriented. More specifically, we will find out how to perform an SQL Injection against an SQL Database enabled web application. Our target is running a website with search capabilities against a back-end database containing searchable items vulnerable to this type of attack. Not all items in this database should be seen by any user, so different privileges on the website will grant you different search results.

SQL Injection is a common way of exploiting web pages that use SQL Statements that retrieve and store user input data. If configured incorrectly, one can use this attack to exploit the well-known SQL Injection vulnerability, which is very dangerous. There are many different techniques of protecting from SQL injections, some of them being input validation, parameterized queries, stored procedures, and implementing a WAF (Web Application Firewall) on the perimeter of the server's network. However, instances can be found where none of these fixes are in place, hence why this type of attack is prevalent, according to the OWASP Top 10 list of web vulnerabilities.

Enumeration

First, I performed an nmap scan to find the open and available ports and their services. If no alternative flag is specified in the command syntax, nmap will scan the most common 1000 TCP ports for active services. This will suit us in our case.

Additionally, we will need super-user privileges to run the command below with the -sC or -sV flags. This is because script scanning ( -sC ) and version detection ( -sV ) are considered more intrusive methods of scanning the target. This results in a higher probability of being caught by a perimeter security device on the target's network.

The only open port we detect is port 80 TCP, which is running the Apache httpd server version 2.4.38. We can also see that a login title is shows indicating a login page is available on the server. Apache HTTP Server is a free and open-source application that runs web pages on either physical or virtual web servers. It is one of the most popular HTTP servers, and it usually runs on standard HTTP ports such as ports 80 TCP, 443 TCP, and alternatively on HTTP ports such as 8080 TCP or 8000 TCP. HTTP stands for Hypertext Transfer Protocol, and it is an application-layer protocol used for transmitting hypermedia documents, such as HTML (Hypertext Markup Language).

Searching for the service version on popular vulnerability databases online to see if any vulnerability exists for the specified version. However, in our case, this version does not contain any known vulnerability that we could potentially exploit. Thus, I navigated directly to the IP address of the target from our browser.

Since we are not aware of any specific credentials that we could use to log-in, I checked if there are any other directories or pages useful for us in the enumeration process using Gobuster to brute-force the directories and files provided in the wordlist of our choice. The wordlists can be found in /usr/share/wordlists . I decided to use /usr/share/dirb/wordlists/common.txt . The flags we will be using with this command are as follows:

dir : Specify that we wish to do web directory enumeration.
--url or -u : Specify the web address of the target machine that runs the HTTP server.
--wordlist or -w : Specify the wordlist that we want to use.

I wasnt able to find any useful info other than seeing that the login page is a php file.

Hence, I decided to check for default credentials. I typed the most common combinations in the username and password fields, such as:

admin:admin
guest:guest
user:user
root:root
administrator:password

After attempting all of those combinations, I still failed to log in. I could, hypothetically, use a tool to attempt brute-forcing the log-in page. However, that would take much time and might trigger a security measure. The next sensible tactic would be to test the log-in form for a possible SQL Injection vulnerability.

Here is an example of how authentication works using PHP & SQL:

<?php
mysql_connect("localhost", "db_username", "db_password"); # Connection to the SQL
Database.
mysql_select_db("users"); # Database table where user information is stored.
\(username=\)_POST['username']; # User-specified username.
\(password=\)_POST['password']; #User-specified password.
\(sql="SELECT * FROM users WHERE username='\)username' AND password='$password'";
# Query for user/pass retrieval from the DB.
\(result=mysql_query(\)sql);
# Performs query stored in \(sql and stores it in \)result.
\(count=mysql_num_rows(\)result);
# Sets the \(count variable to the number of rows stored in \)result.
if ($count==1){
    # Checks if there's at least 1 result, and if yes:
    \(_SESSION['username'] = \)username; # Creates a session with the         specified $username.
    \(_SESSION['password'] = \)password; # Creates a session with the specified $password.
    header("location:home.php"); # Redirect to homepage.
}
else { # If there's no singular result of a user/pass combination:
    header("location:login.php");
     # No redirection, as the login failed in the case the $count variable is not equal to 1, HTTP Response code 200 OK.
}
?>

In PHP, # is used to comment. This code above is vulnerable to SQL Injection attacks, where you can modify the query (the $sql variable) through the log-in form on the web page to make the query do something that is not supposed to do - bypass the log-in altogether!

We can specify the username and password through the log-in form on the web page. However, it will be directly embedded in the $sql variable that performs the SQL query without input validation. Notice that no regular expressions or functions forbid us from inserting special characters such as a single quote or hashtag. This is a dangerous practice because those special characters can be used for modifying the queries. The pair of single quotes are used to specify the exact data that needs to be retrieved from the SQL Database, while the hashtag symbol is used to make comments. Therefore, we could manipulate the query command by inputting the following:

Username: admin'#

This makes the query look like: `

\(sql="SELECT * FROM users WHERE username='admin'#' AND password='\)password'";

The hashtag comments out the rest of the query, which will make searching for a matching password for the specified username obsolete. If we look further down in the PHP code above, we will see that the code will only approve the log-in once there is precisely one result of our username and password combination. However, since we have skipped the password search part of our query, the script will now only search if any entry exists with the username admin .

In this case, we got lucky. There is indeed an account called admin , which will validate our SQL Injection and return the 1 value for the $count variable, which will be put through the if statement , allowing us to log-in without knowing the password. If there was no admin account, we could try any other accounts until we found one that existed. ( administrator , root , etc.) Any valid, existing username would make our SQL Injection work. In this case, because the password-search part of the query has been commented out/ skipped, we can throw anything we want at the password field, and it will not matter.

Similarly, one can also use ' OR 1=1 # or admin'-- instead of admin'# .

Mitigations

To combat SQL injection, one can employ the following:

1. Parameterized Queries (Prepared Statements) — Primary Mitigation

The most effective defense against SQL Injection is using parameterized queries, where user input is treated strictly as data rather than executable SQL code.

Vulnerable code

\(sql="SELECT * FROM users WHERE username='\)username' AND password='$password'";

Secure version (PDO example)

\(stmt = \)pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
\(stmt->execute([\)username, $password]);

Why this works

  • SQL query structure is compiled first.

  • User input cannot modify the query logic.

Prepared statements are recommended by organizations like OWASP as the primary protection against SQL injection.


2. Input Validation and Sanitization

Applications should validate and restrict user input before it reaches the database.

Examples:

  • Only allow expected characters

  • Limit input length

  • Reject special characters when unnecessary

Example:

\(username = preg_replace("/[^a-zA-Z0-9]/", "", \)_POST['username']);

Types of validation:

Validation Type Example
Length check max 50 characters
Character whitelist letters and numbers only
Format validation email regex

Input validation should not be the only protection, but an additional layer.


3. Stored Procedures

Stored procedures can limit injection risks if implemented correctly.

Example:

CREATE PROCEDURE GetUser(IN uname VARCHAR(50), IN pass VARCHAR(50))
BEGIN
SELECT * FROM users WHERE username = uname AND password = pass;
END;

Application calls the procedure instead of constructing dynamic SQL.

However:

  • Poorly written stored procedures can still be vulnerable.

4. Use an ORM (Object Relational Mapping)

Frameworks that use ORMs automatically handle parameterized queries.

Examples:

  • Hibernate

  • Django ORM

  • Laravel Eloquent

ORMs reduce the risk of developers writing unsafe SQL queries.


5. Principle of Least Privilege

Database accounts used by the web application should have minimal permissions.

Example restrictions:

  • No DROP TABLE

  • No ALTER TABLE

  • Read-only access when possible

Example:

GRANT SELECT, INSERT ON users TO 'webapp_user';

This limits the damage even if an injection occurs.


6. Web Application Firewall (WAF)

A Web Application Firewall can detect and block suspicious requests.

Common WAFs:

  • ModSecurity

  • Cloudflare WAF

  • AWS WAF

Typical protections include:

  • Blocking SQL keywords (UNION, SELECT, OR 1=1)

  • Rate limiting suspicious requests

  • Filtering malicious payloads

Note: WAFs should be a secondary control, not the primary defense.

Conclusion

This assessment demonstrated how a seemingly simple login form can become a critical security vulnerability when proper input handling is not implemented. By exploiting an SQL Injection flaw in the authentication query, it was possible to manipulate the backend database logic and bypass the login mechanism without knowing valid credentials. This highlights how dynamically constructed SQL queries that directly incorporate user input can expose sensitive functionality and data.

The exercise reinforces the importance of secure coding practices in web application development. Implementing defensive measures such as parameterized queries, strict input validation, and proper database privilege management significantly reduces the risk of injection attacks. Additionally, security controls like Web Application Firewalls and regular vulnerability assessments further strengthen an application's resilience.

SQL Injection remains one of the most prevalent web vulnerabilities identified by organizations such as OWASP, demonstrating that even well-known issues continue to appear in real-world systems when security best practices are overlooked. Ultimately, this lab illustrates that proactive security design and rigorous testing are essential to protecting web applications and the sensitive data they manage.