Python取证 - 快速指南



Python取证 - 简介

Python是一种通用编程语言,具有简单易读的代码,专业开发人员和新手程序员都易于理解。Python包含许多可与任何堆栈框架一起使用的实用库。许多实验室依靠Python来构建预测的基本模型并运行实验。它还有助于控制关键的操作系统。

Python具有内置的功能来支持数字调查并在调查期间保护证据的完整性。在本教程中,我们将解释在数字或计算取证中应用Python的基本概念。

什么是计算取证?

计算取证是一个新兴的研究领域。它处理使用数字方法解决取证问题。它利用计算科学来研究数字证据。

计算取证涵盖广泛的学科,其对象、物质和过程主要基于模式证据,例如工具痕迹、指纹、鞋印、文件等,还包括生理和行为模式、DNA以及犯罪现场的数字证据。

下图显示了计算取证涵盖的广泛学科。

Computational Forensics

计算取证借助于一些算法实现。这些算法用于信号和图像处理、计算机视觉和图形学。它还包括数据挖掘、机器学习和机器人技术。

计算取证涉及多种数字方法。简化取证中所有数字方法的最佳解决方案是使用Python这样的通用编程语言。

Python取证 - Python的安装

由于我们需要Python来进行计算取证的所有活动,让我们一步一步地了解如何安装它。

步骤1 - 访问https://www.pythonlang.cn/downloads/并根据系统上的操作系统下载Python的安装文件。

Download Installation Files

步骤2 - 下载软件包/安装程序后,单击exe文件以启动安装过程。

Start Installation

安装完成后,您将看到以下屏幕。

Installation Completed

步骤3 - 下一步是在系统中设置Python的环境变量。

Set Environment Variables

步骤4 - 设置环境变量后,在命令提示符下键入命令“python”以验证安装是否成功。

如果安装成功,您将在控制台上获得以下输出。

Installation Output

Python取证 - Python概述

Python编写的代码看起来与其他传统编程语言(如C或Pascal)编写的代码非常相似。也有人说Python的语法大量借鉴了C语言。这包括许多与C语言类似的Python关键字。

Python包含条件和循环语句,可用于准确地提取取证数据。为了进行流程控制,它提供了if/elsewhile以及一个高级for语句,该语句循环遍历任何“可迭代”对象。

if a < b: 
   max = b 
else: 
   max = a

Python与其他编程语言的主要区别在于它使用了动态类型。它使用引用对象的变量名。这些变量不需要声明。

数据类型

Python包含一组内置数据类型,例如字符串、布尔值、数字等。还有一些不可变类型,这意味着在执行过程中无法更改的值。

Python还具有复合内置数据类型,包括元组(不可变数组)、列表字典(哈希表)。所有这些都用于数字取证中存储收集证据时的值。

第三方模块和包

Python支持模块和/或包的组,也称为第三方模块(相关代码组合在一个源文件中)用于组织程序。

Python包含一个广泛的标准库,这是它在计算取证中流行的主要原因之一。

Python代码的生命周期

  • 首先,当您执行Python代码时,解释器会检查代码是否存在语法错误。如果解释器发现任何语法错误,则会立即将其显示为错误消息。

  • 如果没有语法错误,则代码会被编译以生成字节码并发送到PVM(Python虚拟机)。

  • PVM检查字节码是否存在任何运行时或逻辑错误。如果PVM发现任何运行时错误,则会立即将其报告为错误消息。

  • 如果字节码没有错误,则代码将被处理,并获得其输出。

下图以图形方式显示了Python代码如何首先被解释以生成字节码,以及字节码如何被PVM处理以生成输出。

Python Code Life Cycle

Python取证 - 基本取证应用

为了根据取证指南创建应用程序,了解并遵循其命名约定和模式非常重要。

命名约定

在开发Python取证应用程序期间,将在下表中描述要遵循的规则和约定。

常量 使用下划线分隔的大写字母 HIGH_TEMPERATURE
局部变量名 使用驼峰命名法的小写字母(下划线可选) currentTemperature
全局变量名 使用gl作为前缀,然后使用驼峰命名法的小写字母(下划线可选) gl_maximumRecordedTemperature
函数名 使用驼峰命名法的大写字母(下划线可选),并使用主动语态 ConvertFarenheitToCentigrade(...)
对象名 使用ob_作为前缀,然后使用驼峰命名法的小写字母 ob_myTempRecorder
模块 下划线后跟使用驼峰命名法的小写字母 _tempRecorder
类名 使用class_作为前缀,然后使用驼峰命名法,并保持简短 class_TempSystem

让我们以一个场景来了解命名约定在计算取证中的重要性。假设我们有一个哈希算法,通常用于加密数据。单向哈希算法将输入作为二进制数据的流;这可以是密码、文件、二进制数据或任何数字数据。然后,哈希算法会生成一个关于输入中接收到的数据的消息摘要(md)。

实际上不可能创建一个新的二进制输入来生成给定的消息摘要。即使二进制输入数据的单个位发生更改,也会生成一个与之前不同的唯一消息。

