0%

初识SQL注入--小结

注入原理

sql注入是指web应用程序对用户输入数据的合法性没有进行判断或者过滤不严,导致攻击者可以构造恶意语句,获取数据库中的数据,在一定条件下甚至可以拿到shell

前提

mysql5.0以上存在一个自带的数据库名为 information__schema ,是一个存储纪录了所有数据库名、表名、列名的数据库,也相当于可以从这里查询指定数据库下面的表名和列名的信息,这是因为在数据库中”.”表示下一级。例如:books.book 表示 books 数据库下面的book 表名

1
2
3
4
5
6
7
information_schema.schemata:纪录所有数据库的表
information_schema.tables:纪录所有表名的表
information_schema.columns;纪录所有列名的表
相当于变量:
table_name:表名
column_name:列名
table_schema:数据库名

Step 1. 判断

判断是否有注入点

首先需要判断注入点是否存在,如果在页面的url中存在某些参数,比如下面这个URL中就存在一个id参数:http://xxxxx.xxx/?id=1

就可以尝试改变id的数值,将参数值+1或-1,然后查看页面展示的内容是否会变化,如果页面会发生变化,则我们就可以初步判断,这个id会带入数据库查询,查询后的内容会显示到页面中来。

猜测查询的SQL语句大致为:

select * from [表名] where id = 1;

判断注入类型

字符型

在id后面跟一个单引号进行尝试,发现报错信息为 ''1'' LIMIT 0,1' ,去掉报错信息本身的左右单引号,为 '1'' LIMIT 0,1 ,发现1的左方1个单引号,右方2个单引号。可以判断出SQL语句为select * from [表名] where id = ’1‘ LIMIT 0,1;

报错信息分析:因为我们在id后多跟了一个单引号,导致查询语句在id后闭合,后续内容无法正常执行,所以出现这个报错

由此判断id的接受类型为字符型

数字型

判断是否为数字型依然选择添加单引号测试,发现报错结果为 '' LIMIT 0,1' ,去除报错信息本身的左右单引号,为 ' LIMIT 0,1 ,说明跟在id后的单引号多余,导致查询语句无法执行

报错信息分析:传入的参数前面并没有引号包裹,多出的单引号导致语句异常

由此判断id的接受类型为数字型

添加单引号

添加了单引号之后,如果页面中直接进行了报错,并且报错的信息显示到了页面中来,说明我们输入的单引号被带入了数据库查询,我们就可以直接判断此处存在sql注入漏洞。并且结合之前判断的页面是否有回显,就可以尝试进行联合查询注入或是报错注入。

添加逻辑运算

添加 and 1 = 1and 1 = 2

在添加逻辑运算之前我们需要判断或者猜测注入点的数据类型和闭合方式,并对语句进行相应的引号、括号闭合。

比如字符型我们可以直接添加and 1=1 ,而单验号闭合的字符型我们就需要添加 'and '1'=1 ,或 'and '1'=1' # 使用注释符号将后面的引号直接注释掉。

添加了逻辑运算符之后提交,因为 1=1 恒为真,而 1=2 恒为假,所以如果我们的输入带入了数据库,一定会影响到 SQL 语句的布尔状态,如果两次查询返回的页面不同,说明页面存在布尔状态,此处存在注入漏洞,可以考虑使用布尔盲注进行注入。

添加sleep( )函数

sleep() 函数可以让程序在当前位置停留指定的时间,于是我们可以通过观察页面相应的时间来判断我们插入的参数是否会被带入数据库执行。

在参数后添加 and sleep(5) 然后观察页面响应时间是否明显变长,或直接在开发者工具中网络选项卡下观察页面的响应时间。如果页面响应时间确实按照我们的要求增加了5秒,则说明此处存在注入漏洞,我们可以考虑通过延时注入。

执行注入

SQL注释

SQL 注入过程中注释符号有以下几种表达方式:

1
2
3
--
#
%23

SQL注入过程中注释符号的作用是把后面不需要的语句注释掉,以保证SQL命令的完整性。在注入的查询语句后跟注释可以屏蔽掉原本正常查询语句的部分内容。

联合查询注入

有信息回显才能用

1. 爆列

使用 order by 语句测试当前表有多少列, order by 语句的作用是按照某一列进行排序,在 MySQL 数据库中我们可以使用数字来代替对应列的列名,如果数据库中没有对应的列,就会报错。所以我们可以通过依次增加数字,直到报错,然后报错前的数字就是表的列数。例如:

[order by 1]->[order by 2]->[order by 3]->[order by 4]->数据库报错

2. 爆数据库

使用 database() 可以获取当前使用的数据库名称

使用联合查询语句进行查询:

union select 1,database(),3 #

回显信息可以看到Login name已经被替换为了数据库的名称。

4. 爆表

利用前提中的方法,使用联合查询语句:

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

可以查到数据库中的所有表,其中 group_concat() 的意思为将查询到的所有table_name聚合为一条内容,从而解决某些网站只能回显一行的情况。

5. 爆列

对于可能有敏感信息的表可以使用联合查询语句:

union select 1,group_concat(column_name),3 from information_schema.columns where table_name = '<table>'

可以查到 <table> 表中的所有列。

6. 爆值

现在已经得到了数据库名,表名,列。接下来就是需要获取最重要的值,依然使用联合查询语句:

union select 1,group_concat(<column1>,<column2>),3 from <table> #

<column1>,<column2> 表示想要获取数据的列。

<table> 表示想要获取数据的表。

剩余内容正在施工…