windows下sqli-labs的搭建及学习(GET篇):
http://blog.csdn.net/sherlock17/article/details/64454449
Less-11:基于错误的_post_单引号_字符型注入
post型的注入一般都是登录绕过,测试的方法与get都类似,通过查看源码我们知道以post方式传递的两个参数是uname和passwd,那么首先来尝试下单引号
从这里的报错中可以知道后台的sql语句应该是select username,password from table where username='$_GET['uname']' and password='$_GET['passwd']' limit 0,1
而这里之所以报错是因为加号没有被转义,可以换成--%20来注释后面的limit,然后我们可以构造永真语句绕过登录
接着猜字段数
再试试3,报错,说明用select查询的是两个字段
于是 用union来爆数据库名
依次爆表名,字段
最后的payload:
这里还有一个需要注意的地方,username和password的输入框都可以作为注入点,但是在前一个参数处注入时只能注释掉后面的语句,而在最后一个参数处注入时既可以注释也可以闭合,闭合即uname=&passwd=' or 1='1,后一个1前的单引号会与limit前的单引号匹配(闭合)可以正常执行,之所以username那里不能使用闭合,是因为一旦使用后语句将变成:
select username,password from table where username='$_GET['uname']' or 1=1 and password='$_GET['passwd']' limit 0,1
这里的and运算符优先级比or高,语句会先执行1=1 and password='$_GET['passwd']',因为我们并不知道正确的password值,故该语句必为flase,且username的值也是flase,两者进行or运算,其结果也必然是flase
Less-12:基于错误的_双引号_post_字符型_变形注入
尝试单引号没反应,再试试双引号
绕过登录:
方法同之前一样,payload:
Less-13:单引号_post_字符型_双注入_变形注入
尝试之前的方法,可以登入但没有返回用户信息
从源码中可以看到,输出被注释了
于是尝试双注入,直接上payload:
Less-14:双引号_post_字符型_双注入_变形注入
把less-13改成双引号就行了
Less-15:单引号_post_bool型/时间型盲注
输入单引号和双引号出错但都没显示报错,加入永真式单引号可以登入,但也没有用户信息
尝试双注入,仍然没有用户信息返回
查看源码发现,他将输出和sql报错都注释了,less-13仅注释了输出所以可以用双注入
这里只能考虑盲注了,因为合法输入和非法输入返回的是不同的页面,所以这里可以用bool盲注,盲注通常都是先确定数据库名,表名,字段名的长度,然后再匹配内容,如下测试数据库名的长度
由此可以确定数据库名的长度是8,接着来匹配名字的8位字母
于是可以确定数据库名的第一个字母是's',按照这个方法逐个去匹配,最好的方式还是写个脚本,省时省力
Less-16:双引号_post_bool型/时间型盲注
输入uname=&passwd=") or 1=1%23显示登入,其余的和less-15没有什么不同,但也可以用来练下时间型盲注,可以构造如下两种:
uname=&passwd=") or (ascii(substr((select database()) ,1,1))) >115 or if(1=1, sleep(5), null)%23
uname=&passwd=") or if(ascii(substr((select database()) ,1,1))>115,1,sleep(5))%23
Less-17:基于错误的_post_更新查询注入
单双引号尝试后,他的画风始终是这样子的
注意到他的提示password reset,估计后台会用到update,于是去翻了下源码,果然
他的大概执行过程是接收到username和password后,首先根据username的值查询数据库返回username和password,然后再将原有的password值用接收到的值替换掉,这里有一个问题是,username在接收时用了一个自定义的过滤函数check_input(),这个函数首先做了判空处理,合法就截取username的前15个字符,然后是通过get_magic_quotes_gpc()的返回值判断magic_quotes_gpc的值是on还是off:
magic_quotes_gpc=on时, 不用对输入和输出数据库的字符串数据作addslashes()和stripslashes()的操作,数据也会正常显示。
magic_quotes_gpc=off 时,必须使用addslashes()对输入数据进行处理,但并不需要使用stripslashes()格式化输出,因为addslashes()并未将反斜杠一起写入数据库,只是帮助mysql完成了sql语句的执行。
最后,他用了ctype_digit()判断username值的类型是否是数字,是字符就用mysql_real_escape_string对特殊字符进行转义
显然,username这里并不好注入,只有通过弱口令爆破,像是admin之类的,但是他对password的接收没有做过滤的处理,于是我们可以在这里动手脚
对于update的注入有几种思路,我们将他连同insert和delete一起来总结一下:
1、子查询注入
子查询注入原理即双注入,对于dateup、delete和insert通常都是结合or的逻辑判断,本题为例我们对update可以构造如下语句
获取数据库名:
获取表名:
获取字段名:
获取用户信息;
这里就 直接放insert和delete的后台语句了,利用原理和构造的语句与update都是一样的:
- INSERT INTO users (username, password) VALUES ('admin',' or (SELECT 1 FROM(SELECT count(*),concat((SELECT concat(0x7e,0x27,cast(database() as char),0x27,0x7e) FROM information_schema.tables),floor(rand()*2))x FROM information_schema.tables group by x)a)%23);
- DELETE FROM users WHERE id=1 or (SELECT 1 FROM(SELECT count(*),concat((SELECT concat(0x7e,0x27,cast(database() as char),0x27,0x7e) FROM information_schema.tables),floor(rand()*2))x FROM information_schema.tables group by x)a)%23;
2、通过name_const():
name_const(name,value):返回给定值,当用来产生一个结果集合列时, name_const()促使该列使用给定名称
但他的使用范围受限,只适用于一些数据库版本高于5.0.12,但又稍旧的版本,像现在的5.7版本就不用想了...然而我用的就是较新的版本,注入只能显示数据库的版本信息,想要查询其他的信息,会显示Incorrect arguments to NAME_CONST,所以,这里我就不截图了,直接放payload:
获取数据库:
- ' or (SELECT * FROM (SELECT(name_const(database(),1)),name_const(database(),1))a) where username='admin'%23
获取表名:
- ' or (SELECT * FROM(SELECT name_const((SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema='security'),1),name_const(( SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema='security'),1))a)%23
总的来说,对于update,insert和delete都有一个固定的结构:... or (select * from(select name_const((select ...),1),name_const((select...),1))a) ...
3、通过updatexml():
updatexml(xml_target,xpath_expr,new_xml)函数是MYSQL对XML文档数据进行查询和修改的XPATH函数,xml_target是目标xml,形式类似于节点目录,xpath_expr是xml的表达式,new_xml是用来替换的xml,简单来说就是,用new_xml把xml_target中包含xpath_expr的部分节点(包括xml_target)替换掉,比如,updatexml(<a><b><c>asd</c></b><e></e></a>,'//b',<f>abc</f>)运行结果是<a><f>abc</f><e></e></a>,其中'//b'的斜杠表示不管b节点在哪一层都替换掉,而'/b'则是指在根目录下替换,此处xml_target的根目录节点是a
利用updatexml()获取数据的固定payload是:... or updatexml(1,concat(0x7e,(...)),0) ....updatexml()的xml_target和new_xml参数随便设定一个数就行,这里主要让他报错
首先获取数据库名
获取表名:
获取字段名
获取用户信息
报错了,百度一下,说是不能先select出同一表中的某些值,再update这个表(在同一语句中),也就是说将select出的结果再通过中间表select一遍,这样就规避了错误,其实之前在子查询注入中也有用到此方法,同时,还要给多加的一重select赋一个别名
注意,这个问题只出现于mysql,mssql和Oracle不会出现此问
最后总结一下payload:or updatexml(1,concat(0x7e,(select * from(select ....)a),0x7e),0)%23
4、通过extractvalue():
extractvalue(xml,xpath)函数也是MYSQL5.1以后推出的对XML文档数据进行查询和修改的XPATH函数,可一次获取多个xml中某节点的值,注入时第一个参数随便给一个数字
直接上payload:
payload:or extractvalue(1,concat(0x7e,(select * from(select ....)a),0x7e))%23
Less-18:基于错误的_post_用户代理_头部注入
看标题就知道,这道题主要是通过修改User Agent获取他的报错信息,之前直接改password的方法肯定是不行了,从源码可以看出来password和username都进行了过滤
修改User Agent常用的工具有burp,Live Http Headers,Modify Headers,后两者都是firefox的插件,其中Live Http Headers貌似因为firefox版本的更新,变得不好用了,尤其是对post数据包的重放,但是也有办法修复,这里贴一个修复的方法:http://www.cnblogs.com/lcamry/p/5532122.html
我下面使用的是Modify Headers,首先结合之前的updatexml报错方法修改他的User-Agent
然后刷新less-18的页面就可以看到爆出的数据库名了
接着用同样的方法爆出表名、字段名、用户信息,但我这里出现了报错暂时还没解决,所以采用别的方法,既然这里构成了逻辑判断,那么就可以用盲注,写个忙盲注脚本就行
Less-19:基于报错的_post_referer_头部注入
登陆后发现他直接给出了提示:“Your referer is:”
于是用和之前相同的方法修改referer:
然后爆表名:
最后的payload:
Less-20:基于报错的_post_cookie_头部注入
换个地方继续注,直接上payload:
Less-21:基于错误的_复杂型_字符串_cookie注入
登录成功后,发现一个奇怪的地方,我登录的账号是admin,但是显示的cookie不是admin,于是去翻了下源码
原来是对cookie中的username做了base64加密,把页面上显示的cookie值拿去解密确实是admin
那么修改cookie的时候就可以把语句先做一次base64的加密,然后再赋给uname,这样就可以突破了,直接上最后的payload:') union select 1,group_concat(username),group_concat(password) from users#
Less-22:基于错误的_post_双引号_字符型_cookie注入
这个和Less-21差别不大,只是')改成"就可以了,下面直接上payload:" union select 1,group_concat(username),group_concat(password) from users#
参考文献:
http://blog.csdn.net/ysynhtt/article/details/45115849
http://blog.csdn.net/priestmoon/article/details/8016121