示例

查看以下遵循上述约定的示例程序。

import sys, string, md5   # necessary libraries
print "Please enter your full name"
line = sys.stdin.readline()
line = line.rstrip()
md5_object = md5.new()
md5_object.update(line)
print md5_object.hexdigest()   # Prints the output as per the hashing algorithm i.e. md5
exit

上述程序产生以下输出。

Naming Convention Example

在此程序中,Python脚本接受输入(您的全名)并根据md5哈希算法将其转换为相应的格式。它加密数据并根据需要保护信息。根据取证指南,证据或任何其他证明的名称可以以这种模式进行保护。

Python取证 - 哈希函数

哈希函数定义为将大量数据映射到具有指定长度的固定值的函数。此函数确保相同的输入产生相同的输出,这实际上定义为哈希值。哈希值包含具有特定信息的特征。

此函数实际上无法反转。因此,任何第三方攻击(如暴力破解攻击)实际上都是不可能的。此外,这种算法称为单向加密算法

理想的加密哈希函数具有四个主要属性 -

  • 必须易于计算任何给定输入的哈希值。
  • 必须难以从其哈希值生成原始输入。
  • 必须难以修改输入而不更改哈希值。
  • 必须难以找到两个具有相同哈希值的不同的输入。

示例

考虑以下示例,它有助于使用十六进制格式的字符匹配密码。

import uuid
import hashlib
  
def hash_password(password):
   # userid is used to generate a random number
   salt = uuid.uuid4().hex #salt is stored in hexadecimal value
   return hashlib.sha256(salt.encode() + password.encode()).hexdigest() + ':' + salt
     
def check_password(hashed_password, user_password):
   # hexdigest is used as an algorithm for storing passwords
   password, salt = hashed_password.split(':')
   return password == hashlib.sha256(salt.encode()
      + user_password.encode()).hexdigest()

new_pass = raw_input('Please enter required password ')
hashed_password = hash_password(new_pass)
print('The string to store in the db is: ' + hashed_password)
old_pass = raw_input('Re-enter new password ')

if check_password(hashed_password, old_pass):
   print('Yuppie!! You entered the right password')
else:
   print('Oops! I am sorry but the password does not match')

流程图

我们借助以下流程图解释了此程序的逻辑 -

Hash Function Flowchart

输出

我们的代码将产生以下输出 -

Hash Function Output

两次输入的密码与哈希函数匹配。这确保了两次输入的密码是准确的,这有助于收集有用的数据并以加密格式保存它们。

Python取证 - 破解加密

在本章中,我们将学习如何破解在分析和证据期间获取的文本数据。

在密码学中,明文是一些普通的可读文本,例如消息。另一方面,密文是在您输入明文后获取的加密算法的输出。

我们将明文消息转换为密文的简单算法是凯撒密码,由尤利乌斯·凯撒发明,用于将其敌人保密。此密码涉及将消息中的每个字母在字母表中“向前”移动三个位置。

以下是一个演示说明。

a → D

b → E

c → F

....

w → Z

x → A

y → B

z → C

示例

运行Python脚本时输入的消息提供所有字符的可能性,用于模式证据。

使用的模式证据类型如下 -

  • 轮胎痕迹和标记
  • 印记
  • 指纹

每个生物识别数据都包含向量数据,我们需要破解这些数据以收集确凿的证据。

以下 Python 代码展示了如何从纯文本生成密文:

import sys

def decrypt(k,cipher): 
   plaintext = '' 
   
   for each in cipher: 
      p = (ord(each)-k) % 126 
      
      if p < 32: 
         p+=95 
         plaintext += chr(p) 
         print plaintext 

def main(argv):
   if (len(sys.argv) != 1): 
      sys.exit('Usage: cracking.py') 
      cipher = raw_input('Enter message: ') 
      
      for i in range(1,95,1): 
         decrypt(i,cipher)
         
if __name__ == "__main__": 
   main(sys.argv[1:])

输出

现在,检查此代码的输出。当我们输入简单的文本“Radhika”时,程序将生成以下密文。

Cracking Encryption Output

Python取证 - 虚拟化

虚拟化是指模拟 IT 系统(如服务器、工作站、网络和存储)的过程。它只不过是创建任何操作系统的虚拟版本,而不是实际版本,包括服务器、存储设备或网络进程。

帮助模拟虚拟硬件的主要组件定义为管理程序

下图解释了两种主要类型的系统虚拟化。

Virtualization Types

虚拟化已在计算取证中以多种方式使用。它以这样一种方式帮助分析师,即工作站可以在每次调查中都处于经过验证的状态。可以通过将驱动器的 dd 映像作为虚拟机上的辅助驱动器来恢复数据,尤其如此。同一台机器可以用作恢复软件来收集证据。

以下示例有助于理解如何在 Python 编程语言的帮助下创建虚拟机。

步骤 1 - 假设虚拟机的名称为“dummy1”。

每个虚拟机至少必须具有 512 MB 的内存,以字节表示。

