之前的SQL注入笔记侧重于学习其原理,这次详细学一些注入方法和例子。
注入分类
按照查询字段分类
数字型:输入的参数为整型时,可认为是数字型注入。
字符型:当输入参数为字符串时,成为字符型注入。
按照注入方法分类
Union注入,报错注入,布尔注入,时间注入。
判断是字符型还是数字型
用and 1=1和 and 1=2判断,提交and 1=1和提交and 1=2都能正常显示界面,则不可能是数字型注入,即为字符型注入。反之则为数字型注入。还有一个就是用 id=2-1 ,如果是数字型那么这里是可以运算的,相当于id=1,如果是字符型这里就不能运算。
闭合方式
一般采用‘ 、 “ 、 ’) 、 ”) 或其他方式。
判断的话就在注入语句后分别加上这些闭合方式,再跟--+或#或%23注释符,查看是否报错。
闭合的作用
手工提交闭合符号,结束前一段查询语句,后面即可加入其他语句,查询需要的参数,不需要的语句可以用注释符号 --+ 或 # 或%23 注释掉。
union联合注入
想用union联合注入,必须要确保union前后数据的列数一致,那么就要先知道前面的列数。可以用group by或order by 试出来,怎么用在上篇笔记中讲过(基本SQL语句学习笔记blog.csdn.net/Yisitelz/article/details/132224214)。group by的隐蔽性更好一些,能绕过一些waf。试出来列数之后,就可以在union后写下其他的操作语句,放占位符对齐了。比如
?id=1' union select 1,2,database() --+
这条语句能返回数据库名称。前面有三列数据,那么1,2就是占位符;--+用于注释后台中的语句。有时页面回显的数据有限制,可能只显示出一行数据,这里我们可以把id=1改成id=-1,让这行不存在,这样就会接着显示后面的数据了。然后还可以根据试出来的回显位,只让有价值的数据显示出来。比如占位符2显示出来了,它就是回显位,database()却没显示出来,把它俩换一下位置就能让database()显示出来,而无关轻重的占位符2则显示不出来。
拿到表名、列名、最终目标
表名
数据库Information_schema中包含两个数据表,tables表名集合表、columns列名集合表。还是接着上面的情况,id=0' union select 1,table_name,3 from Information schema.tables --+ 这个就是拿到表名的语句
如果你嫌Information_schema里的表太多了而你只想要当前数据库的表名,你可以在原语句注释前加上where table_schema=database()
但是前面又说过了,有的网页显示有限制,甚至只能显示一行的内容,就算是一个数据库,那里面也有很多表啊。这时候就该group_concat()登场了。这玩意怎么用我在上一篇笔记里也讲过,这里简单提一下,它能把数据多行变一行显示。原每一行的不同列数据挤在一起,原行数据之间用逗号隔开。最后改来改去原语句变成这样:
id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
列名
拿到列名也差不多,举个例子id=0' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table name='users' --+ 意思就是,在所有列名中拿到库为security且表为users的列,并整合为一行显示。
最终目标
既然知道了库名、表名、列名,那最终还不是信手拈来,要啥有啥。
id=0' union select 1, group_concat(username,password), 3 from users --+
意思就是把users表中的usename列和password列合并显示出来。当然,把用户名和密码挤在一起未免太影响可读性了,可以在username和password之间加点什么分开它们,比如把原函数改为group_concat(username,‘~’password) 这样数据情况就一目了然了。