网络安全的机器学习秘籍-三-

110 阅读1小时+

网络安全的机器学习秘籍(三)

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

译者:飞龙

协议:CC BY-NC-SA 4.0

第五章:使用机器学习的渗透测试

渗透测试,简称“渗透测试”,是一种授权的模拟网络攻击,旨在发现信息系统中的安全漏洞。在本章中,我们将涵盖一系列用于渗透测试和安全对策的机器学习技术。我们将从破解一个简单的验证码系统开始。接下来,我们将介绍使用深度学习、模糊测试和代码小工具自动发现软件漏洞。我们将展示如何增强 Metasploit,并讨论如何评估机器学习系统对抗性攻击的鲁棒性。最后,我们将探讨一些更专业的主题,如去匿名化 Tor 流量、通过键击动态识别未授权访问以及检测恶意 URL。

本章将涵盖以下内容:

  • 验证码破解器

  • 神经网络辅助模糊测试

  • DeepExploit

  • 使用机器学习的 Web 服务器漏洞扫描器(GyoiThon)

  • 使用机器学习去匿名化 Tor 流量

  • 使用机器学习的物联网IoT)设备类型识别

  • 键击动态

  • 恶意 URL 检测器

  • 深度渗透

  • 基于深度学习的自动软件漏洞检测系统(VulDeePecker)

技术要求

在本章中,我们将使用以下工具:

  • TensorFlow

  • Keras

  • OpenCV

  • Google API 客户端

  • Censys

  • NetworkX

  • Tldextract

  • dpkt

  • NumPy

  • SciPy

  • Xlib

  • Gensim

代码和数据集可以在github.com/PacktPublishing/Machine-Learning-for-Cybersecurity-Cookbook/tree/master/Chapter05找到。

验证码破解器

验证码是一种旨在防止自动访问或抓取的系统。它通过提出旨在识别用户是人类还是程序的问题来实现这一点。你可能已经看到了许多类似的屏幕截图:

有时,要求插入一段代码,有时需要选择一些物体,例如在一系列图像中选择店面或交通信号灯,有时验证码是一个数学问题。在本章中,我们将破解一个简单的验证码系统,叫做“非常简单的验证码”:

尽管其简单性,非常简单的验证码仍然被广泛使用。最重要的是,它将说明如何破解其他更复杂的验证码系统。

第一步是处理 CAPTCHA 数据集,以便它适合机器学习。最简单的方法可能会失败。即,构建一个监督分类器,该分类器接收一个四字符的 CAPTCHA,并将其分类到 (26+10)⁴ = 1,679,616 个可能的类别中(26 个字母和 10 个数字,由于四个字符的组合,类别总数为上述幂的计算结果)。这种方法需要大量的数据和计算。相反,我们在单个字符上训练分类器,将 CAPTCHA 切割成单个字符,然后进行四次分类。这里同样有一个问题,那就是精确裁剪字符并不容易。通过使用 OpenCV 功能和额外的考虑,本食谱将解决这一挑战。

处理 CAPTCHA 数据集

在本食谱中,我们将执行创建 CAPTCHA 破解器的第一部分,即处理 CAPTCHA 数据集,使其适合训练机器学习模型。

准备工作

本食谱的准备工作包括在 pip 中安装一些软件包。安装说明如下:

pip install opencv-python imutils

此外,为了方便起见,已经包含了一些 CAPTCHA 数据集,存储在 captcha_images.7z 文件中。只需解压此存档到 captcha_images 文件夹中即可使用。

如何操作...

在接下来的步骤中,我们将处理一个 CAPTCHA 数据集,使其适合训练机器学习模型:

  1. 收集大量 CAPTCHA 数据。

  2. 我们的下一个目标是处理 CAPTCHA,指定 CAPTCHA 图像存储的位置,然后枚举指定文件夹中的所有 CAPTCHA:

import os

captcha_images_folder = "captcha_images"
captchas = [
    os.path.join(captcha_images_folder, f) for f in os.listdir(captcha_images_folder)
]
  1. 定义一个函数,该函数将接受 CAPTCHA 图像并生成一个灰度版本,以及一个阈值化的(即黑白)版本的 CAPTCHA 图像:
import cv2

def preprocess_CAPTCHA(img):
    """Takes a CAPTCHA image and thresholds it."""
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray_with_border = cv2.copyMakeBorder(gray, 8, 8, 8, 8, cv2.BORDER_REPLICATE)
    preprocessed = cv2.threshold(
        gray_with_border, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU
    )[1]
    return gray_with_border, preprocessed
  1. 定义一个函数,该函数将接受 CAPTCHA 的路径,并使用该路径存储该 CAPTCHA 的文本标签:
def get_CAPTCHA_label(path_to_file):
    """Get the CAPTCHA text from the file name."""
    filename = os.path.basename(path_to_file)
    label = filename.split(".")[0]
    return label
  1. 定义一个函数,该函数将接受 CAPTCHA 的轮廓,我们将计算这些轮廓,并确定它们的边界矩形,为将 CAPTCHA 切割成单个字符做准备:
def find_bounding_rectangles_of_contours(contours):
    """Determines the bounding rectangles of the contours of the cropped letters."""
    letter_bounding_rectangles = []
    for contour in contours:
        (x, y, w, h) = cv2.boundingRect(contour)
        if w / h > 1.25:
            half_width = int(w / 2)
            letter_bounding_rectangles.append((x, y, half_width, h))
            letter_bounding_rectangles.append((x + half_width, y, half_width, h))
        else:
            letter_bounding_rectangles.append((x, y, w, h))
    return letter_bounding_rectangles
  1. 定义一个函数,该函数将接受 CAPTCHA 的路径,将其作为图像读取,并使用我们已定义的函数进行预处理:
def CAPTCHA_to_gray_scale_and_bounding_rectangles(captcha_image_file):
    """Take a CAPTCHA and output a grayscale version as well as the bounding rectangles of its cropped letters."""
    image = cv2.imread(captcha_image_file)
    gray, preprocessed = preprocess_CAPTCHA(image)
    contours = cv2.findContours(
        preprocessed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )
    contours = contours[0]
    letter_bounding_rectangles = find_bounding_rectangles_of_contours(contours)
    letter_bounding_rectangles = sorted(letter_bounding_rectangles, key=lambda x: x[0])
    return gray, letter_bounding_rectangles
  1. 定义另一个辅助函数,接受字母轮廓的边界矩形并从中生成字符图像:
def bounding_rectangle_to_letter_image(letter_bounding_box, grayscaled):
    """Obtains the letter defined by a bounding box."""
    x, y, w, h = letter_bounding_box
    letter_image = grayscaled[y - 2 : y + h + 2, x - 2 : x + w + 2]
    return letter_image
  1. 定义最后一个辅助函数,执行 CAPTCHA 的裁剪,然后保存每个裁剪后的字符:
captcha_processing_output_folder = "extracted_letter_images"
character_counts = {}

def crop_bounding_rectangles_and_save_to_file(
    letter_bounding_rectangles, gray, captcha_label
):
    """Saves the individual letters of a CAPTCHA."""
    for letter_bounding_rectangle, current_letter in zip(
        letter_bounding_rectangles, captcha_label
    ):
        letter_image = bounding_rectangle_to_letter_image(
            letter_bounding_rectangle, gray
        )

        save_path = os.path.join(captcha_processing_output_folder, current_letter)
        if not os.path.exists(save_path):
            os.makedirs(save_path)

        character_count = character_counts.get(current_letter, 1)

        p = os.path.join(save_path, str(character_count) + ".png")
        cv2.imwrite(p, letter_image)

        character_counts[current_letter] = character_count + 1
  1. 遍历所有的 CAPTCHA,进行预处理,找到字符轮廓,然后保存相应的字符:
import imutils
import numpy as np

for captcha_image_file in captchas:
    captcha_label = get_CAPTCHA_label(captcha_image_file)
    gray, letter_bounding_rectangles = CAPTCHA_to_gray_scale_and_bounding_rectangles(
        captcha_image_file
    )
    if len(letter_bounding_rectangles) != 4:
        continue
    crop_bounding_rectangles_and_save_to_file(
        letter_bounding_rectangles, gray, captcha_label
    )

它是如何工作的……

我们的起点是收集大量 CAPTCHA(步骤 1)。您可以在 captcha_images.7z 中找到这些 CAPTCHA。或者,由于 Really Simple CAPTCHA 的代码可以在线获取,您可以修改它来生成大量的 CAPTCHA。其他方法包括使用机器人抓取 CAPTCHA。接下来,在 步骤 2 中,我们指定 CAPTCHA 图像的存储位置,并列举出指定文件夹中的所有 CAPTCHA。我们的目标是开始处理这些 CAPTCHA。在 步骤 3 中,我们定义一个函数,用来阈值化并将 CAPTCHA 图像转换为灰度图像。这样可以减少计算量,并且更容易确定一个字符的起始位置和下一个字符的结束位置。然后我们定义一个函数来获取 CAPTCHA 的标签(步骤 4)。接下来,为了准备处理,我们定义一个实用函数,获取 CAPTCHA 的轮廓,并利用这些轮廓来确定每个字符的边界矩形。一旦找到边界矩形,就可以轻松地裁剪字符,以便将其隔离出来(步骤 5)。然后,在 步骤 6 中,我们将到目前为止定义的函数组合成一个方便的函数。我们还定义了一个额外的函数,用来实际裁剪字符。将以上内容结合起来,在 步骤 8 中,我们编写一个函数来执行前面的步骤,然后保存结果中的隔离字符,并统计每个字符保存的数量。这对命名和统计都非常有帮助。现在我们可以开始裁剪了,所以,在 步骤 9 中,我们遍历所有的 CAPTCHA,并利用我们的实用函数裁剪单个字符。请注意,if 语句用于跳过裁剪错误的 CAPTCHA。

在本教程结束时,您的输出文件夹 extracted_letter_images 应该会有一个文件夹,包含大多数字母和数字,如下图所示:

并非所有的字符和数字都有表示,原因是 CAPTCHA 中不包含数字 1 和字母 I,因为这两者容易混淆。同理,数字 0 和字母 O 也存在相同问题。

在每个文件夹内,您将会有大量该字母或数字的实例,这些实例是从原始 CAPTCHA 中裁剪和处理出来的:

这结束了预处理步骤。

训练一个 CAPTCHA 解码神经网络

现在我们的数据已经处理得很整洁,可以训练一个神经网络来进行 CAPTCHA 预测。

准备工作

本教程的准备工作包括通过 pip 安装若干软件包。安装步骤如下:

pip install opencv-python imutils sklearn keras tensorflow

如何做到这一点...

在接下来的步骤中,我们将训练一个神经网络来解决 Really Simple CAPTCHA 的 CAPTCHA:

  1. 指定提取的字母图像所在的文件夹:
captcha_processing_output_folder = "extracted_letter_images"
  1. 导入 OpenCV 和 imutils 进行图像处理:
import cv2
import imutils
  1. 定义一个辅助函数,将图像调整为给定的大小:
def resize_image_to_dimensions(image, desired_width, desired_height):
    """Resizes an image to the desired dimensions."""
    (h, w) = image.shape[:2]
    if w > h:
        image = imutils.resize(image, width=desired_width)
    else:
        image = imutils.resize(image, height=desired_height)
    pad_width = int((desired_width - image.shape[1]) / 2.0)
    pad_height = int((desired_height - image.shape[0]) / 2.0)
    image_with_border = cv2.copyMakeBorder(
        image, pad_height, pad_height, pad_width, pad_width, cv2.BORDER_REPLICATE
    )
    image_with_border_resized = cv2.resize(
        image_with_border, (desired_width, desired_height)
    )
    return image_with_border_resized
  1. 准备读取图像:
def read_image(image_file_path):
    """Read in an image file."""
    img = cv2.imread(image_file_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img = resize_image_to_dimensions(img, 20, 20)
    img = np.expand_dims(img, axis=2)
    return img
  1. 读取每个字母图像并记录其标签:
import numpy as np
import os
from imutils import paths

images = []
labels = []

for image_file_path in imutils.paths.list_images(captcha_processing_output_folder):
    image_file = read_image(image_file_path)
    label = image_file_path.split(os.path.sep)[-2]
    images.append(image_file)
    labels.append(label)
  1. 归一化所有图像,即将像素值缩放到 0-1,并将标签转换为 NumPy 数组:
images = np.array(images, dtype="float") / 255.0
labels = np.array(labels)
  1. 创建训练集和测试集的划分:
from sklearn.model_selection import train_test_split

(X_train, X_test, y_train, y_test) = train_test_split(
    images, labels, test_size=0.3, random_state=11
)
  1. 导入LabelBinarizer以编码标签:
from sklearn.preprocessing import LabelBinarizer

label_binarizer = LabelBinarizer().fit(y_train)
y_train = label_binarizer.transform(y_train)
y_test = label_binarizer.transform(y_test)
  1. 定义神经网络架构:
from keras.models import Sequential
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.layers.core import Flatten, Dense

num_classes = 32
NN_model = Sequential()
NN_model.add(
    Conv2D(20, (5, 5), padding="same", input_shape=(20, 20, 1), activation="relu")
)
NN_model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
NN_model.add(Conv2D(50, (5, 5), padding="same", activation="relu"))
NN_model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
NN_model.add(Flatten())
NN_model.add(Dense(512, activation="relu"))
NN_model.add(Dense(num_classes, activation="softmax"))
NN_model.compile(
    loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]
)
NN_model.summary()
  1. 将神经网络拟合到训练数据上:
NN_model.fit(
    X_train,
    y_train,
    validation_data=(X_test, y_test),
    batch_size=16,
    epochs=5,
    verbose=1,
)
  1. 选择一个你想破解的 CAPTCHA 实例:
CAPTCHA = "captcha_images\\NZH2.png"
  1. 我们将导入在上一节中用于处理图像的所有函数,即find_bounding_rectangles_of_contourspreprocess_CAPTCHAget_CAPTCHA_labelCAPTCHA_to_grayscale_and_bounding_rectangles

  2. 按照我们在上一节中所做的方式处理 CAPTCHA 图像:

captcha_label = get_CAPTCHA_label(CAPTCHA)
gray, letter_bounding_rectangles = CAPTCHA_to_gray_scale_and_bounding_rectangles(
    CAPTCHA
)
predictions = []
  1. 读取每个裁剪后的字母,并使用神经网络预测标签:
for letter_bounding_rectangle in letter_bounding_rectangles:
    x, y, w, h = letter_bounding_rectangle
    letter_image = gray[y - 2 : y + h + 2, x - 2 : x + w + 2]
    letter_image = resize_image_to_dimensions(letter_image, 20, 20)
    letter_image = np.expand_dims(letter_image, axis=2)
    letter_image = np.expand_dims(letter_image, axis=0)
    prediction = NN_model.predict(letter_image)
    letter = label_binarizer.inverse_transform(prediction)[0]
    predictions.append(letter)
  1. 输出预测结果:
predicted_captcha_text = "".join(predictions)
print("Predicted CAPTCHA text is: {}".format(predicted_captcha_text))
print("CAPTCHA text is: {}".format(CAPTCHA.split("\\")[-1].split(".")[0]))

Predicted CAPTCHA text is: NZH2
CAPTCHA text is: NZH2

它是如何工作的……

在上一节中我们已经完成了 CAPTCHA 的预处理,现在我们准备利用这些数据来训练一个 CAPTCHA 破解器。我们首先设置一个变量,指向从 CAPTCHA 中提取的所有单个字符的路径。然后我们导入将要使用的图像处理库(第 2 步),接着在第 3 步中定义一个调整图像大小的函数。这是一种相对标准的字符识别方法,可以加速训练并减少内存消耗。在第 4 步中,我们定义一个方便的函数,将文件读取为 NumPy 数组,用于训练;然后在第 5 步中,我们遍历所有字母并记录它们的标签。接下来,我们对所有图像进行归一化处理(第 6 步),这是另一个标准的计算机视觉技巧。现在我们创建训练集和测试集的划分,准备进行分类器拟合(第 7 步),然后使用标签二值化器对标签进行编码(第 8 步)。这是必要的,因为标签是字符,可能并非数值类型。在第 9 步中,我们定义神经网络的架构。所定义的架构是相对常见的,既具有精度又具备速度。在第 10 步中,我们将神经网络拟合到训练集上。其他参数可以增强网络的性能。现在,繁重的工作已经完成。接下来,我们展示 CAPTCHA 破解器如何工作。在第 11 步中,我们选择一个单例实例来展示 CAPTCHA 破解器的有效性。在第 12 到 14 步中,我们将图像通过我们的处理管道,生成对该 CAPTCHA 的预测文本。最后,我们验证预测是否正确(第 15 步)。

神经网络辅助模糊测试

Fuzz 测试是一种软件漏洞检测方法,其中将大量随机输入提供给程序,寻找会导致崩溃、信息泄露或其他意外行为的输入。在自动化模糊测试中,程序会生成这些输入。通常,自动化模糊测试器存在一个缺点,即它们倾向于重复尝试冗余的输入。为了解决这个问题,最近开发了基于 AI 的模糊测试器。在这个食谱中,我们将使用 She 等人开发的基于神经网络的模糊测试器 NEUZZ(见 arxiv.org/abs/1807.05620)来发现软件中的未知漏洞。

准备工作

以下食谱要求使用 Ubuntu 16.04 或 18.04 虚拟机或物理机。在此设备上运行以下命令:

pip install keras

neuzz-modified.7z 解压到你选择的文件夹中。

如何操作...

在接下来的步骤中,我们提供了一个使用 NEUZZ 查找导致崩溃的输入的食谱,针对的是 readelf Unix 工具:

  1. 使用以下命令构建 neuzz:
gcc -O3 -funroll-loops ./neuzz.c -o neuzz

如果你收到警告,没关系。

2. 安装 32 位二进制文件所需的库:

 sudo dpkg --add-architecture i386
 sudo apt-get update
 sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1
  1. 以 root 用户身份设置 CPU 缩放算法和核心转储通知:
 cd /sys/devices/system/cpu
 echo performance | tee cpu*/cpufreq/scaling_governor
 echo core >/proc/sys/kernel/core_pattern
  1. neuzznn.pyafl-showmap 复制到 programs/readelf
 cp /path_to_neuzz/neuzz /path_to_neuzz/programs/readelf
 cp /path_to_neuzz/nn.py /path_to_neuzz/programs/readelf
 cp /path_to_neuzz/afl-showmap /path_to_neuzz/programs/readelf
  1. 为所有文件提供可执行权限:
chmod +x /path_to_neuzz/programs/readelf/neuzz
chmod +x /path_to_neuzz/programs/readelf/nn.py
chmod +x /path_to_neuzz/programs/readelf/afl-showmap
chmod +x /path_to_neuzz/programs/readelf/readelf
  1. 打开终端以启动神经网络模块:
cd /path_to_neuzz/programs/readelf
python nn.py ./readelf -a
  1. 打开另一个终端并启动 NEUZZ:
 ./neuzz -i neuzz_in -o seeds -l 7507 ./readelf -a @@

下面是运行这些命令的一部分:

  1. 通过运行以下命令测试 NEUZZ 收集的崩溃:
 ./readelf -a crash/file_name

工作原理…

大多数流行的模糊测试工具在某些有限的情况下有效,但通常会陷入循环中。基于梯度的方法,如这里讨论的这种方法,虽然很有前景,但并不完全适用于这个问题,因为现实世界中的程序行为不一定是平滑的函数(例如,它们可能是不连续的)。NEUZZ 背后的理念是使用神经网络来逼近程序的行为作为一个平滑的函数。然后,可以应用梯度方法来提高模糊测试的效率。我们从编译 NEUZZ(步骤 1)开始。funroll-loops标志会使编译器展开可以在编译时或进入循环时确定迭代次数的循环。这样,代码会变大,运行速度可能会更快,但不一定。继续设置 NEUZZ,我们加入 32 位支持(步骤 2)。我们设置 CPU 调节算法和核心转储通知(步骤 3);CPU 频率调节是一个让操作系统通过调整 CPU 频率来节省电力的设置。在接下来的两个步骤中,我们只需将文件放置在一个方便的位置,并允许执行权限。我们已经完成了 NEUZZ 的设置。现在,我们可以使用它来找到导致程序崩溃的输入。在步骤 6步骤 7中,我们开始使用神经网络搜索崩溃。等待足够的时间,让步骤 6步骤 7收集到足够的输入以使 readelf 工具崩溃后,我们执行其中一个输入(步骤 8),看看结果。果然,我们看到该输入导致 readelf 崩溃。

DeepExploit

DeepExploit是一个渗透测试工具,通过利用人工智能,将 Metasploit 提升到一个全新的水平。它的主要特点如下:

  • 深度渗透:如果 DeepExploit 成功利用目标漏洞,它将自动执行漏洞利用到其他内部服务器。

  • 学习:DeepExploit 是一个强化学习系统,类似于 AlphaGo。

使用 DeepExploit 来进行渗透测试可以大大增强你系统的安全性。在本教程中,我们将设置并运行 DeepExploit。

准备工作

现在,我们将引导你完成安装DeepExploit的步骤:

  1. 下载并设置 Kali Linux。你可以在www.offensive-security.com/kali-linux-vm-vmware-virtualbox-image-download/找到虚拟机镜像。接下来的步骤都将在你的 Kali Linux 系统中进行。

  2. 通过在终端中运行以下命令来安装 Git:

sudo apt install git
  1. 通过运行以下命令来安装 Python:
sudo apt install python3-pip
  1. 克隆git仓库。在终端中,运行以下命令:
git clone https://github.com/emmanueltsukerman/machine_learning_security.git
  1. 打开DeepExploit目录:

在终端中,运行以下命令:

cd machine_learning_security/DeepExploit
  1. 安装DeepExploit的前置软件包。

在终端中,运行以下命令:

pip3 install -r requirements.txt

如何操作...

在本教程中,你将使用DeepExploit来攻破一个受害者虚拟机。

  1. 下载Metasploitable2虚拟机镜像。

详细信息请参见metasploit.help.rapid7.com/docs/metasploitable-2

  1. 在虚拟机上运行一个Metasploitable2实例。

  2. 获取你的Metasploitable2的 IP 地址。

  3. 下一步是设置DeepExploit的配置。

  4. 在终端中运行ifconfig以获取 Kali Linux 的 IP 地址。编辑config.ini(例如,使用vim)并将[common]下的server_host设置为你的 Kali Linux IP。

  5. config.ini中的proxy_hostproxy_port的值设置为proxychains.conf中的值。

  6. 在终端中,运行cat /etc/proxychains.conf并找到socks4旁边的值:

 ...snip...
 [ProxyList]
 ...snip...
 socks4  127.0.0.1 9050
  1. 然后,将config.iniproxy_hostproxy_port的值设置为这些值:
 vim config.ini
 ...snip...
 proxy_host      : 127.0.0.1
 proxy_port      : 9050
  1. 在终端中运行msfconsole启动 Metasploit。

  2. 在 Metasploit 上启动 RPC 服务器。在指定的位置,输入你的 Kali Linux 的 IP 地址:

msf> load msgrpc ServerHost="kali linux ip" ServerPort=55553 User=test Pass=test1234.

你应该看到如下内容:

[*] MSGRPC Service: "kali linux ip":55553
[*] MSGRPC Username: test
[*] MSGRPC Password: test1234
[*] Successfully loaded plugin: msgrpc
  1. 在你的 Kali Linux 机器的终端中,运行python3 DeepExploit.py -t "Metasploitable2 ip" -m train来训练DeepExploit。训练开始时应该如下所示:

每当DeepExploit发现漏洞时,你会看到一个BINGO!!!的通知,如下图所示:

培训结束时,学习内容会被保存。你可以在此处看到完成屏幕:

  1. 使用DeepExploit测试Metasploitable2的漏洞。在终端中,运行python DeepExploit.py -t "Metasploitable2 ip" -m test

  2. 检查渗透测试的报告,如下所示:

firefox report/DeepExploit_test_report.html

我们会得到以下输出:

它的工作原理是…