vm_memory = 512 * 1024 * 1024

步骤 2 - 虚拟机必须连接到已计算出的默认群集。

vm_cluster = api.clusters.get(name = "Default")

步骤 3 - 虚拟机必须从虚拟硬盘驱动器启动。

vm_os = params.OperatingSystem(boot = [params.Boot(dev = "hd")])

在使用 vms 集合的 add 方法将虚拟机添加到虚拟机之前,所有选项都组合到一个虚拟机参数对象中。

示例

以下是添加虚拟机的完整 Python 脚本。

from ovirtsdk.api import API #importing API library
from ovirtsdk.xml import params

try: #Api credentials is required for virtual machine
   api = API(url = "https://HOST", 
      username = "Radhika", 
      password = "a@123", 
      ca_file = "ca.crt")
      
   vm_name = "dummy1"
   vm_memory = 512 * 1024 * 1024 #calculating the memory in bytes
   vm_cluster = api.clusters.get(name = "Default")
   vm_template = api.templates.get(name = "Blank")
   
   #assigning the parameters to operating system
   vm_os = params.OperatingSystem(boot = [params.Boot(dev = "hd")])
   
   vm_params = params.VM(name = vm_name,
      memory = vm_memory,
      cluster = vm_cluster,
      template = vm_template
      os = vm_os)

   try: 
      api.vms.add(vm = vm_params) 
      print "Virtual machine '%s' added." % vm_name #output if it is successful. 
   except Exception as ex: 
      print "Adding virtual machine '%s' failed: %s" % (vm_name, ex) 
      api.disconnect()
      
except Exception as ex: 
   print "Unexpected error: %s" % ex

输出

我们的代码将产生以下输出 -

Virtualization Output

Python取证 - 网络取证

现代网络环境的场景是这样的,由于许多困难,调查可能会充满挑战。无论您是在响应违规支持、调查内部人员活动、执行漏洞评估还是验证法规遵从性,都可能发生这种情况。

网络编程的概念

以下定义用于网络编程。

  • 客户端 - 客户端是网络编程的客户端-服务器架构的一部分,它在个人电脑和工作站上运行。

  • 服务器 - 服务器是客户端-服务器架构的一部分,它为同一台或其他计算机中的其他计算机程序提供服务。

  • WebSocket - WebSocket 在客户端和服务器之间提供一个协议,该协议在持久 TCP 连接上运行。通过此协议,可以在 TCP 套接字连接之间(同时)发送双向消息。

WebSocket 出现在许多其他允许服务器向客户端发送信息的技术之后。除了握手升级标头之外,WebSocket 与 HTTP 无关。

Network Programming

这些协议用于验证第三方用户发送或接收的信息。由于加密是用于保护消息的方法之一,因此通过传输消息的通道来确保安全也很重要。

考虑以下 Python 程序,客户端使用它进行握手

示例

# client.py
import socket

# create a socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# get local machine name
host = socket.gethostname()
port = 8080

# connection to hostname on the port.
s.connect((host, port))

# Receive no more than 1024 bytes
tm = s.recv(1024)
print("The client is waiting for connection")
s.close()

输出

它将产生以下输出:

Network Programming Output

接受通信通道请求的服务器将包含以下脚本。

# server.py
import socket
import time

# create a socket object
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# get local machine name 
host = socket.gethostname()
port = 8080

# bind to the port
serversocket.bind((host, port))

# queue up to 5 requests 
serversocket.listen(5)

while True:
   # establish a connection 
   clientsocket,addr = serversocket.accept()
   print("Got a connection from %s" % str(addr))
   currentTime = time.ctime(time.time()) + "\r\n"
   clientsocket.send(currentTime.encode('ascii'))
   clientsocket.close()

使用 Python 编程创建的客户端和服务器侦听主机号。最初,客户端向服务器发送有关主机号中发送数据的请求,服务器接受该请求并立即发送响应。这样,我们就可以拥有一个安全的通信通道。

Python取证 - Python 模块

Python 程序中的模块有助于组织代码。它们有助于将相关代码分组到单个模块中,这使得更容易理解和使用。它包含任意命名的值,可用于绑定和引用。简单来说,模块是一个包含 Python 代码的文件,其中包含函数、类和变量。

模块(文件)的 Python 代码以.py扩展名保存,并在需要时进行编译。

示例

def print_hello_func( par ): 
   print "Hello : ", par 
   return

导入语句

通过执行import语句,可以将 Python 源文件用作模块,该语句导入其他包或第三方库。使用的语法如下:

import module1[, module2[,... moduleN]

当 Python 解释器遇到 import 语句时,它会导入指定的模块,该模块位于搜索路径中。

示例

考虑以下示例。

#!/usr/bin/python

# Import module support
import support

# Now you can call defined function that module as follows
support.print_func("Radhika")

它将产生以下输出:

Module Output

模块仅加载一次,无论 Python 代码已导入多少次。

From...import 语句

From属性有助于将模块中的特定属性导入到当前命名空间中。以下是其语法。

from modname import name1[, name2[, ... nameN]]

示例

要从模块fib导入函数fibonacci,请使用以下语句。

from fib import fibonacci

查找模块

导入模块时,Python 解释器会搜索以下序列:

  • 当前目录。

  • 如果模块不存在,则 Python 会搜索 shell 变量 PYTHONPATH 中的每个目录。

  • 如果 shell 变量位置失败,则 Python 会检查默认路径。

计算取证使用 Python 模块和第三方模块来获取信息并更轻松地提取证据。后面的章节重点介绍模块的实现以获取必要的输出。

Python取证 - Dshell 和 Scapy

DShell

Dshell是一个基于 Python 的网络取证分析工具包。该工具包由美国陆军研究实验室开发。此开源工具包于 2014 年发布。该工具包的主要重点是简化取证调查。

该工具包包含大量解码器,如下表所示。

序号 解码器名称和描述
1

dns

用于提取与 DNS 相关的查询

2

reservedips

识别 DNS 问题的解决方案

3

large-flows

净流量列表

4

rip-http

用于从 HTTP 流量中提取文件

5

协议

用于识别非标准协议

美国陆军实验室已在 GitHub 中维护克隆存储库,链接如下:

https://github.com/USArmyResearchLab/Dshell

Clone Repository

克隆包含一个用于安装此工具包的脚本install-ubuntu.py ()

安装成功后,它将自动构建稍后将使用的可执行文件和依赖项。

依赖项如下:

dependencies = { 
   "Crypto": "crypto", 
   "dpkt": "dpkt", 
   "IPy": "ipy", 
   "pcap": "pypcap" 
}

此工具包可用于 pcap(数据包捕获)文件,这些文件通常在事件期间或警报期间记录。这些 pcap 文件是由 Linux 平台上的 libpcap 或 Windows 平台上的 WinPcap 创建的。

Scapy

Scapy 是一个基于 Python 的工具,用于分析和操作网络流量。以下是 Scapy 工具包的链接:

http://www.secdev.org/projects/scapy/

此工具包用于分析数据包操作。它非常能够解码大量协议的数据包并捕获它们。Scapy 与 Dshell 工具包的不同之处在于,它为调查人员提供了有关网络流量的详细描述。这些描述已实时记录。

Scapy 能够使用第三方工具或操作系统指纹进行绘图。

考虑以下示例。

import scapy, GeoIP #Imports scapy and GeoIP toolkit 
from scapy import * 
geoIp = GeoIP.new(GeoIP.GEOIP_MEMORY_CACHE) #locates the Geo IP address 
def locatePackage(pkg): 
src = pkg.getlayer(IP).src #gets source IP address 
dst = pkg.getlayer(IP).dst #gets destination IP address 
srcCountry = geoIp.country_code_by_addr(src) #gets Country details of source 
dstCountry = geoIp.country_code_by_addr(dst) #gets country details of destination 
print src+"("+srcCountry+") >> "+dst+"("+dstCountry+")\n"

此脚本详细描述了网络数据包中相互通信的国家/地区的详细信息。

上述脚本将产生以下输出。

DShell and Scapy Output

Python取证 - 搜索

搜索无疑是取证调查的支柱之一。如今,搜索的质量取决于运行证据的调查员。

从消息中搜索关键字在取证中起着至关重要的作用,当我们使用关键字搜索证据时。了解在特定文件中以及已删除文件中需要搜索的内容,需要经验和知识。

Python 具有各种内置机制以及标准库模块来支持搜索操作。从根本上说,调查人员使用搜索操作来查找诸如“谁”、“什么”、“在哪里”、“何时”等问题的答案。

示例

在以下示例中,我们声明了两个字符串,然后使用 find 函数检查第一个字符串是否包含第二个字符串。

# Searching a particular word from a message
str1 = "This is a string example for Computational forensics of gathering evidence!";
str2 = "string";

print str1.find(str2)
print str1.find(str2, 10)
print str1.find(str2, 40)

上述脚本将产生以下输出。

Search Output

Python 中的“find”函数有助于在消息或段落中搜索关键字。这对于收集适当的证据至关重要。

Python取证 - 索引

索引实际上使调查员能够全面查看文件并从中收集潜在的证据。证据可能包含在文件、磁盘映像、内存快照或网络跟踪中。

索引有助于减少耗时任务(如关键字搜索)的时间。取证调查还涉及交互式搜索阶段,其中索引用于快速定位关键字。

索引还有助于将关键字列在排序列表中。

示例

以下示例显示了如何在 Python 中使用索引

aList = [123, 'sample', 'zara', 'indexing'];

print "Index for sample : ", aList.index('sample')
print "Index for indexing : ", aList.index('indexing')

str1 = "This is sample message for forensic investigation indexing";
str2 = "sample";

print "Index of the character keyword found is " 
print str1.index(str2)

上述脚本将产生以下输出。

Indexing Output

Python取证 - Python 图像库

从可用资源中提取有价值的信息是数字取证的重要组成部分。访问所有可用信息对于调查过程至关重要,因为它有助于检索适当的证据。

包含数据的资源可以是简单的数据库等数据结构,也可以是复杂的 JPEG 图像等数据结构。简单的结构可以使用简单的桌面工具轻松访问,而从复杂的数据结构中提取信息则需要复杂的编程工具。

Python图像库

Python 图像处理库 (PIL) 为您的 Python 解释器添加了图像处理功能。该库支持多种文件格式,并提供了强大的图像处理和图形功能。您可以从以下网址下载 PIL 的源文件:http://www.pythonware.com/products/pil/

下图显示了使用 PIL 从图像(复杂数据结构)中提取数据的完整流程图。

Python Imaging Library

示例

现在,让我们通过一个编程示例来了解它是如何工作的。

步骤 1 − 假设我们有以下图像,我们需要从中提取信息。

Python Imaging Library Step1

步骤 2 − 当我们使用 PIL 打开此图像时,它首先会记录提取证据所需的关键点,包括各种像素值。以下是打开图像并记录其像素值的代码 −

from PIL import Image
im = Image.open('Capture.jpeg', 'r')
pix_val = list(im.getdata())
pix_val_flat = [x for sets in pix_val for x in sets]
print pix_val_flat

步骤 3 − 在提取图像的像素值后,我们的代码将产生以下输出。

Python Imaging Library Step3

提供的输出表示 RGB 组合的像素值,这更清楚地说明了证据所需的数据。提取的数据以数组的形式表示。

Python 取证 - 移动取证

对标准计算机硬件(如硬盘)进行取证调查和分析已经发展成为一个稳定的学科,并通过分析非标准硬件或瞬态证据的技术来实现。

尽管智能手机在数字调查中越来越普遍,但它们仍然被视为非标准的。

取证分析

取证调查搜索诸如从智能手机接收或拨打的电话、短信、照片或任何其他可能构成犯罪证据的数据。大多数智能手机都具有使用密码或字母数字字符的屏幕锁定功能。

在这里,我们将举一个例子来说明 Python 如何帮助破解屏幕锁定密码以检索智能手机中的数据。

手动检查

Android 支持使用 PIN 码或字母数字密码进行密码锁定。两种密码的长度都要求在 4 到 16 位数字或字符之间。智能手机的密码存储在 Android 系统中的一个名为 password.key 的特殊文件中,位于 /data/system 目录下。

Android 存储密码的加盐 SHA1 哈希和 MD5 哈希。这些密码可以使用以下代码进行处理。

public byte[] passwordToHash(String password) {

   if (password == null) { 
      return null; 
   }

   String algo = null;
   byte[] hashed = null;

   try { 
      byte[] saltedPassword = (password + getSalt()).getBytes(); 
      byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
      byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword); 
      hashed = (toHex(sha1) + toHex(md5)).getBytes(); 
   } catch (NoSuchAlgorithmException e) { 
      Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo); 
   }
   
   return hashed;
}

