基本概念

关于查询的基本概念

SELECT 后面是字段

  • 在 SQL 中,SELECT 语句后面跟的是字段(列名)。SELECT 语句的作用是从表中选取指定的列的数据。例如:
1
SELECT column1, column2 FROM table_name;

​ 这里 column1column2 就是表 table_name 中的字段,该语句会从 table_name 表中选取 column1column2 这两列的数 据。最终呈现的结果是一个二维数据集,每一行代表一条记录,每一列对应一个字段。

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) 是一个表达式,它会先将 column1column2 的值用 - 连接起来,然后 GROUP_CONCAT() 再把这些连接后的结果连接成一个大字符串。

table_name 是字段

  • 在你给出的注入语句 -1' union select 1,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user'--+ 中,table_nameinformation_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选取的元素的类型和数量就需要相同。

  • 适用环境:

    image-20250417135005040

如该题,不可以使用一般的-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_userctfshow_user2,说明所属于该数据库的表有ctfshow_userctfshow_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