本教程需要大量准备和配置。初步步骤是设置受害者虚拟机(步骤 1 和 2)。在 步骤 3 中,我们确定受害者虚拟机的 IP 地址。请注意,Metasploitable2 的凭据是 msfadmin/msfadmin。您可以使用这些凭据登录,然后使用 ifconfig 获取 Metasploitable2 的 IP 地址。如果您在同一主机上使用 Kali Linux 虚拟机和 Metasploitable2 虚拟机,请确保两者能够通信。例如,将两个虚拟机都放在 Host-Only 适配器上,并从 Kali Linux 机器 ping Metasploitable2 机器。接下来,我们配置 DeepExploit,以便我们可以针对受害者虚拟机进行攻击(步骤 4-8)。在 步骤 910 中,我们打开 Metasploit,Metasploit 被 DeepExploit 作为子模块使用。Metasploit 是一个主要的渗透测试框架。完成所有准备工作后,我们现在可以开始训练我们的模型。在 步骤 11 中,我们在 Metasploitable2 虚拟机上训练 DeepExploit。该模型利用 异步演员批评算法A3C),这是 Google DeepMind 团队几年前发布的算法,因其超越了 深度 Q 网络DQN)方法而闻名。接下来,我们测试我们的模型(步骤 12),并将其分析结果以报告的形式打印出来(步骤 13)。从长报告中可以看出,DeepExploit 发现了大量漏洞。从高层次来看,将强化学习应用于渗透测试表明,高效的自动化渗透测试即将到来。

使用机器学习的 Web 服务器漏洞扫描器(GyoiThon)

GyoiThon 是一款用于 Web 服务器的情报收集工具。它执行远程访问目标 Web 服务器,识别服务器上运行的产品,如 内容管理系统 (CMS)、Web 服务器软件、框架和编程语言。此外,它还可以使用 Metasploit 执行已识别产品的漏洞利用模块。

GyoiThon 的一些主要功能如下:

  • 远程访问/完全自动化:GyoiThon 仅通过远程访问即可自动收集目标 Web 服务器的信息。您只需执行一次 GyoiThon 即可完成操作。

  • 非破坏性测试:GyoiThon 仅通过正常访问即可收集目标 Web 服务器的信息。一个功能允许 GyoiThon 异常访问,如通过发送漏洞利用模块。

  • 收集多样的信息:GyoiThon 拥有多种情报收集引擎,如网络爬虫、Google 自定义搜索 API、Censys、默认内容探索器以及云服务检查。通过使用字符串模式匹配和机器学习分析收集的信息,GyoiThon 可以识别目标 Web 服务器上运行的产品/版本/CVE 编号、HTML 注释/调试信息、登录页面及其他信息。

  • 真实漏洞检查:GyoiThon 可以使用 Metasploit 执行漏洞模块,对已识别的产品进行攻击。因此,它可以确定目标 Web 服务器的实际漏洞。

准备工作

现在,您将按照步骤进行 GyoiThon 的安装和运行:

  1. 下载并设置 Kali Linux。您可以在www.offensive-security.com/kali-linux-vm-vmware-virtualbox-image-download/找到虚拟机镜像。接下来的步骤都将在您的 Kali Linux 机器上进行。

  2. 在终端中通过运行以下命令安装git

sudo apt install git
  1. 在终端中运行以下命令安装python
sudo apt install python3-pip
  1. 在 Linux 终端中,通过运行以下命令克隆 Git 仓库:
git clone https://github.com/gyoisamurai/GyoiThon.git
  1. 在终端中运行以下命令,打开GyoiThon目录:
cd GyoiThon
  1. 在终端中通过运行以下命令安装 DeepExploit 的先决条件:
pip3 install -r requirements.txt
  1. (可选)将Gyoi_CveExplorerNVD文件替换为本书仓库中提供的文件。在某些情况下,原始代码可能已失效,而本书仓库中的修改代码可能解决了这个问题。

如何操作...

在本食谱中,您将使用 DeepExploit 来攻陷一个受害者虚拟机:

  1. 下载Metasploitable2虚拟机镜像。

  2. 在虚拟机上运行一个Metasploitable2实例。

  3. 获取您的Metasploitable2的 IP 地址。

  4. 在您的 Kali Linux 机器上,您应该能够通过在浏览器中输入Metasploitable2 的 ip 地址:80来查看Metasploitable2的网页实例:

  1. 在终端中运行ifconfig来获取 Kali Linux 的 IP 地址。通过编辑config.ini(例如使用vim),将proxy设置为空,将server host设置为您的Kali Linux IP,将LHOST设置为Metasploitable2 IP,将LPORT设置为80

  2. 打开主机文件,并通过输入http:Metasploitable2 ip:80/来添加Metasploitable2的 web 服务器地址。

  3. 在 Kali Linux 机器的终端中,运行python3 Gyoithon.py开始攻击。

  4. 攻击结束后,检查位于报告文件夹中的渗透测试报告:

它是如何工作的…

步骤 1-3与 DeepExploit 中的配方没有区别,我们在其中准备了一个受害者虚拟机。Metasploitable2的凭证是msfadmin/msfadmin。你可以使用这些凭证登录,然后使用ifconfig获取你的Metasploitable2 IP。如果你在同一主机上使用 Kali Linux 虚拟机和Metasploitable2虚拟机,确保它们能够通信。例如,将这两个虚拟机设置为 Host-only 适配器,并从 Kali Linux 机器 ping 到 Metasploitable2 机器。接下来,我们通过检查能否访问受害者虚拟机的网页来验证环境是否已正确设置(步骤 4)。在步骤 5步骤 6中,我们配置 GyoiThon 以准备进行渗透测试。完成环境设置后,我们就准备开始渗透测试。在步骤 7中,我们利用 GyoiThon 搜索漏洞。然后,我们输出检测到的漏洞的完整报告(步骤 8)。通过查看报告,我们可以看到 GyoiThon 能够找到大量漏洞。确定受害者主机的漏洞后,我们可以使用例如 Metasploit 等工具进行攻击。

使用机器学习去匿名化 Tor

Tor 是一款免费的开源软件,用于实现匿名通信。此外,只有使用 Tor 浏览器才能访问的网站存在,它们是暗网生态系统的一部分——这是指普通用户无法访问的互联网部分。在这个配方中,我们将通过收集足够的特征和信息来去匿名化 Tor 流量,从而识别匿名用户的活动。这个配方使用了conmarap/website-fingerprinting仓库。

准备工作

现在将引导你完成设置 Tor 和 Lynx 网页浏览器所需的步骤:

  1. 设置一个 Ubuntu 虚拟机。

  2. 在终端中通过运行以下命令安装git

sudo apt install git
  1. 在终端中通过运行以下命令克隆代码仓库:
git clone https://github.com/conmarap/website-fingerprinting
  1. 在终端中通过运行以下命令安装torlynx
sudo apt install tor lynx

如何做到…

这个配方由三个部分组成。第一部分是收集 Tor 流量数据。第二部分是基于这些数据训练分类器。最后一部分是使用分类器来预测观察到的流量类型。

数据收集

以下步骤是数据收集时需要遵循的:

  1. config.json中列出你希望分类的流量类别:

  1. website-fingerprinting目录中,从一个类(比如duckduckgo.com)收集额外的数据点,在终端中运行以下命令:
./pcaps/capture.sh duckduckgo.com
  1. 打开另一个终端,并运行以下命令:
torsocks lynx https://duckduckgo.com

此时,你的两个终端应该如下所示:

  1. 一旦浏览会话结束,按Q键两次结束捕获。

当足够的训练数据收集完毕后,我们就可以开始训练分类器。

训练

要在数据上训练分类器,请使用 Python 运行以下脚本:

python gather_and_train.py

结果是一个分类器文件:nb.dmp

预测

让我们使用分类器来预测所观察到的流量类型:

  1. 要预测新的流量实例,请收集pcap文件。

  2. 使用 Python 运行predict.py脚本,并将pcap文件作为参数:

作者的聚类结果如下:

上述图表显示,尽管流量是匿名的,但特征的确能够区分不同类型的流量。

它是如何工作的...

我们通过创建一个我们希望分析的所有网站的目录(步骤 1)来开始构建我们的分类器。网站数量越多,目标访问这些网站的可能性越大。另一方面,网站越少,训练数据集所需的大小也越小。在步骤 2步骤 4 中,我们执行收集分类器数据点所需的步骤。具体来说,我们通过访问步骤 1中定义的网站之一,然后捕获该访问的网络数据包。通过对不同的浏览会话重复这些步骤,我们能够构建一个强大的数据集。在步骤 5 中,我们在迄今为止收集的数据上训练分类器。现在我们已经准备好测试我们的分类器了。在步骤 6 中,我们访问一个网站并收集其pcap文件,就像我们收集训练数据时一样。然后,我们使用分类器来分类这个访问(步骤 7)。我们看到,尽管用户使用了 Tor,它仍然正确地识别出了用户访问的网页。

总结来说,在本教程中,使用了 scikit-learn 编写了一个 k 最近邻分类器,用来分类 Tor 的pcap文件。在实际情况中,流量数据往往不像干净数据那样,准确度在相同大小的真实数据集上可能会降低。然而,拥有大量资源的实体可以创建一个非常精确的分类器。这意味着,像这种方法完全有可能准确地攻破匿名用户。

使用机器学习进行物联网设备类型识别

随着物联网(IoT)的到来,任何目标的攻击面都呈指数级增加。随着新技术的出现,也伴随而来的是新的风险,而在物联网的案例中,一个组织面临的风险之一就是恶意物联网设备被接入组织的网络。因此,能够判断网络中是否新增了此类设备,并了解其性质,是至关重要的。在本教程中,我们将构建一个机器学习模型,以按类型分类网络中的物联网设备。

准备工作

本教程的准备工作包括在pip中安装sklearnpandasxgboost包。安装指令如下:

pip install pandas sklearn xgboost

数据集已通过iot_train.csviot_test.csv文件提供。

如何实现...

在接下来的步骤中,我们将训练并测试一个分类器,基于物联网(IoT)网络信息:

  1. 导入pandasos,并读取训练和测试数据:
import pandas as pd
import os

training_data = pd.read_csv("iot_devices_train.csv")
testing_data = pd.read_csv("iot_devices_test.csv")

数据包含 298 个特征,如下图所示:

  1. 创建训练和测试数据集,其中目标是设备类别:
X_train, y_train = (
    training_data.loc[:, training_data.columns != "device_category"].values,
    training_data["device_category"],
)
X_test, y_test = (
    testing_data.loc[:, testing_data.columns != "device_category"].values,
    testing_data["device_category"],
)

设备类别包括安全摄像头、电视、烟雾探测器、恒温器、水传感器、手表、婴儿监视器、运动传感器、灯具和插座。

  1. 将类别标签编码为数值形式:
from sklearn import preprocessing

le = preprocessing.LabelEncoder()
le.fit(training_data["device_category"].unique())
y_train_encoded = le.transform(y_train)
y_test_encoded = le.transform(y_test)
  1. 实例化一个xgboost分类器:
from xgboost import XGBClassifier

model = XGBClassifier()
  1. 训练并测试xgboost分类器:
model.fit(X_train, y_train_encoded)
model.score(X_test, y_test_encoded)

输出结果如下:

0.6622222222222223

如何运作…

本示例的一个重要动机是我们不能依赖 IP 地址作为设备的标识符,因为该值可能会被伪造。因此,我们希望分析流量的高层数据,即元数据和流量统计信息,而不是内容,以确定设备是否属于该网络。我们首先读取训练和测试数据集。接着我们对数据进行特征提取,并通过观察分类标签进行快速数据探索(第 2 步)。为了将这些数据输入到我们的分类器中,我们将分类标签转换为数值标签,用于训练我们的机器学习分类器(第 3 步)。在第 4 步第 5 步中提取特征后,我们实例化、训练并测试一个xgboost分类器,最终在测试集上获得了0.66的评分。关联数据中有 10 类物联网设备。随机猜测 10 类设备的基线准确率为 0.1。这里训练的XGBoost分类器达到了 0.66 的准确率,表明它确实是一个有前景的基于高层流量数据成功分类物联网设备的方法。

击键动态学

击键动态学,也叫打字生物特征识别,是通过一个人的打字方式来识别其身份的研究领域。一个重要的应用场景是识别使用给定凭证登录的用户,例如,谁正在以 root 用户登录?另一个应用场景是识别何时有不同的用户输入了一系列击键。在这个示例中,我们将展示如何使用基于机器学习的击键动态学算法。