由于哈希密码存储在 salt 文件中,因此无法使用 字典攻击来破解密码。此 salt 是一个 64 位随机整数的十六进制表示字符串。使用 Root 智能手机JTAG 适配器可以轻松访问 salt

Root 智能手机

文件 /data/system/password.key 的转储存储在 SQLite 数据库中,位于 lockscreen.password_salt 密钥下。在 settings.db 中,存储了密码,并且其值在以下屏幕截图中清晰可见。

Rooted Smartphone

JTAG 适配器

可以使用称为 JTAG(联合测试行动组)适配器的特殊硬件来访问 salt。类似地,Riff-BoxJIG-适配器也可以用于相同的功能。

使用从 Riff-box 获得的信息,我们可以找到加密数据的所在位置,即 salt。规则如下 −

  • 搜索关联字符串“lockscreen.password_salt”。

  • 字节表示盐的实际宽度,即它的 长度

  • 这实际上是搜索以获取智能手机存储的密码/PIN 的长度。

这套规则有助于获取正确的 salt 数据。

JTAG Adapter

Python 取证 - 网络时间协议

网络时间协议 (NTP) 是最广泛使用的用于时间同步的协议,并且已被广泛接受为一种实践。

NTP 使用用户数据报协议 (UDP),该协议使用最少的时间在希望与给定时间源同步的服务器和客户端之间通信数据包。

Network Time Protocol

网络时间协议的功能如下 −

  • 默认服务器端口为 123。

  • 该协议包含许多与国家实验室同步的可访问时间服务器。

  • NTP 协议标准由 IETF 监管,建议标准为 RFC 5905,标题为“网络时间协议版本 4:协议和算法规范”[NTP RFC]

  • 操作系统、程序和应用程序使用 NTP 以正确的方式同步时间。

在本章中,我们将重点关注 NTP 与 Python 的用法,这可以通过第三方 Python 库 ntplib 实现。该库有效地处理了繁重的工作,并将结果与我的本地系统时钟进行比较。

安装 NTP 库

