Appointment Writeup

Continuing with Starting Point, I moved onto the next tier. Learned a lot doing these boxes. And it caused some self-reflection.

A bad habit that I am trying to correct is my tendency to not completely understand why a specific attack works. Some may call me a script kiddie and I would agree. Relying on tools that automate an attack or copy/pasting a PoC is a major crutch. But what happens when the tool doesn’t work? Or a PoC doesn’t match the exact environment I am in?

That is when an understanding of how an exploit works comes into play. There is no need to recreate the wheel. But it is important to understand what the vulnerability is, how the tool tries to take exploit it, why it may or may not work, and how to correct any errors.

Anyways, here is my writeup for Appointment.


Appointment

Initial Recon

Began with a nmap scan.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Appointment]
└─$ sudo nmap -sC -sV -oA nmap/initial $tgt
[sudo] password for crimson: 
Starting Nmap 7.92 ( https://nmap.org ) at 2022-05-17 19:31 CDT
Nmap scan report for 10.129.82.216
Host is up (0.048s latency).
Not shown: 999 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.38 ((Debian))
|_http-title: Login
|_http-server-header: Apache/2.4.38 (Debian)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.25 seconds

There is a single port open – HTTP on port 80.

Initial Access

HTTP

I navigated to http://$tgt and was greeted with a login page. I then attempted to guess username and passwords, yet none that I tried worked. Clicking on the “Forgot Password?” link did nothing as well.

While I was guessing usernames and passwords I started additional recon in the background, specifically a gobuster scan. Here I specified dir mode, -u to for the remote system’s IP, and -w for the wordlist to use.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Appointment]
└─$ gobuster dir -u $tgt -w /opt/SecLists/Discovery/Web-Content/raft-small-words.txt     
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.129.82.222
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-small-words.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/05/17 20:28:35 Starting gobuster in directory enumeration mode
===============================================================
/.php                 (Status: 403) [Size: 278]
/.html                (Status: 403) [Size: 278]
/images               (Status: 301) [Size: 315] [--> http://10.129.82.222/images/]
/js                   (Status: 301) [Size: 311] [--> http://10.129.82.222/js/]    
/css                  (Status: 301) [Size: 312] [--> http://10.129.82.222/css/]   
/.htm                 (Status: 403) [Size: 278]                                   
/.                    (Status: 200) [Size: 4896]                                  
/fonts                (Status: 301) [Size: 314] [--> http://10.129.82.222/fonts/] 
/.htaccess            (Status: 403) [Size: 278]                                   
Progress: 873 / 43004 (2.03%)                   

Looking at the results did not reveal anything promising.

SQL

Taking a step back, let me explain in very simple terms how a website might authenticate a user. Said user will provide a username and password. There will be a backend database, such as one running Structured Query Language (SQL), that contains valid usernames and passwords. The web application will query said database for the provided credentials. If the credentials are in the database then the user is authenticated. Otherwise, the user is denied access.

Simply stated, a SQL database contains tables. These tables are comprised of rows and columns. For example, let’s look at a table called members. This table has two columns named username and password. Each row contains values.

usernamepassword
user1password
user2p@ssword
user 3qwerty
adminadmin

What would a SQL query look like to see if there is a particular username and password in the table?

SELECT * FROM members WHERE username = 'admin' AND password = 'admin'

The query is going to select everything from the table called members where username is equal to admin and where password is equal to admin. This query will return true since those values are in the database.

A web application could use the above query to validate users by passing user input into the query. It would look something like this where $username and $password contains the user’s input which is then evaluated.

SELECT * FROM members WHERE username = '$username' AND password = '$password'

Now it is critical that user input be propery sanitized otherwise SQL injection could occur. What would a SQL injection look like? Say a user provides “admin` #”” for a username and “kjdfjklsdf” for a password. The SQL query will then be evaluated as follows.

SELECT * FROM members WHERE username = 'admin' #' AND password = 'kjdfjklsdf'

The query will select everything from the members table where the username is equal to admin. Now this is where it gets interesting. The # in SQL is used for comments. With that said, the second half of the SQL statement is commented out and not executed. So the password is not checked! As long as a valid username is found the SQL statement will be true.

Now back to our regularly scheduled hacking of Appointment.

Below are a few common SQL injections to try out.

admin' --
admin' #
admin'/*
' or 1=1--
' or 1=1#
' or 1=1/*
') or '1'='1--
') or ('1'='1--

I started off by firing up Burp and having all HTTP traffic be proxied through it. With Burp running in the background I attempted to login. In Burp I selected the POST request and sent it to Repeater.

From there I went down the line of common SQL injection payloads. Sending “admin’ #” for the username and whatever value for a password worked for the reasons explained previously!