准备工作

本示例需要在 Linux 虚拟机或实际机器上运行。准备工作如下:

  1. 在你的设备上安装git

在终端中,运行以下命令:

sudo apt install git
  1. 克隆包含击键动态学算法代码的git仓库:
git clone https://github.com/emmanueltsukerman/keystroke_dynamics.git

如何操作…

在接下来的步骤中,我们将训练模型,基于两位用户的打字模式,然后使用该模型识别其中一位用户的打字模式。此示例应在 Linux 虚拟机或实际机器上运行:

  1. 运行example.py
python example.py
  1. 通过选择选项 1 并输入文本来训练用户 1 的击键模式:

  1. 运行 example.py 并通过选择选项 1 来训练用户 2 的按键动态,然后让用户 2 输入以下文本:

  1. 运行 example.py,这次选择选项 2。

  2. 让其中一个用户再次输入文本。算法将匹配该用户的键盘动态,并与训练数据中最相似的打字员进行匹配:

它是如何工作的…

按键动态分析利用用户在键盘上的打字节奏和速度来验证该用户的身份。我们首先设置一些基准。在步骤 1步骤 2 中,我们设置按键动态系统以学习第一个用户的打字模式。然后我们对第二个用户执行相同操作(步骤 3)。这就建立了我们的正常用户及其打字模式。在步骤 4步骤 5 中,我们利用经过训练的模型(在步骤 1-3 中训练)来确定当前用户是谁。如你所见,分类器输出相似度得分并预测当前用户是谁,依据的是它保存的用户目录。这使我们能够检测未经授权的用户,并能够简单地跟踪系统的使用情况。

恶意 URL 检测器

恶意 URL 每年造成数十亿美元的损失,原因包括托管垃圾邮件、恶意软件和漏洞攻击,以及窃取信息。传统上,对这些威胁的防御依赖于黑名单和白名单——分别是被认为恶意的 URL 列表和被认为安全的 URL 列表。然而,黑名单存在缺乏通用性的问题,且无法防御之前未见过的恶意 URL。为了解决这一问题,已经开发出了机器学习技术。在本教程中,我们将使用 Keras 运行一个基于字符级递归神经网络的恶意 URL 检测器。代码基于 github.com/chen0040/keras-malicious-url-detector

准备就绪

本教程的准备工作包括在 pip 中安装多个软件包。安装步骤如下:

pip install keras tensorflow sklearn pandas matplotlib

此外,克隆以下 git 仓库:

git clone https://github.com/emmanueltsukerman/keras-malicious-url-detector.git

如何操作…

  1. 训练双向 LSTM 模型:
python bidirectional_lstm_train.py

训练界面应如下所示:

  1. 测试分类器:
python bidirectional_lstm_predict.py

测试界面应如下所示:

最后,你可以在 reports 文件夹下看到结果:

它是如何工作的…

这是一个相对简单的方案,但它是构建更高效恶意 URL 检测器的良好起点。数据集由带有标签 0 和 1 的 URL 组成,取决于它们是恶意的还是良性的:

http://google.com,0
http://facebook.com,0
http://youtube.com,0
http://yahoo.com,0
http://baidu.com,0
http://wikipedia.org,0
http://qq.com,0
http://linkedin.com,0
http://live.com,0
http://twitter.com,0
http://amazon.com,0
http://taobao.com,0
http://blogspot.com,0

<snip>
http://360.cn,0 
http://go.com,0 
http://bbc.co.uk,0
http://xhamster.com,0

步骤 1中,我们训练了一个双向 LSTM 模型。通过深入代码,你可以根据自己的需求调整网络。训练好模型后,重要的是评估其性能并进行一些合理性检查。我们在步骤 2中进行测试步骤,通过在 20 个随机选定的 URL 上展示分类器的结果来进行。一般来说,双向 LSTM 是一种循环神经网络架构,因其能够记住信息并分析从前到后的数据及从后到前的数据而展现出巨大的潜力。

Deep-pwning

Deep-pwning 是一个用于评估机器学习工具在对抗性攻击下鲁棒性的框架。数据科学界已经广泛认识到,单纯为分类图像而训练的深度神经网络等简单机器学习模型非常容易被欺骗。

下图展示了《解释与利用对抗样本》,I. J. Goodfellow 等人的研究:

网络安全是一个对抗性较强的领域,用于防御攻击者的机器学习模型应当具备抗对抗性攻击的鲁棒性。因此,不仅要报告通常的性能指标,如准确率、精确度和召回率,还需要有一定的对抗鲁棒性测量。deep-pwning 框架就是一个实现这一目标的简单工具包。

准备工作

准备这个食谱时,请按照以下步骤操作:

  1. 在你的设备上安装git

  2. 使用以下命令通过 Git 下载或克隆该仓库:

git clone https://github.com/emmanueltsukerman/deep-pwning.git
  1. 安装该仓库的依赖项。

在终端中,进入仓库的根目录并运行以下命令:

pip install -r requirements.txt

如何操作…

在接下来的步骤中,你将利用 deep-pwning 对 MNIST 数字数据集上的 LeNet5 进行攻击:

  1. 从该目录向下,使用以下命令运行 MNIST 驱动程序:
python mnist_driver.py –restore_checkpoint

结果应该像这样显示:

它是如何工作的…

步骤 1中,我们创建了一个包含对抗样本的大型数据集;即,创建了 150,000 个对抗样本,几乎所有这些样本都能够欺骗 LeNet5 对数字的识别。要检查这些对抗样本,可以像这样解压输出目录中的 pickle 文件:

utils目录下,有一个名为mnist_read_pickle.py的文件,它将pickle文件作为参数传入。运行它会显示一个对抗样本。以下图像让 LeNet5 误以为它看到的是数字 1:

deep-pwning 框架设计为模块化,因此用户可以插入并修改各个部分以满足自己的需求。例如,替换 MNIST 数据集和 LeNet5 架构。

基于深度学习的自动化软件漏洞检测系统

信息安全专家通常能够识别出潜在可利用的代码片段。然而,这项工作是繁重且成本高昂的,并且可能不足以确保程序的安全性。深度学习相较于传统机器学习的一个重要优势是可以自动发现特征。这使得我们能够减少对漏洞领域人类专家的依赖,并且能产生更有效的系统。在本教程中,我们将使用一个修改版的*VulDeePecker : *基于深度学习的漏洞检测系统 (arxiv.org/pdf/1801.01681.pdf),自动检测 C/C++软件中的缓冲区错误漏洞和资源管理错误。

准备工作

本教程的准备工作包括安装pandasgensimkerastensorflowsklearn等软件包,使用pip进行安装。安装指令如下:

pip install pandas gensim keras tensorflow sklearn

此外,为了进行本教程操作,克隆 VulDeePecker 的代码库:

  1. 安装git,然后在终端运行以下命令:
git clone https://github.com/emmanueltsukerman/Deep-Learning-Based-System-for-Automatic-Detection-of-Software-Vulnerabilities.git

datasets文件夹中有两个数据集,cwe119_cgd.7zcwe399_cgd.7z。如果你想使用它们,请解压。

如何操作…

  1. 收集一个包含代码小片段的训练数据集,并将其放在datasets文件夹下。该文件夹中有两个数据集,它们的形式如下:

  1. 在你的数据集上训练和测试深度学习模型。

通过运行以下命令来完成此操作:

python vuldeepecker_train.py "path to dataset"

输出结果显示在以下截图中:

  1. 收集你希望进行预测的数据集,并将其放置在datasets文件夹下:

  1. 使用你训练好的模型通过运行以下命令来预测这些代码是否存在漏洞:
python vuldeepecker_predict.py "path to data" "path to model"

它是如何工作的…

为了让机器学习能够进行漏洞检测,你需要找到能够学习的软件程序表示方式。为此,我们使用代码小片段,并将它们转换为向量。代码小片段是一组语义相关的代码行。在步骤 1中,我们为训练收集这样的代码小片段。你可以看到三种代码小片段及其标签的图片。这里,标签为 1 表示存在漏洞,而标签为 0 表示没有漏洞。为了从所需程序中提取小片段,建议使用商业产品 Checkmarx 来提取程序切片,然后将它们组装成代码小片段。另一个数据集cwe-119与缓冲区错误漏洞相关。接下来,我们在我们的漏洞数据集上训练一个深度学习模型(步骤 2)。所使用的深度学习模型是双向长短期记忆网络BLSTM),其架构如下所示:

Bidirectional(LSTM(300), input_shape=(50, 50))
Dense(300)
LeakyReLU()
Dropout(0.5)
Dense(300)
LeakyReLU()
Dropout(0.5)
Dense(2, activation='softmax')
Adamax(lr=0.002)
'categorical_crossentropy'

请注意,训练阶段会自动将模型保存为[base-name-of-training-dataset]_model.h5。现在我们准备寻找新的漏洞。所以,我们将测试集放入datasets中(步骤 3),然后通过预测这个新数据集中的漏洞来使用我们的神经网络(步骤 4)。

第六章:自动入侵检测

入侵检测系统监控网络或一组系统,以发现恶意活动或政策违规行为。任何被捕获的恶意活动或违规行为都将被阻止或报告。在本章中,我们将设计并实现几个使用机器学习的入侵检测系统。我们将从检测垃圾邮件这一经典问题开始。然后我们将转向分类恶意 URL。接下来,我们将简要介绍如何捕获网络流量,以便解决更具挑战性的网络问题,如僵尸网络和 DDoS 检测。我们将构建一个针对内部威胁的分类器。最后,我们将解决信用卡欺诈这一依赖示例、成本敏感、极度不平衡且具有挑战性的问题。

本章包含以下内容:

  • 使用机器学习进行垃圾邮件过滤

  • 网络钓鱼 URL 检测

  • 捕获网络流量

  • 网络行为异常检测

  • 僵尸网络流量检测

  • 内部威胁检测的特征工程

  • 使用异常检测进行内部威胁检测

  • 检测 DDoS 攻击

  • 信用卡欺诈检测

  • 伪造银行票据检测

  • 使用机器学习进行广告拦截

  • 无线室内定位

技术要求

本章的技术前提如下:

  • Wireshark

  • PyShark

  • costcla

  • scikit-learn

  • pandas

  • NumPy

代码和数据集可以在github.com/PacktPublishing/Machine-Learning-for-Cybersecurity-Cookbook/tree/master/Chapter06找到。

使用机器学习进行垃圾邮件过滤

垃圾邮件(不需要的邮件)约占全球电子邮件流量的 60%。除了自 1978 年首次垃圾邮件出现以来,垃圾邮件检测软件取得的进展外,任何拥有电子邮件帐户的人都知道,垃圾邮件仍然是一个费时且昂贵的问题。在这里,我们提供一个使用机器学习进行垃圾邮件-非垃圾邮件(ham)分类的配方。

准备就绪

为本配方的准备工作包括通过pip安装scikit-learn包。命令如下:

pip install sklearn

此外,将spamassassin-public-corpus.7z解压到名为spamassassin-public-corpus的文件夹中。

如何实现...

在以下步骤中,我们构建一个用于分类垃圾邮件和非垃圾邮件的分类器:

  1. 解压spamassassin-public-corpus.7z数据集。

  2. 指定spamham目录的路径:

import os

spam_emails_path = os.path.join("spamassassin-public-corpus", "spam")
ham_emails_path = os.path.join("spamassassin-public-corpus", "ham")
labeled_file_directories = [(spam_emails_path, 0), (ham_emails_path, 1)]
  1. 为两个类别创建标签并将电子邮件读取到语料库中:
email_corpus = []
labels = []

for class_files, label in labeled_file_directories:
    files = os.listdir(class_files)
    for file in files:
        file_path = os.path.join(class_files, file)
        try:
            with open(file_path, "r") as currentFile:
                email_content = currentFile.read().replace("\n", "")
                email_content = str(email_content)
                email_corpus.append(email_content)
                labels.append(label)
        except:
            pass
  1. 对数据集进行训练-测试拆分:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    email_corpus, labels, test_size=0.2, random_state=11
)
  1. 在训练数据上训练 NLP 管道:
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import HashingVectorizer, TfidfTransformer
from sklearn import tree