ntplib 可从 https://pypi.python.org/pypi/ntplib/ 下载,如下图所示。

该库为 NTP 服务器提供了简单的接口,并提供了可以转换 NTP 协议字段的方法。这有助于访问其他关键值,例如闰秒。

Installing the NTP Library

以下 Python 程序有助于理解 NTP 的用法。

import ntplib
import time

NIST = 'nist1-macon.macon.ga.us'
ntp = ntplib.NTPClient()
ntpResponse = ntp.request(NIST)

if (ntpResponse):
   now = time.time()
   diff = now-ntpResponse.tx_time
   print diff;

上述程序将产生以下输出。

Using NTP Output

上述程序计算了时间差。这些计算有助于取证调查。获得的网络数据与硬盘上发现的数据分析从根本上不同。

时区的差异或获取准确的时区可以帮助收集通过此协议捕获消息的证据。

Python 取证 - 多处理支持

取证专家通常发现很难应用数字解决方案来分析普通犯罪中大量数字证据。大多数数字调查工具都是单线程的,一次只能执行一个命令。

在本章中,我们将重点关注 Python 的多处理功能,这与常见的取证挑战相关。

多处理

多处理定义为计算机系统支持多个进程的能力。支持多处理的操作系统允许多个程序并发运行。

有多种类型的多处理,例如 对称非对称处理。下图指的是对称多处理系统,这通常在取证调查中遵循。

Multiprocessing

示例

以下代码显示了 Python 编程中如何在内部列出不同的进程。

import random
import multiprocessing

def list_append(count, id, out_list): 
   #appends the count of number of processes which takes place at a time
   for i in range(count):
      out_list.append(random.random())
         
   if __name__ == "__main__": 
      size = 999  
      procs = 2
      # Create a list of jobs and then iterate through 
      # the number of processes appending each process to 
      # the job list  
      jobs = []
         
   for i in range(0, procs): 
      out_list = list() #list of processes 
      process1 = multiprocessing.Process(
         target = list_append, args = (size, i, out_list))

      # appends the list of processes
      jobs.append(process)

   # Calculate the random number of processes
   for j in jobs:
      j.start()  #initiate the process

   # After the processes have finished execution
   for j in jobs:
      j.join()
      print "List processing complete."

这里,函数 list_append() 用于列出系统中的进程集。

输出

我们的代码将产生以下输出 -

Multiprocessing Support Output

Python 取证 - 内存和取证

在本章中,我们将重点关注使用 Volatility(一个基于 Python 的取证框架,适用于以下平台:AndroidLinux)调查易失性内存。

易失性内存

易失性内存是一种存储类型,当系统电源关闭或中断时,其内容将被擦除。RAM 是易失性内存的最佳示例。这意味着,如果您正在处理尚未保存到非易失性内存(例如硬盘)的文档,并且计算机断电,则所有数据都将丢失。

通常,易失性内存取证遵循与其他取证调查相同的模式 −

  • 选择调查目标
  • 获取取证数据
  • 取证分析

用于 Android 的基本 volatility 插件收集 RAM 转储以进行分析。一旦收集了 RAM 转储以进行分析,就必须开始在 RAM 中搜索恶意软件。

YARA 规则

YARA 是一种流行的工具,它提供了一种强大的语言,与基于 Perl 的正则表达式兼容,并且用于检查可疑文件/目录并匹配字符串。

在本节中,我们将使用基于模式匹配实现的 YARA 并将其与实用程序功能结合起来。整个过程将有利于取证分析。

示例

考虑以下代码。此代码有助于提取代码。

import operator
import os
import sys

sys.path.insert(0, os.getcwd())
import plyara.interp as interp

# Plyara is a script that lexes and parses a file consisting of one more Yara
# rules into a python dictionary representation.
if __name__ == '__main__': 
   file_to_analyze = sys.argv[1] 
   rulesDict = interp.parseString(open(file_to_analyze).read()) 
   authors = {} 
   imps = {} 
   meta_keys = {} 
   max_strings = [] 
   max_string_len = 0 
   tags = {} 
   rule_count = 0  

   for rule in rulesDict: 
      rule_count += 1  
   
   # Imports 
   if 'imports' in rule: 
      for imp in rule['imports']: 
         imp = imp.replace('"','') 
         
         if imp in imps: 
            imps[imp] += 1 
         else: 
            imps[imp] = 1  
   # Tags 
   if 'tags' in rule: 
      for tag in rule['tags']: 
         if tag in tags: 
            tags[tag] += 1 
         else: 
            tags[tag] = 1
            
   # Metadata 
   if 'metadata' in rule: 
      for key in rule['metadata']: 
         if key in meta_keys: 
            meta_keys[key] += 1
         else: 
            meta_keys[key] = 1 
         
         if key in ['Author', 'author']: 
            if rule['metadata'][key] in authors: 
               authors[rule['metadata'][key]] += 1 
            else: 
               authors[rule['metadata'][key]] = 1  

   #Strings 
   if 'strings' in rule: 
      for strr in rule['strings']: 
         if len(strr['value']) > max_string_len: 
            max_string_len = len(strr['value']) 
            max_strings = [(rule['rule_name'], strr['name'], strr['value'])] 
         elif len(strr['value']) == max_string_len: 
            max_strings.append((rule['rule_name'], strr['key'], strr['value']))  
   
   print("\nThe number of rules implemented" + str(rule_count))
   ordered_meta_keys = sorted(meta_keys.items(), key = operator.itemgetter(1),
      reverse = True)
   ordered_authors = sorted(authors.items(), key = operator.itemgetter(1), 
      reverse = True)
   ordered_imps = sorted(imps.items(), key = operator.itemgetter(1), reverse = True)
   ordered_tags = sorted(tags.items(), key = operator.itemgetter(1), reverse = True)

上述代码将产生以下输出。

Memory and Forensics Output

实施的 YARA 规则数量有助于更好地了解可疑文件。间接地,可疑文件的列表有助于收集取证所需的信息。

以下是 github 中的源代码:https://github.com/radhikascs/Python_yara

Linux 中的 Python 取证

数字调查的主要关注点是使用加密或任何其他格式来保护重要证据或数据。最基本的例子是存储密码。因此,有必要了解 Linux 操作系统的用法,以便在数字取证实施中保护这些宝贵的数据。

所有本地用户的信息主要存储在以下两个文件中 −

  • /etc/passwd
  • etc/shadow

第一个文件是强制性的,它存储所有密码。第二个文件是可选的,它存储有关本地用户的信息,包括哈希密码。

将密码信息存储在每个用户都可以读取的文件中会引发安全问题。因此,哈希密码存储在 /etc/passwd 中,其中内容被替换为特殊值“x”。

相应的哈希必须在 /etc/shadow 中查找。/etc/passwd 中的设置可能会覆盖 /etc/shadow 中的详细信息。

Linux 中的这两个文本文件每行包含一个条目,并且条目由多个字段组成,用冒号分隔。

/etc/passwd 的格式如下 −

序号 字段名称和描述
1

用户名

此字段包含人类可读格式的属性

2

密码哈希

它包含根据 Posix crypt 函数编码的密码

如果哈希密码保存为空,则相应的用户无需任何密码即可登录系统。如果此字段包含无法由哈希算法生成的的值,例如感叹号,则用户无法使用密码登录。

具有锁定密码的用户仍然可以使用其他身份验证机制登录,例如 SSH 密钥。如前所述,特殊值“x”表示必须在 shadow 文件中查找密码哈希。

密码哈希包含以下内容 −

  • 加密盐加密盐有助于维护屏幕锁定、PIN 码和密码。

  • 数值用户 ID − 此字段表示用户的 ID。Linux 内核将此用户 ID 分配给系统。

  • 数值组 ID − 此字段指的是用户的首要组。

  • 主目录 − 新进程以对该目录的引用启动。

  • 命令 shell − 此可选字段表示在成功登录系统后要启动的默认 shell。

数字取证包括收集与跟踪证据相关的信息。因此,用户 ID 有助于维护记录。

使用 Python,可以自动分析所有这些信息以获取分析指标,重建最近的系统活动。通过 Linux Shell 的实现,跟踪变得简单易行。

Python 与 Linux 编程

示例

import sys
import hashlib
import getpass