nlp_followed_by_dt = Pipeline(
    [
        ("vect", HashingVectorizer(input="content", ngram_range=(1, 3))),
        ("tfidf", TfidfTransformer(use_idf=True,)),
        ("dt", tree.DecisionTreeClassifier(class_weight="balanced")),
    ]
)
nlp_followed_by_dt.fit(X_train, y_train)
  1. 在测试数据上评估分类器:
from sklearn.metrics import accuracy_score, confusion_matrix

y_test_pred = nlp_followed_by_dt.predict(X_test)
print(accuracy_score(y_test, y_test_pred))
print(confusion_matrix(y_test, y_test_pred))

以下是输出结果:

0.9761620977353993
[[291 7]
[ 13 528]]

它是如何工作的…

我们首先准备一个包含原始邮件的数据集(步骤 1),读者可以通过查看数据集来进行检查。在步骤 2中,我们指定垃圾邮件和正常邮件的路径,并为它们的目录分配标签。接着,我们将在步骤 3中读取所有邮件到一个数组中,并创建一个标签数组。接下来,我们将数据集进行训练-测试拆分(步骤 4),然后在步骤 5中为其拟合一个 NLP 管道。最后,在步骤 6中,我们测试我们的管道。我们发现准确率相当高。由于数据集相对平衡,因此无需使用特殊的评估指标来评估成功。

钓鱼 URL 检测

钓鱼网站是通过让你认为自己在一个合法网站上,从而试图获取你的账户密码或其他个人信息的网站。一些钓鱼 URL 与目标 URL 只有一个字符不同,这个字符特别选择以增加拼写错误的几率,而其他一些则利用其他渠道来生成流量。

这是一个钓鱼网站的示例,该网站通过让用户相信他们的电子邮件将被关闭,从而迫使用户提供电子邮件地址:

由于钓鱼是最成功的攻击方式之一,因此能够识别 URL 是否合法至关重要。在本食谱中,我们将构建一个机器学习模型来检测钓鱼 URL。

准备工作

本食谱的准备工作包括在pip中安装scikit-learnpandas。命令如下:

pip install sklearn pandas

此外,提取名为phishing-dataset.7z的压缩文件。

如何进行...

在接下来的步骤中,我们将读取一个特征化的 URL 数据集,并对其进行分类器训练。

  1. 从本章节的目录下载钓鱼数据集。

  2. 使用pandas读取训练和测试数据:

import pandas as pd
import os

train_CSV = os.path.join("phishing-dataset", "train.csv")
test_CSV = os.path.join("phishing-dataset", "test.csv")
train_df = pd.read_csv(train_CSV)
test_df = pd.read_csv(test_CSV)
  1. 准备钓鱼网页的标签:
y_train = train_df.pop("target").values
y_test = test_df.pop("target").values
  1. 准备特征:
X_train = train_df.values
X_test = test_df.values
  1. 训练、测试和评估分类器:
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, confusion_matrix

clf = RandomForestClassifier()
clf.fit(X_train, y_train)
y_test_pred = clf.predict(X_test)
print(accuracy_score(y_test, y_test_pred))
print(confusion_matrix(y_test, y_test_pred))

以下是输出:

0.9820846905537459
[[343 4]
[ 7 260]]

如何工作...

我们首先下载数据集,然后将其读取到数据框中(步骤 1步骤 2),以方便检查和操作。接下来,我们将数据集放入数组中,为机器学习做准备(步骤 3步骤 4)。该数据集包含了数千个钓鱼 URL 的特征向量。这里列出了 30 个特征的名称和值:

属性列名
是否具有 IP 地址{ 1,0 }has_ip
是否具有长 URL{ 1,0,-1 }long_url
是否使用缩短服务{ 0,1 }short_service
是否具有'@'符号{ 0,1 }has_at
是否双斜杠重定向{ 0,1 }double_slash_redirect
是否具有前后缀{ -1,0,1 }pref_suf
是否具有子域名{ -1,0,1 }has_sub_domain
SSL 最终状态{ -1,1,0 }ssl_state
域名注册长度{ 0,1,-1 }long_domain
网站图标{ 0,1 }favicon
是否为标准端口{ 0,1 }port
是否使用 HTTPS 令牌{ 0,1 }https_token
请求 URL{ 1,-1 }req_url
异常 URL 锚点{ -1,0,1 }url_of_anchor
标签中的链接{ 1,-1,0 }tag_links
SFH{ -1,1 }SFH
提交到邮件{ 1,0 }submit_to_email
异常 URL{ 1,0 }abnormal_url
重定向{ 0,1 }redirect
鼠标悬停{ 0,1 }mouseover
右键点击{ 0,1 }right_click
弹出窗口{ 0,1 }popup
内嵌框架{ 0,1 }iframe
域名年龄{ -1,0,1 }domain_age
DNS 记录{ 1,0 }dns_record
网络流量{ -1,0,1 }traffic
页面排名{ -1,0,1 }page_rank
Google 索引{ 0,1 }google_index
指向页面的链接{ 1,0,-1 }links_to_page
统计报告{ 1,0 }stats_report
结果{ 1,-1 }target

步骤 5 中,我们训练并测试一个随机森林分类器。准确度相当高,但根据数据集的平衡情况,可能需要考虑 FP 约束。有许多方法可以扩展此类检测器,例如添加其他特征并扩大数据集。由于大多数网站包含一些图片,图像分类器只是模型改进结果的一种方式。

捕获网络流量

捕获网络流量对于故障排除、分析、软件和通信协议开发非常重要。对于关注安全的个人来说,监控网络流量是检测恶意活动或政策违规的关键。在本教程中,我们将演示如何捕获和检查网络流量。

准备就绪

为了准备此教程,请遵循以下步骤:

  1. 安装 pyshark
pip install pyshark
  1. 安装 wireshark。最新版本可以在 www.wireshark.org/download.html 找到。

如何操作……

在接下来的步骤中,我们将使用一个名为 PyShark 的 Python 库,并结合 Wireshark 捕获和检查网络流量。

  1. 你必须将 tshark 添加到 PyShark 的配置路径中。Tshark 是 Wireshark 的命令行版本。为此,运行以下命令:
pip show pyshark

请注意数据包的位置。在该位置的 pyshark 目录中,找到文件 config.ini。编辑 tshark_pathwireshark 安装文件夹内 tshark 的路径。同样,编辑 dumpcap_pathwireshark 安装文件夹内 dumpcap 的路径。

步骤 2步骤 4 应在 Python 环境中执行。请注意,在当前版本中,pyshark 在 Jupyter notebook 中运行时可能存在一些 bug。

  1. 导入 pyshark 并指定捕获的持续时间:
import pyshark

capture_time = 20
  1. 指定文件名以输出捕获内容,to
import datetime
start = datetime.datetime.now()
end = start+datetime.timedelta(seconds=capture_time)
file_name = "networkTrafficCatpureFrom"+str(start).replace(" ", "T")+"to"+str(end).replace(" ","T")+".pcap"
  1. 捕获网络流量:
cap = pyshark.LiveCapture(output_file=file_name)
cap.sniff(timeout=capture_time)
  1. 要检查捕获内容,请在 Wireshark 中打开 pcap 文件:

工作原理……

我们从配置 tshark(Wireshark 的命令行版本)开始。完成配置后,可以通过pyshark进行访问。我们导入pyshark并指定网络捕获的持续时间(步骤 2)。由于捕获的网络流量数据可能非常庞大,因此控制持续时间很重要。接下来,我们指定输出捕获的名称,使其既唯一又容易理解(步骤 3),然后在步骤 4中,开始捕获流量。最后,在步骤 6中,我们使用 Wireshark 的图形界面来检查捕获的网络流量。在熟练的操作下,这样的网络流量有助于检测不安全的物联网设备、配置错误、异常事件、黑客攻击尝试,甚至数据泄露。

网络行为异常检测

网络行为异常检测NBAD)是对网络进行连续监控,寻找不寻常的事件或趋势。理想情况下,NBAD 程序实时跟踪关键网络特征,并在检测到表明威胁的奇异事件或趋势时生成警报。在本教程中,我们将使用机器学习构建一个 NBAD。

使用的数据集是从著名的数据集 KDD 数据集中修改而来的子集,是测试和构建 IDS 系统的标准数据集。该数据集包含在军事网络环境中模拟的各种入侵。

准备工作

本教程的准备工作包括安装scikit-learnpandasmatplotlib。命令如下:

pip install sklearn pandas matplotlib

此外,解压kddcup_dataset.7z档案。

如何做到这一点…

在接下来的步骤中,我们将利用孤立森林在 KDD 数据集中检测异常:

  1. 导入pandas并将数据集读取到数据框中:
import pandas as pd

kdd_df = pd.read_csv("kddcup_dataset.csv", index_col=None)
  1. 检查流量类型的比例:
y = kdd_df["label"].values
from collections import Counter

Counter(y).most_common()

将会观察到以下输出:

[('normal', 39247),('back', 1098),('apache2', 794),('neptune', 93),('phf', 2),('portsweep', 2),('saint', 1)]
  1. 将所有非正常观测值转换为单一类别:
def label_anomalous(text):
    """Binarize target labels into normal or anomalous."""
    if text == "normal":
        return 0
    else:
        return 1

kdd_df["label"] = kdd_df["label"].apply(label_anomalous)
  1. 获取异常数据与正常数据的比例。这是我们在孤立森林中使用的污染参数:
y = kdd_df["label"].values
counts = Counter(y).most_common()
contamination_parameter = counts[1][1] / (counts[0][1] + counts[1][1])
  1. 将所有类别特征转换为数值形式:
from sklearn.preprocessing import LabelEncoder

encodings_dictionary = dict()
for c in kdd_df.columns:
    if kdd_df[c].dtype == "object":
        encodings_dictionary[c] = LabelEncoder()
        kdd_df[c] = encodings_dictionary[c].fit_transform(kdd_df[c])
  1. 将数据集分为正常和异常观测值:
kdd_df_normal = kdd_df[kdd_df["label"] == 0]
kdd_df_abnormal = kdd_df[kdd_df["label"] == 1]
y_normal = kdd_df_normal.pop("label").values
X_normal = kdd_df_normal.values
y_anomaly = kdd_df_abnormal.pop("label").values
X_anomaly = kdd_df_abnormal.values
  1. 将数据集分为训练集和测试集:
from sklearn.model_selection import train_test_split

X_normal_train, X_normal_test, y_normal_train, y_normal_test = train_test_split(
    X_normal, y_normal, test_size=0.3, random_state=11
)
X_anomaly_train, X_anomaly_test, y_anomaly_train, y_anomaly_test = train_test_split(
    X_anomaly, y_anomaly, test_size=0.3, random_state=11
)

import numpy as np

X_train = np.concatenate((X_normal_train, X_anomaly_train))
y_train = np.concatenate((y_normal_train, y_anomaly_train))
X_test = np.concatenate((X_normal_test, X_anomaly_test))
y_test = np.concatenate((y_normal_test, y_anomaly_test))
  1. 实例化并训练一个孤立森林分类器:
from sklearn.ensemble import IsolationForest