def main(argv):
   print '\nUser & Password Storage Program in Linux for forensic detection v.01\n' 
  
   if raw_input('The file ' + sys.argv[1] + ' will be erased or overwrite if 
         it exists .\nDo you wish to continue (Y/n): ') not in ('Y','y') : 
   sys.exit('\nChanges were not recorded\n') 
  
   user_name = raw_input('Please Enter a User Name: ')
   password = hashlib.sha224(getpass.getpass('Please Enter a Password:')).hexdigest()
   
   # Passwords which are hashed  
   try: 
      file_conn = open(sys.argv[1],'w') 
      file_conn.write(user_name + '\n') 
      file_conn.write(password + '\n') 
      file_conn.close() 
   except: 
      sys.exit('There was a problem writing the passwords to file!')
      
if __name__ == "__main__": 
   main(sys.argv[1:])

输出

密码以十六进制格式存储在 pass_db.txt 中,如下面的屏幕截图所示。文本文件被保存以供在计算取证中进一步使用。

Python Forensics in Linux Output

Python 取证 - 妥协指标

妥协指标 (IOC) 定义为“取证数据片段,其中包括在系统日志条目或文件中找到的数据,这些数据识别系统或网络上可能存在恶意活动的活动”。

通过监控 IOC,组织可以检测攻击并迅速采取行动,防止此类违规行为发生或通过在早期阶段阻止攻击来限制损害。

有一些用例允许查询取证工件,例如 −

  • 按 MD5 查找特定文件
  • 搜索存储在内存中的特定实体
  • 存储在 Windows 注册表中的特定条目或条目集

上述所有方法的结合在搜索工件方面提供了更好的结果。如上所述,Windows注册表为生成和维护IOC提供了完美的平台,这直接有助于计算取证。

方法

  • 查找文件系统中的位置,特别是现在Windows注册表中的位置。

  • 搜索由取证工具设计的工件集。

  • 寻找任何不利活动的迹象。

调查生命周期

调查生命周期遵循IOC,并在注册表中搜索特定条目。

  • 阶段1:初始证据 - 在主机或网络上检测到入侵的证据。响应者将调查并确定确切的解决方案,这是一个具体的取证指标。

  • 阶段2:为主机和网络创建IOC - 遵循收集的数据,创建IOC,这可以通过Windows注册表轻松实现。OpenIOC的灵活性为如何构建指标提供了无限数量的排列组合。

  • 阶段3:在企业中部署IOC - 创建指定的IOC后,调查人员将在Windows注册表中借助API部署这些技术。

  • 阶段4:识别嫌疑人 - IOC的部署有助于以正常方式识别嫌疑人。甚至会识别出其他系统。

  • 阶段5:收集和分析证据 - 针对嫌疑人的证据会被收集并相应地进行分析。

  • 阶段6:完善和创建新的IOC - 调查小组可以根据他们在企业中发现的证据和数据以及其他情报创建新的IOC,并继续完善他们的循环。

下图显示了调查生命周期的阶段 -

Investigative Life Cycle

Python取证 - 云的实现

云计算可以定义为通过互联网向用户提供的一组托管服务。它使组织能够使用或甚至计算资源,包括虚拟机(VM)、存储或应用程序作为实用程序。

使用Python编程语言构建应用程序最重要的优势之一是它包括能够在任何平台上虚拟部署应用程序的能力,其中也包括。这意味着Python可以在云服务器上执行,也可以在方便的设备上启动,例如桌面、平板电脑或智能手机。

一个有趣的视角是创建基于云的彩虹表生成。它有助于集成应用程序的单处理和多处理版本,这需要一些考虑。

Pi云

Pi云是一个云计算平台,它将Python编程语言与Amazon Web Services的计算能力相结合。

Pi Cloud

让我们来看一个使用彩虹表实现Pi云的示例。

彩虹表

彩虹表定义为特定散列算法加密密码的所有可能的明文排列的列表。

  • 彩虹表遵循一个标准模式,该模式创建了一个散列密码列表。

  • 一个文本文件用于生成密码,其中包括要加密的密码的字符或明文。

  • Pi云使用该文件,调用要存储的主函数。

  • 散列密码的输出也存储在文本文件中。

此算法也可用于将密码保存到数据库中,并在云系统中拥有备份存储。

以下内置程序在文本文件中创建加密密码列表。

示例

import os
import random
import hashlib
import string
import enchant    #Rainbow tables with enchant 
import cloud      #importing pi-cloud

def randomword(length): 
   return ''.join(random.choice(string.lowercase) for i in range(length))

print('Author- Radhika Subramanian')

def mainroutine():
   engdict = enchant.Dict("en_US")
   fileb = open("password.txt","a+")

   # Capture the values from the text file named password
   while True:
      randomword0 = randomword(6)
      if engdict.check(randomword0) == True:
         randomkey0 = randomword0+str(random.randint(0,99))
      elif engdict.check(randomword0) == False:
         englist = engdict.suggest(randomword0)
         if len(englist) > 0:
            randomkey0 = englist[0]+str(random.randint(0,99))
         else:
            randomkey0 = randomword0+str(random.randint(0,99))

      randomword3 = randomword(5)
      if engdict.check(randomword3) == True:
         randomkey3 = randomword3+str(random.randint(0,99))
      elif engdict.check(randomword3) == False:
         englist = engdict.suggest(randomword3)
         if len(englist) > 0:
            randomkey3 = englist[0]+str(random.randint(0,99))
         else:
            randomkey3 = randomword3+str(random.randint(0,99))
      
      if 'randomkey0' and 'randomkey3' and 'randomkey1' in locals():
         whasher0 = hashlib.new("md5")
         whasher0.update(randomkey0)
         whasher3 = hashlib.new("md5")
         whasher3.update(randomkey3)
         whasher1 = hashlib.new("md5")
         whasher1.update(randomkey1)
         print(randomkey0+" + "+str(whasher0.hexdigest())+"\n")
         print(randomkey3+" + "+str(whasher3.hexdigest())+"\n")
         print(randomkey1+" + "+str(whasher1.hexdigest())+"\n")
         fileb.write(randomkey0+" + "+str(whasher0.hexdigest())+"\n") 
         fileb.write(randomkey3+" + "+str(whasher3.hexdigest())+"\n")
         fileb.write(randomkey1+" + "+str(whasher1.hexdigest())+"\n")

jid = cloud.call(randomword)  #square(3) evaluated on PiCloud
cloud.result(jid)
print('Value added to cloud')
print('Password added')
mainroutine()

输出

此代码将产生以下输出 -

Cloud Implementation Output

密码存储在文本文件中,如以下屏幕截图所示。

Passwords Stored in Text Files
广告