IF = IsolationForest(contamination=contamination_parameter)
IF.fit(X_train
  1. 对正常和异常观测值进行分类评分:
decisionScores_train_normal = IF.decision_function(X_normal_train)
decisionScores_train_anomaly = IF.decision_function(X_anomaly_train)
  1. 绘制正常数据集的分数:
import matplotlib.pyplot as plt

%matplotlib inline
plt.figure(figsize=(20, 10))
_ = plt.hist(decisionScores_train_normal, bins=50)

以下图表提供了输出结果:

  1. 类似地,绘制异常观测值的分数以进行可视化检查:
plt.figure(figsize=(20, 10))
_ = plt.hist(decisionScores_train_anomaly, bins=50)

以下图表提供了输出结果:

  1. 选择一个截断点,以将异常数据与正常数据分开:
cutoff = 0
  1. 在测试集上检查此截断点:
print(Counter(y_test))
print(Counter(y_test[cutoff > IF.decision_function(X_test)]))

以下是输出结果:

Counter({0: 11775, 1: 597})
Counter({1: 595, 0: 85})

它是如何工作的…

我们首先将KDD cup数据集读取到数据框中。接下来,在步骤 2中,我们检查数据,发现大多数流量是正常的,正如预期的那样,但少量是异常的。显然,这个问题是高度不平衡的。因此,这个问题非常适合使用异常检测方法。在步骤 3步骤 5中,我们将所有非正常流量转化为一个单一类别,即异常

我们还确保计算异常值与正常观察值的比率(步骤 4),即污染参数。这是设置隔离森林灵敏度的参数之一。这个步骤是可选的,但可能会提高性能。我们在步骤 6中将数据集分为正常和异常观察值,同时将数据集分为正常和异常数据的训练集和测试集(步骤 7)。我们实例化一个隔离森林分类器,并设置其污染参数(步骤 8)。论文《Isolation Forest》中推荐使用的默认参数n_estimatorsmax_samples由 Liu 等人提出。在步骤 9步骤 10中,我们使用隔离森林的决策函数为正常训练集提供分数,然后在图表中检查结果。在步骤 11中,我们类似地为异常训练集提供分数。

知道决策函数是衡量一个点描述简单程度的指标后,我们希望通过选择一个数值截断点,将简单点与复杂点分离开来,从而获得明显的区分。通过可视化检查,建议选择在步骤 12中选定的值。

最后,我们可以使用模型进行预测并评估其性能。在步骤 13中,我们看到模型能够捕捉到大量异常,而不会触发过多的假阳性(正常流量的实例),按比例而言。

僵尸网络流量检测

僵尸网络是由被攻击的互联网设备组成的网络。僵尸网络可用于执行分布式拒绝服务攻击DDoS 攻击)、窃取数据、发送垃圾邮件,以及其他各种创意恶意用途。僵尸网络可以造成巨大的损害。例如,在写作时,快速搜索“僵尸网络”一词显示,3 天前,Electrum 僵尸网络窃取了 460 万美元的加密货币。在本教程中,我们构建一个分类器来检测僵尸网络流量。

使用的数据集是一个处理过的子集,名为CTU-13,包含了 2011 年捷克 CTU 大学捕获的僵尸网络流量。该数据集包含大量真实的僵尸网络流量,混合了正常流量和背景流量。

准备工作

本教程的准备工作包括在pip中安装scikit-learn。命令如下:

pip install sklearn

此外,解压CTU13Scenario1flowData.7z。要反序列化CTU13Scenario1flowData.pickle文件,需要使用 Python 2:

如何操作…

  1. 首先读取已序列化的数据:
import pickle

file = open('CTU13Scenario1flowData.pickle', 'rb')
botnet_dataset = pickle.load(file)
  1. 数据已分割为训练集和测试集,你只需将它们分别分配给各自的变量:
X_train, y_train, X_test, y_test = (
    botnet_dataset[0],
    botnet_dataset[1],
    botnet_dataset[2],
    botnet_dataset[3],
)
  1. 使用默认参数实例化决策树分类器:
from sklearn.tree import *

clf = DecisionTreeClassifier()
  1. 将分类器拟合到训练数据:
clf.fit(X_train, y_train)
  1. 在测试集上进行测试:
clf.score(X_test, y_test)

以下是输出:

0.9991001799640072

它是如何工作的…

我们从步骤 1开始,通过反序列化数据来加载它。数据集已经经过预处理以确保平衡,因此我们无需担心数据不平衡的问题。实际上,检测僵尸网络可能需要满足对假阳性率的限制。接下来,我们利用已经预定义的训练集-测试集划分来分割数据(步骤 2)。现在我们可以实例化分类器,将其拟合到数据上,然后进行测试(步骤 3步骤 5)。从准确率来看,我们看到它相当高。由于数据集已经平衡,我们无需担心我们的指标会产生误导。一般来说,检测僵尸网络是一个具有挑战性的任务。僵尸网络的检测难度可以通过 GameOver Zeus 僵尸网络恶意软件包来说明。该僵尸网络最初在 2007 年被发现,运营了超过三年,最终导致约 7000 万美元的资金被盗,并导致 FBI 在 2010 年逮捕了 100 多名嫌疑人。直到 2012 年 3 月,微软才宣布它已经能够关闭该僵尸网络的大部分指挥与控制(C&C)服务器。

内部威胁检测

内部威胁是雇主面临的一个复杂且日益严峻的挑战。通常定义为员工采取的任何可能对组织造成危害的行为。这些行为可能包括未经授权的数据传输或资源破坏等。内部威胁可能以各种新颖形式表现出来,动机各异,从不满的员工破坏雇主声誉,到高级持续性威胁APT)等。

卡内基梅隆大学软件工程研究所(CERT 项目)的内部风险数据库包含了最大的公开红队情景档案。该模拟通过将真实世界的内部风险案例与从防御公司秘密获得的实际中立客户结合而构建。该数据集代表了一家单一工程公司数月的流量,涵盖了互联网、电话、登录、文件夹和系统访问(dtaa.com)。模拟公司雇佣了数千名员工,每人每天平均执行 1,000 次登录活动。数据中描绘了几种威胁情景,例如泄密者、小偷和破坏者。该问题的一个显著特点是其非常低的信噪比,无论是表现为恶意用户的总数、频繁的计数,还是总体使用情况。

我们进行的分析基于 CERT 内部威胁情景(v.4.2),特别是因为它代表了一个密集的针形数据集,这意味着它具有高频次的攻击发生。

攻击的基本计划是,首先手工创建新特征,例如是否向外部人员发送了邮件或登录是否发生在非工作时间。接下来的想法是为每个用户提取一个多变量时间序列。这个时间序列将由一系列向量组成,每个向量构成一天中我们手工创建的特征发生的次数计数。因此,我们输入数据集的形状将如下所示:

(每天检查的用户数,每天检查的总特征数,时间序列中的天数)。

然后我们将展平每个用户的时间序列,并利用隔离森林来检测异常。

内部威胁检测的特征工程

通常情况下,当一个机器学习解决方案不依赖端到端的深度学习时,通过创建富有洞见和信息性的特征可以提高性能。在这个示例中,我们将为内部威胁检测构建几个有前途的新特征。

准备工作

准备工作包括在pip中安装pandas。命令如下:

pip install pandas

另外,从以下链接下载 CERT 内部威胁数据集:ftp://ftp.sei.cmu.edu/pub/cert-data/r4.2.tar.bz2。有关数据集的更多信息以及答案,请访问resources.sei.cmu.edu/library/asset-view.cfm?assetid=508099

如何做…

在接下来的步骤中,您将为 CERT 内部威胁数据集构建新特征:

  1. 导入numpypandas,并指向下载数据的位置:
import numpy as np
import pandas as pd path_to_dataset = "./r42short/"
  1. 指定.csv文件及其要读取的列:
log_types = ["device", "email", "file", "logon", "http"]
log_fields_list = [    ["date", "user", "activity"],
    ["date", "user", "to", "cc", "bcc"],
    ["date", "user", "filename"],
    ["date", "user", "activity"],
    ["date", "user", "url"],
]
  1. 我们将手工创建一些特征并对其进行编码,从而创建一个字典来跟踪这些特征。
features = 0
feature_map = {}

def add_feature(name):
    """Add a feature to a dictionary to be encoded."""
    if name not in feature_map:
        global features
        feature_map[name] = features
        features += 1
  1. 将要使用的特征添加到我们的字典中:
add_feature("Weekday_Logon_Normal")
add_feature("Weekday_Logon_After")
add_feature("Weekend_Logon")
add_feature("Logoff")

add_feature("Connect_Normal")
add_feature("Connect_After")
add_feature("Connect_Weekend")
add_feature("Disconnect")

add_feature("Email_In")
add_feature("Email_Out")

add_feature("File_exe")
add_feature("File_jpg")
add_feature("File_zip")
add_feature("File_txt")
add_feature("File_doc")
add_feature("File_pdf")
add_feature("File_other")

add_feature("url")
  1. 定义一个函数来记录被复制到可移动介质的文件类型:
def file_features(row):
    """Creates a feature recording the file extension of the file used."""
    if row["filename"].endswith(".exe"):
        return feature_map["File_exe"]
    if row["filename"].endswith(".jpg"):
        return feature_map["File_jpg"]
    if row["filename"].endswith(".zip"):
        return feature_map["File_zip"]
    if row["filename"].endswith(".txt"):
        return feature_map["File_txt"]
    if row["filename"].endswith(".doc"):
        return feature_map["File_doc"]
    if row["filename"].endswith(".pdf"):
        return feature_map["File_pdf"]
    else:
        return feature_map["File_other"]
  1. 定义一个函数来识别员工是否向非公司邮箱发送了邮件:
def email_features(row):
    """Creates a feature recording whether an email has been sent externally."""
    outsider = False
    if not pd.isnull(row["to"]):
        for address in row["to"].split(";"):
            if not address.endswith("dtaa.com"):
                outsider = True

    if not pd.isnull(row["cc"]):
        for address in row["cc"].split(";"):
            if not address.endswith("dtaa.com"):
                outsider = True

    if not pd.isnull(row["bcc"]):
        for address in row["bcc"].split(";"):
            if not address.endswith("dtaa.com"):
                outsider = True
    if outsider:
        return feature_map["Email_Out"]
    else:
        return feature_map["Email_In"]
  1. 定义一个函数来记录员工是否在非工作时间使用可移动介质:
def device_features(row):
    """Creates a feature for whether the user has connected during normal hours or otherwise."""
    if row["activity"] == "Connect":
        if row["date"].weekday() < 5:
            if row["date"].hour >= 8 and row["date"].hour < 17:
                return feature_map["Connect_Normal"]
            else:
                return feature_map["Connect_After"]
        else:
            return feature_map["Connect_Weekend"]
    else:
        return feature_map["Disconnect"]
  1. 定义一个函数来记录员工是否在非工作时间登录到计算机:
def logon_features(row):
    """Creates a feature for whether the user logged in during normal hours or otherwise."""
    if row["activity"] == "Logon":
        if row["date"].weekday() < 5:
            if row["date"].hour >= 8 and row["date"].hour < 17:
                return feature_map["Weekday_Logon_Normal"]
            else:
                return feature_map["Weekday_Logon_After"]
        else:
            return feature_map["Weekend_Logon"]
    else:
        return feature_map["Logoff"]
  1. 我们不会利用员工访问的 URL 中包含的信息:
def http_features(row):
    """Encodes the URL visited."""
    return feature_map["url"]
  1. 我们仅保留事件发生的日期,而不是完整的时间戳:
def date_to_day(row):
    """Converts a full datetime to date only."""
    day_only = row["date"].date()
    return day_only
  1. 我们循环遍历包含日志的.csv文件,并将它们读入 pandas 数据框中:
log_feature_functions = [
    device_features,
    email_features,
    file_features,
    logon_features,
    http_features,
]
dfs = []
for i in range(len(log_types)):
    log_type = log_types[i]
    log_fields = log_fields_list[i]
    log_feature_function = log_feature_functions[i]
    df = pd.read_csv(
        path_to_dataset + log_type + ".csv", usecols=log_fields, index_col=None
    )
  1. date数据转换为pandas时间戳:
    date_format = "%m/%d/%Y %H:%M:%S"
    df["date"] = pd.to_datetime(df["date"], format=date_format)
  1. 创建上述定义的新特征,然后丢弃除日期、用户和我们的新特征之外的所有特征:
    new_feature = df.apply(log_feature_function, axis=1)
    df["feature"] = new_feature

    cols_to_keep = ["date", "user", "feature"]
    df = df[cols_to_keep]
  1. 将日期转换为只有一天:
    df["date"] = df.apply(date_to_day, axis=1)

    dfs.append(df)
  1. 将所有数据框连接成一个,并按date排序:
joint = pd.concat(dfs)
joint = joint.sort_values(by="date")

工作原理...

首先导入pandasnumpy并创建一个指向数据集的变量(步骤 1)。CERT 提供了多个数据集。4.2 版本之所以与众不同,是因为它是一个密集的“针”数据集,意味着它比其他数据集有更高的内部威胁发生率。由于数据集非常庞大,因此在实验阶段,至少要对其进行过滤和下采样,以便更方便地处理数据,因此我们在步骤 2中这样做。在接下来的步骤中,我们将手动设计一些特征,认为这些特征有助于我们的分类器识别内部威胁。在步骤 3中,我们创建一个便捷的函数来编码特征,以便一个字典可以跟踪这些特征。我们在步骤 4中提供将要添加的特征名称。在步骤 5中,我们创建一个特征,用于跟踪复制到可移动介质中的文件类型。推测这可能表明数据泄露犯罪行为。在步骤 6中,我们创建一个特征,跟踪员工是否曾给外部实体发送过电子邮件。我们又创建了一个特征,用于跟踪员工是否在非工作时间使用过可移动存储设备(步骤 7)。

一个附加特征用于跟踪员工是否在非工作时间登录过设备(步骤 8)。为了简化处理,我们没有利用员工访问的 URL(步骤 9),尽管这些可能暗示恶意行为。

接下来,我们通过仅使用日期(步骤 10),而不是在特征化数据中使用完整的时间戳,来简化数据。在步骤 11中,我们将数据读取到一个 pandas 数据框中。然后,在步骤 12中,我们编辑当前的日期格式,以适应 pandas,并收集所有新的特征,同时丢弃旧的特征(步骤 13)。在步骤 14中,我们将数据转换为一个时间序列,其增量为单天。最后,在步骤 15中,我们将所有数据汇总到一个大型的已排序数据框中。我们现在已经完成了特征工程阶段的第一次迭代。为了提升性能并添加特征,你可以朝着多个方向努力。这些方向包括观察电子邮件文本中的负面情绪,并使用心理测量学分析个性。

使用异常检测来识别内部威胁

在设计出有前景的新特征后,我们的下一步是进行训练集和测试集划分,将数据处理成方便的时间序列形式,然后进行分类。我们的训练集和测试集将是数据集的两个时间半部分。通过这种方式,我们可以轻松确保训练输入的形状与测试输入的形状相同,从而避免在评估中作弊。

准备工作

这个配方的准备工作包括在pip中安装scikit-learnpandasmatplotlib。命令如下:

pip install sklearn pandas matplotlib

在准备这个配方时,你需要加载前一个配方中的数据框(或者直接从前一个配方的结束部分继续)。

如何操作...

在接下来的步骤中,你将把特征化数据转换为时间序列集合,并使用孤立森林检测犯罪:

  1. 列出所有威胁行为者,为创建标签做准备:
threat_actors = [
    "AAM0658",
    "AJR0932",
    "BDV0168",
    <snip>
    "MSO0222",
]
  1. 然后我们对日期进行索引:
start_date = joint["date"].iloc[0]
end_date = joint["date"].iloc[-1]
time_horizon = (end_date - start_date).days + 1

def date_to_index(date):
    """Indexes dates by counting the number of days since the starting date of the dataset."""
    return (date - start_date).days
  1. 定义一个函数来提取给定用户的时间序列信息:
def extract_time_series_by_user(user_name, df):
    """Filters the dataframe down to a specific user."""
    return df[df["user"] == user_name]
  1. 定义一个函数来向量化用户的时间序列信息:
def vectorize_user_time_series(user_name, df):
    """Convert the sequence of features of a user to a vector-valued time series."""
    user_time_series = extract_time_series_by_user(user_name, df)
    x = np.zeros((len(feature_map), time_horizon))
    event_date_indices = user_time_series["date"].apply(date_to_index).to_numpy()
    event_features = user_time_series["feature"].to_numpy()
    for i in range(len(event_date_indices)):
        x[event_features[i], event_date_indices[i]] += 1
    return x
  1. 定义一个函数来向量化所有用户特征的时间序列:
def vectorize_dataset(df):
    """Takes the dataset and featurizes it."""
    users = set(df["user"].values)
    X = np.zeros((len(users), len(feature_map), time_horizon))
    y = np.zeros((len(users)))
    for index, user in enumerate(users):
        x = vectorize_user_time_series(user, df)
        X[index, :, :] = x
        y[index] = int(user in threat_actors)
    return X, y
  1. 向量化数据集:
X, y = vectorize_dataset(joint)
  1. 对向量化数据进行训练-测试集划分:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
  1. 重新调整向量化数据的形状:
X_train_reshaped = X_train.reshape(
    [X_train.shape[0], X_train.shape[1] * X_train.shape[2]]
)
X_test_reshaped = X_test.reshape([X_test.shape[0], X_test.shape[1] * X_test.shape[2]])
  1. 将训练集和测试集数据拆分为威胁和非威胁子集:
X_train_normal = X_train_reshaped[y_train == 0, :]
X_train_threat = X_train_reshaped[y_train == 1, :]
X_test_normal = X_test_reshaped[y_test == 0, :]
X_test_threat = X_test_reshaped[y_test == 1, :]
  1. 定义并实例化孤立森林分类器:
from sklearn.ensemble import IsolationForest

contamination_parameter = 0.035
IF = IsolationForest(
    n_estimators=100, max_samples=256, contamination=contamination_parameter
)
  1. 将孤立森林分类器拟合到训练数据:
IF.fit(X_train_reshaped)
  1. 绘制训练数据中正常子集的决策分数:
normal_scores = IF.decision_function(X_train_normal)
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(8, 4), dpi=600, facecolor="w", edgecolor="k")

normal = plt.hist(normal_scores, 50, density=True)

plt.xlim((-0.2, 0.2))
plt.xlabel("Anomaly score")
plt.ylabel("Percentage")
plt.title("Distribution of anomaly score for non threats")

请查看以下截图:

  1. 对训练数据中的威胁行为者执行相同操作:
anomaly_scores = IF.decision_function(X_train_threat)
fig = plt.figure(figsize=(8, 4), dpi=600, facecolor="w", edgecolor="k")

anomaly = plt.hist(anomaly_scores, 50, density=True)

plt.xlim((-0.2, 0.2))
plt.xlabel("Anomaly score")
plt.ylabel("Percentage")
plt.title("Distribution of anomaly score for threats") 

请查看以下截图:

  1. 选择一个截断分数:
cutoff = 0.12
  1. 观察截断在训练数据上的结果:
from collections import Counter

s = IF.decision_function(X_train_reshaped)
print(Counter(y_train[cutoff > s]))

以下是输出结果:

Counter({0.0: 155, 1.0: 23})
  1. 测量截断选择在测试集上的结果:
s = IF.decision_function(X_test_reshaped)
print(Counter(y_test[cutoff > s]))

以下是输出结果:

Counter({0.0: 46, 1.0: 8})

它是如何工作的…

在前面的食谱中完成特征工程阶段后,我们继续创建了一个模型。在第 1 步中,我们列出了所有的威胁行为者,为接下来的步骤做准备。在第 2 步中,我们为日期创建了索引,使得0对应起始日期,1对应第二天,依此类推。在随后的第 3 步第 5 步中,我们定义了函数来读取整个数据集的时间序列,将其过滤到每个用户,然后为每个用户向量化时间序列。接着我们向量化了数据集(第 6 步),并进行了训练-测试集划分(第 7 步)。我们在第 8 步中重新调整了数据形状,以便能够将其输入到孤立森林分类器中。我们进一步将数据拆分为良性和威胁子集(第 9 步),以便调整我们的参数。在第 10 步中,我们实例化了孤立森林分类器,然后在第 11 步中将其拟合到数据上。对于我们的污染参数,我们使用了一个值,对应威胁与良性行为者的比例。

在接下来的三步(第 12 步 - 第 14 步)中,我们检查了孤立森林在良性和威胁行为者上的决策分数,并通过检查得出结论,截断值 0.12 能够检测到大比例的威胁行为者,而不会标记太多良性行为者。最后,在第 15 步第 16 步中评估我们的性能时,我们发现有一些假阳性,但也检测到了相当数量的内部威胁。由于比例不是很高,因此分类器对于告知分析员潜在威胁非常有帮助。

检测 DDoS

DDoS,即分布式拒绝服务攻击,是一种攻击方式,其中来自不同来源的流量洪水般涌向目标,导致服务中断。DDoS 攻击有许多类型,通常分为三大类:应用层攻击、协议攻击和流量攻击。目前,很多 DDoS 防御仍是手动进行的。通过识别并阻止特定的 IP 地址或域名来进行防御。随着 DDoS 攻击的机器人变得越来越复杂,这种方法正在逐渐过时。机器学习为此提供了一个有前景的自动化解决方案。

我们将使用的数据集是对 CSE-CIC-IDS2018、CICIDS2017 和 CIC DoS 数据集(2017 年)的子采样。它由 80%的正常流量和 20%的 DDoS 流量组成,以代表更为现实的正常流量与 DDoS 流量的比例。

准备工作

本配方的准备工作包括在pip中安装几个包,分别是scikit-learnpandas。命令如下:

pip install sklearn pandas

为了准备这个配方,提取归档文件ddos_dataset.7z

如何实现…

在接下来的步骤中,我们将训练一个随机森林分类器来检测 DDoS 流量:

  1. 导入pandas并指定您将在代码中读取的列的数据类型:
import pandas as pd

features = [
    "Fwd Seg Size Min",
    "Init Bwd Win Byts",
    "Init Fwd Win Byts",
    "Fwd Seg Size Min",
    "Fwd Pkt Len Mean",
    "Fwd Seg Size Avg",
    "Label",
    "Timestamp",
]
dtypes = {
    "Fwd Pkt Len Mean": "float",
    "Fwd Seg Size Avg": "float",
    "Init Fwd Win Byts": "int",
    "Init Bwd Win Byts": "int",
    "Fwd Seg Size Min": "int",
    "Label": "str",
}
date_columns = ["Timestamp"]
  1. 读取包含数据集的.csv文件:
df = pd.read_csv("ddos_dataset.csv", usecols=features, dtype=dtypes,parse_dates=date_columns,index_col=None)
  1. 按日期对数据进行排序:
df2 = df.sort_values("Timestamp")
  1. 删除日期列,因为它不再需要:
df3 = df2.drop(columns=["Timestamp"])
  1. 将数据分割为训练集和测试集,分别由数据的前 80%和后 20%组成:
l = len(df3.index)
train_df = df3.head(int(l * 0.8))
test_df = df3.tail(int(l * 0.2))
  1. 准备标签:
y_train = train_df.pop("Label").values
y_test = test_df.pop("Label").values
  1. 准备特征向量:
X_train = train_df.values
X_test = test_df.values
  1. 导入并实例化一个随机森林分类器:
from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier(n_estimators=50)
  1. 将随机森林模型拟合到训练数据,并在测试数据上进行评分:
clf.fit(X_train, y_train)
clf.score(X_test, y_test)

以下是输出结果:

0.83262

它是如何工作的…

由于数据集较大,即便是导入它也会消耗大量计算资源。因此,我们在步骤 1中通过指定我们认为最有前景的特征子集以及记录它们的数据类型来开始操作,这样我们就不需要后续再转换它们。然后,在步骤 2中,我们将数据读取到数据框中。在步骤 34中,我们按日期对数据进行排序,因为问题要求能够预测未来的事件,并且随后删除日期列,因为我们不再需要它。在接下来的两步中,我们进行训练-测试数据集划分,同时考虑到时间进展。然后,我们在步骤 89中实例化、拟合并测试一个随机森林分类器。根据应用场景,得到的准确性是一个不错的起点。为了提升性能,一个有前景的方向是考虑源 IP 和目的 IP。直观来说,连接的来源应该对它是否属于 DDoS 攻击有重要影响。

信用卡欺诈检测

信用卡公司必须监控欺诈交易,以避免客户被错误收费。这样的数据非常不平衡,我们在本章中将使用的数据集,其中欺诈交易仅占总交易的 0.172%。它只包含数字输入变量,这些变量是通过 PCA 变换得到的,还有TimeAmount特征。Time特征包含每笔交易与数据集中第一笔交易之间经过的秒数。Amount特征是交易金额,这是我们将在成本敏感学习中使用的一个特征。Class特征是响应参数,在欺诈情况下,其值为1,否则为0

那么什么是示例相关的、成本敏感的学习呢?考虑每种分类类型相关的成本。如果程序没有识别出欺诈交易,钱就会被浪费,并且持卡人必须获得全额退款。如果程序认为支付是欺诈性的,交易将被停止。在这种情况下,由于需要联系持卡人,且卡需要被替换(如果交易被正确标记为欺诈),或者重新激活(如果交易实际上是合法的),就会产生行政成本。为了简化起见,假设行政成本总是相同的。如果系统认为交易是有效的,那么交易将自动接受,并且不会收取费用。这就导致了每种预测场景相关的以下成本:

欺诈 y = 1良性 y = 0
预测的欺诈 y_pred = 1真阳性成本 = 行政成本假阳性成本 = 行政成本
预测的良性 y_pred = 0假阴性成本 = 交易金额真阴性成本 = $0

与大多数场景不同,我们的兴趣在于最小化总成本,基于上述考虑,而不是准确性、精确度或召回率。

准备工作

为了准备这个配方,需要在pip中安装scikit-learnpandasmatplotlib,以及一个名为costcla的新包。命令如下:

pip install sklearn pandas matplotlib costcla

为了准备这个配方,从www.kaggle.com/mlg-ulb/creditcardfraud/downloads/creditcardfraud.zip/3下载信用卡交易数据集(开放数据库许可证)。

如何操作……

在接下来的步骤中,我们将使用costcla库在信用卡交易数据上构建一个示例相关的、成本敏感的分类器:

  1. 导入pandas并将与交易相关的数据读取到数据框中:
import pandas as pd

fraud_df = pd.read_csv("FinancialFraudDB.csv", index_col=None)
  1. 正例和负例设置成本:
card_replacement_cost = 5
customer_freeze_cost = 3
  1. 定义一个对应于图表的成本矩阵:
import numpy as np

cost_matrix = np.zeros((len(fraud_df.index), 4))
cost_matrix[:, 0] = customer_freeze_cost * np.ones(len(fraud_df.index))
cost_matrix[:, 1] = fraud_df["Amount"].values
cost_matrix[:, 2] = card_replacement_cost * np.ones(len(fraud_df.index))
  1. 创建标签和特征矩阵:
y = fraud_df.pop("Class").values
X = fraud_df.values
  1. 创建训练集和测试集的划分:
from sklearn.model_selection import train_test_split

sets = train_test_split(X, y, cost_matrix, test_size=0.25, random_state=11)
X_train, X_test, y_train, y_test, cost_matrix_train, cost_matrix_test = sets
  1. 导入决策树,将其拟合到训练数据上,然后在测试集上进行预测:
from sklearn import tree

y_pred_test_dt = tree.DecisionTreeClassifier().fit(X_train, y_train).predict(X_test)
  1. 导入成本敏感决策树,将其拟合到训练数据上,然后在测试集上进行预测:
from costcla.models import CostSensitiveDecisionTreeClassifier

y_pred_test_csdt = CostSensitiveDecisionTreeClassifier().fit(X_train, y_train, cost_matrix_train).predict(X_test)
  1. 计算两个模型的节省得分:
from costcla.metrics import savings_score

print(savings_score(y_test, y_pred_test_dt, cost_matrix_test))
print(savings_score(y_test, y_pred_test_csdt, cost_matrix_test))

以下是输出结果:

0.5231523713991505 0.5994028394464614

它是如何工作的…

第一步是简单地加载数据。在第 2 步中,我们根据更换信用卡的预期成本设置了行政成本。此外,我们还估算了冻结客户银行操作直到所有交易被验证的商业成本。在实践中,你应该获取一个准确的数字,适合具体的信用卡公司或业务用例。使用我们定义的参数,在第 3 步中,我们定义了一个成本矩阵,考虑了更换信用卡的行政成本、冻结客户带来的业务中断等因素。在第 4 步第 5 步中,我们进行数据的训练-测试拆分。接下来,我们想看看这个依赖于示例的、成本敏感的分类器与普通分类器相比表现如何。为此,我们实例化一个简单的分类器,进行训练,并在第 6 步中使用它对测试集进行预测,然后在第 7 步中使用costcla库中的成本敏感随机森林模型进行相同的操作。最后,在第 8 步中,我们利用costcla中的savings_score函数,基于成本矩阵计算使用y_predy_true的节省成本。数字越高,节省的成本越大。因此,我们可以看到,成本敏感的随机森林模型优于普通模型。

伪造钞票检测

伪造货币是未经国家或政府合法批准的货币,通常是为了模仿合法货币并欺骗其使用者。在这个教程中,你将训练一个机器学习分类器来区分真实和伪造的钞票。

准备中

本教程的准备工作包括在pip中安装scikit-learnpandas。命令如下:

pip install sklearn pandas

在准备本教程时,从 UCI 机器学习库下载钞票鉴定数据集:archive.ics.uci.edu/ml/datasets/banknote+authentication

如何操作...

在接下来的步骤中,你将下载一个标注过的伪造和合法钞票数据集,并构建一个分类器来检测伪造货币:

  1. 获取真实和伪造的钞票标注数据集。

  2. 使用pandas读取钞票数据集:

import pandas as pd

df = pd.read_csv("data_banknote_authentication.txt", header=None)
df.columns = ["0", "1", "2", "3", "label"]

以下是输出结果:

feature 1 feature 2 feature 3 feature 4 label
0 3.62160 8.6661 -2.8073 -0.44699 0
1 4.54590 8.1674 -2.4586 -1.46210 0
2 3.86600 -2.6383 1.9242 0.10645 0
3 3.45660 9.5228 -4.0112 -3.59440 0
4 0.32924 -4.4552 4.5718 -0.98880 0
  1. 创建训练-测试拆分:
from sklearn.model_selection import train_test_split

df_train, df_test = train_test_split(df)
  1. 将特征和标签收集到数组中:
y_train = df_train.pop("label").values
X_train = df_train.values
y_test = df_test.pop("label").values
X_test = df_test.values
  1. 实例化一个随机森林分类器:
from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
  1. 训练并测试分类器:
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test))

以下是输出结果:

0.9825072886297376

它是如何工作的...

解决伪造问题的最大潜力在于获取大量的图像数据集并使用深度学习技术。然而,在数据集相对较小的情况下(如本案例所示),特征工程是必不可少的。我们通过加载并读取数据集到 pandas 中来开始解决问题(步骤 1步骤 2)。在这个数据集的情况下,使用了小波变换工具从图像中提取特征。接下来,在步骤 3步骤 4 中,我们将数据进行训练-测试分割并汇总成数组。最后,在步骤 5步骤 6 中,我们对数据集进行了基础分类器的训练和测试。高达 98% 的得分表明,从该数据集中提取的特征确实能够区分真实与伪造的钞票。

使用机器学习进行广告屏蔽

广告屏蔽是指在网页浏览器或应用程序中移除或更改在线广告。在这个食谱中,你将利用机器学习检测广告,以便能够屏蔽广告,畅快无忧地浏览!

准备工作

准备这个食谱时,需要在 pip 中安装 scikit-learnpandas。命令如下:

pip install sklearn pandas

为了准备这个食谱,从 UCI 机器学习库下载互联网广告数据集:archive.ics.uci.edu/ml/datasets/internet+advertisements

如何实现……

以下步骤展示了如何使用机器学习实现广告屏蔽:

  1. 收集互联网广告的数据集。

  2. 使用 pandas 导入数据到数据框中:

import pandas as pd

df = pd.read_csv("ad.data", header=None)
df.rename(columns={1558: "label"}, inplace=True)
  1. 数据存在脏数据问题,即有缺失值。让我们找出所有缺失值的行:
improper_rows = []
for index, row in df.iterrows():
    for col in df.columns:
        val = str(row[col]).strip()
        if val == "?":
            improper_rows.append(index)
  1. 在当前的情况下,删除缺失值的行是合理的,如下代码所示:
df = df.drop(df.index[list(set(improper_rows))])
  1. 将标签转换为数值形式:
def label_to_numeric(row):
    """Binarize the label."""
    if row["label"] == "ad.":
        return 1
    else:
        return 0

df["label"] = df.apply(label_to_numeric, axis=1)
  1. 将数据分为训练数据和测试数据:
from sklearn.model_selection import train_test_split

df_train, df_test = train_test_split(df)
  1. 将数据分配到特征数组和标签数组中:
y_train = df_train.pop("label").values
y_test = df_test.pop("label").values
X_train = df_train.values
X_test = df_test.values
  1. 实例化一个随机森林分类器并进行训练:
from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
clf.fit(X_train, y_train)
  1. 在测试数据上对分类器进行评分:
clf.score(X_test, y_test)

以下是输出结果:

0.9847457627118644

它是如何工作的……

我们通过导入数据集来开始阻止不必要广告的步骤。我们在这个食谱中使用的数据已经经过了特征工程处理。在步骤 2 中,我们将数据导入数据框。查看数据,我们发现它由 1,558 个数值特征和一个广告或非广告标签组成:

特征编码了图像的几何形状、URL 中的句子、图像的 URL、alt 文本、锚文本和靠近锚文本的单词。我们的目标是预测图像是否为广告(ad)或不是(non-ad)。我们通过在步骤3 和4中删除缺失值的行来清理数据。通常,使用其他技术来填补缺失值是有意义的,比如使用平均值或最常见的值。继续到步骤5,我们将目标转换为数字形式。然后,在步骤6 和7中,我们将数据进行训练集和测试集的拆分,为学习做好准备。最后,在步骤8 和9中,我们在数据上训练并测试一个基本分类器。结果表明,这些特征确实提供了很高的区分能力。

最近的方法利用深度学习处理屏幕图像来应对广告。这个方法非常有前景,但由于深度学习对对抗性攻击的敏感性,到目前为止并未成功。随着对抗攻击的鲁棒性在该领域的提升,基于深度学习的广告拦截器可能会变得普及。

无线室内定位

黑客停在某个住宅外,恶意入侵他们的网络的故事堪称传奇。虽然这些故事可能夸大了此情景的易得性和动机,但在许多情况下,最佳做法是仅允许家中的用户,或者在企业环境中,仅允许特定区域的用户拥有指定的网络权限。在这个案例中,您将利用机器学习基于 Wi-Fi 信号来定位一个实体。我们将使用的数据集是在室内空间收集的,数据通过观察智能手机上可见的七个 Wi-Fi 信号的信号强度获得。四个房间中的一个是决策因素。

准备工作

本案例的准备工作包括安装 scikit-learnpandas。在您的 Python 环境中,运行以下命令:

pip install sklearn pandas

为了准备本案例,下载 UCI 机器学习库中的无线室内定位数据集:archive.ics.uci.edu/ml/datasets/Wireless+Indoor+Localization.

如何操作…

要利用机器学习基于 Wi-Fi 信号定位一个实体,请按照以下步骤操作:

  1. 从感兴趣区域的不同位置收集 Wi-Fi 信号强度的数据集。

  2. 使用 pandas 将数据加载到数据框中:

import pandas as pd

df = pd.read_csv("wifi_localization.txt", sep="\t", header=None)
df = df.rename(columns={7: "room"})
  1. 将数据框分割为训练集和测试集:
from sklearn.model_selection import train_test_split

df_train, df_test = train_test_split(df)
  1. 将特征和标签分配到数组中:
y_train = df_train.pop("room").values
y_test = df_test.pop("room").values
X_train = df_train.values
X_test = df_test.values
  1. 实例化一个随机森林分类器:
from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
  1. 将分类器拟合到训练数据上:
clf.fit(X_train, y_train)
  1. 在测试数据集上进行预测并打印出混淆矩阵:
y_pred = clf.predict(X_test)
from sklearn.metrics import confusion_matrix

print(confusion_matrix(y_test, y_pred))

以下输出显示了我们的混淆矩阵:

[[124   0   0   0]
 [  0 124   4   0]
 [  0   2 134   0]
 [  1   0   0 111]]

工作原理…

第一步 是从感兴趣区域的不同位置收集 Wi-Fi 信号强度的数据集。这是一个相对容易完成的任务,只需要带着启用 GPS 功能的手机走遍一个房间,并运行一个脚本记录 Wi-Fi 的信号强度。在 第二步 中,我们将数据读取到数据框中,然后将目标列重命名为 room,这样我们就知道它指的是什么。接下来,在 第三步 中,我们将数据进行训练测试集拆分,为学习做准备。我们将特征和标签拆分成数组(第四步)。最后,在 第五步 和第六步 中,我们训练并测试一个基本的分类器。观察到模型的表现非常优秀。这表明,基于设备能够接收到的 Wi-Fi 信号强度进行定位并不是一项困难的任务,只要该区域已经被预先学习过。