Các phần tử quan trọng trong Windows-II
Chương này nói về một số tạo tác quan trọng hơn trong Windows và phương pháp trích xuất của chúng bằng Python.
Hoạt động của Người dùng
Windows có NTUSER.DATtệp để lưu trữ các hoạt động khác nhau của người dùng. Mọi hồ sơ người dùng đều có rất nhiều lượt thíchNTUSER.DAT, nơi lưu trữ thông tin và cấu hình cụ thể liên quan đến người dùng đó. Do đó, nó rất hữu ích cho mục đích điều tra của các nhà phân tích pháp y.
Tập lệnh Python sau sẽ phân tích cú pháp một số khóa của NTUSER.DATđể khám phá các hành động của người dùng trên hệ thống. Trước khi tiếp tục, đối với tập lệnh Python, chúng ta cần cài đặt các mô-đun của bên thứ ba, cụ thể làRegistry, pytsk3, pyewf và Jinja2. Chúng ta có thể sử dụng pip để cài đặt chúng.
Chúng ta có thể làm theo các bước sau để trích xuất thông tin từ NTUSER.DAT tập tin -
Đầu tiên, hãy tìm kiếm tất cả NTUSER.DAT các tệp trong hệ thống.
Sau đó phân tích cú pháp WordWheelQuery, TypePath and RunMRU chìa khóa cho mỗi NTUSER.DAT tập tin.
Cuối cùng, chúng tôi sẽ viết các tạo phẩm này, đã được xử lý, vào một báo cáo HTML bằng cách sử dụng Jinja2 fmodule.
Mã Python
Hãy để chúng tôi xem cách sử dụng mã Python cho mục đích này -
Trước hết, chúng ta cần nhập các mô-đun Python sau:
from __future__ import print_function
from argparse import ArgumentParser
import os
import StringIO
import struct
from utility.pytskutil import TSKUtil
from Registry import Registry
import jinja2
Bây giờ, cung cấp đối số cho trình xử lý dòng lệnh. Ở đây nó sẽ chấp nhận ba đối số - đầu tiên là đường dẫn đến tệp bằng chứng, thứ hai là loại tệp bằng chứng và thứ ba là đường dẫn đầu ra mong muốn đến báo cáo HTML, như được hiển thị bên dưới -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Information from user activities')
parser.add_argument('EVIDENCE_FILE',help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE',help = "Evidence file format",choices = ('ewf', 'raw'))
parser.add_argument('REPORT',help = "Path to report file")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT)
Bây giờ, chúng ta hãy xác định main() chức năng tìm kiếm tất cả NTUSER.DAT các tệp, như được hiển thị -
def main(evidence, image_type, report):
tsk_util = TSKUtil(evidence, image_type)
tsk_ntuser_hives = tsk_util.recurse_files('ntuser.dat','/Users', 'equals')
nt_rec = {
'wordwheel': {'data': [], 'title': 'WordWheel Query'},
'typed_path': {'data': [], 'title': 'Typed Paths'},
'run_mru': {'data': [], 'title': 'Run MRU'}
}
Bây giờ, chúng tôi sẽ cố gắng tìm ra chìa khóa trong NTUSER.DAT và khi bạn tìm thấy nó, hãy xác định các chức năng xử lý của người dùng như được hiển thị bên dưới -
for ntuser in tsk_ntuser_hives:
uname = ntuser[1].split("/")
open_ntuser = open_file_as_reg(ntuser[2])
try:
explorer_key = open_ntuser.root().find_key("Software").find_key("Microsoft")
.find_key("Windows").find_key("CurrentVersion").find_key("Explorer")
except Registry.RegistryKeyNotFoundException:
continue
nt_rec['wordwheel']['data'] += parse_wordwheel(explorer_key, uname)
nt_rec['typed_path']['data'] += parse_typed_paths(explorer_key, uname)
nt_rec['run_mru']['data'] += parse_run_mru(explorer_key, uname)
nt_rec['wordwheel']['headers'] = \ nt_rec['wordwheel']['data'][0].keys()
nt_rec['typed_path']['headers'] = \ nt_rec['typed_path']['data'][0].keys()
nt_rec['run_mru']['headers'] = \ nt_rec['run_mru']['data'][0].keys()
Bây giờ, chuyển đối tượng từ điển và đường dẫn của nó tới write_html() phương pháp như sau -
write_html(report, nt_rec)
Bây giờ, hãy xác định một phương pháp, cần pytsk xử lý tệp và đọc nó vào lớp Registry thông qua StringIO lớp học.
def open_file_as_reg(reg_file):
file_size = reg_file.info.meta.size
file_content = reg_file.read_random(0, file_size)
file_like_obj = StringIO.StringIO(file_content)
return Registry.Registry(file_like_obj)
Bây giờ, chúng ta sẽ xác định hàm sẽ phân tích cú pháp và xử lý WordWheelQuery chìa khóa từ NTUSER.DAT tập tin như sau -
def parse_wordwheel(explorer_key, username):
try:
wwq = explorer_key.find_key("WordWheelQuery")
except Registry.RegistryKeyNotFoundException:
return []
mru_list = wwq.value("MRUListEx").value()
mru_order = []
for i in xrange(0, len(mru_list), 2):
order_val = struct.unpack('h', mru_list[i:i + 2])[0]
if order_val in mru_order and order_val in (0, -1):
break
else:
mru_order.append(order_val)
search_list = []
for count, val in enumerate(mru_order):
ts = "N/A"
if count == 0:
ts = wwq.timestamp()
search_list.append({
'timestamp': ts,
'username': username,
'order': count,
'value_name': str(val),
'search': wwq.value(str(val)).value().decode("UTF-16").strip("\x00")
})
return search_list
Bây giờ, chúng ta sẽ xác định hàm sẽ phân tích cú pháp và xử lý TypedPaths chìa khóa từ NTUSER.DAT tập tin như sau -
def parse_typed_paths(explorer_key, username):
try:
typed_paths = explorer_key.find_key("TypedPaths")
except Registry.RegistryKeyNotFoundException:
return []
typed_path_details = []
for val in typed_paths.values():
typed_path_details.append({
"username": username,
"value_name": val.name(),
"path": val.value()
})
return typed_path_details
Bây giờ, chúng ta sẽ xác định hàm sẽ phân tích cú pháp và xử lý RunMRU chìa khóa từ NTUSER.DAT tập tin như sau -
def parse_run_mru(explorer_key, username):
try:
run_mru = explorer_key.find_key("RunMRU")
except Registry.RegistryKeyNotFoundException:
return []
if len(run_mru.values()) == 0:
return []
mru_list = run_mru.value("MRUList").value()
mru_order = []
for i in mru_list:
mru_order.append(i)
mru_details = []
for count, val in enumerate(mru_order):
ts = "N/A"
if count == 0:
ts = run_mru.timestamp()
mru_details.append({
"username": username,
"timestamp": ts,
"order": count,
"value_name": val,
"run_statement": run_mru.value(val).value()
})
return mru_details
Bây giờ, hàm sau sẽ xử lý việc tạo báo cáo HTML:
def write_html(outfile, data_dict):
cwd = os.path.dirname(os.path.abspath(__file__))
env = jinja2.Environment(loader=jinja2.FileSystemLoader(cwd))
template = env.get_template("user_activity.html")
rendering = template.render(nt_data=data_dict)
with open(outfile, 'w') as open_outfile:
open_outfile.write(rendering)
Cuối cùng, chúng tôi có thể viết tài liệu HTML cho báo cáo. Sau khi chạy đoạn script trên, chúng ta sẽ lấy thông tin từ tệp NTUSER.DAT ở định dạng tài liệu HTML.
LINK tệp
Tệp lối tắt được tạo khi người dùng hoặc hệ điều hành tạo tệp lối tắt cho tệp thường được sử dụng, nhấp đúp hoặc truy cập từ các ổ đĩa hệ thống như bộ nhớ đính kèm. Các loại tệp lối tắt như vậy được gọi là tệp liên kết. Bằng cách truy cập các tệp liên kết này, điều tra viên có thể tìm thấy hoạt động của cửa sổ như thời gian và vị trí từ nơi các tệp này đã được truy cập.
Hãy để chúng tôi thảo luận về tập lệnh Python mà chúng tôi có thể sử dụng để lấy thông tin từ các tệp Windows LINK này.
Đối với tập lệnh Python, hãy cài đặt các mô-đun của bên thứ ba, cụ thể là pylnk, pytsk3, pyewf. Chúng ta có thể làm theo các bước sau để trích xuất thông tin từlnk các tập tin
Đầu tiên, hãy tìm kiếm lnk các tệp trong hệ thống.
Sau đó, trích xuất thông tin từ tệp đó bằng cách lặp lại chúng.
Bây giờ, cuối cùng chúng tôi cần thông tin này vào báo cáo CSV.
Mã Python
Hãy để chúng tôi xem cách sử dụng mã Python cho mục đích này -
Đầu tiên, nhập các thư viện Python sau:
from __future__ import print_function
from argparse import ArgumentParser
import csv
import StringIO
from utility.pytskutil import TSKUtil
import pylnk
Bây giờ, cung cấp đối số cho trình xử lý dòng lệnh. Ở đây nó sẽ chấp nhận ba đối số - đầu tiên là đường dẫn đến tệp bằng chứng, thứ hai là loại tệp bằng chứng và thứ ba là đường dẫn đầu ra mong muốn đến báo cáo CSV, như được hiển thị bên dưới -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Parsing LNK files')
parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE', help = "Evidence file format",choices = ('ewf', 'raw'))
parser.add_argument('CSV_REPORT', help = "Path to CSV report")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.CSV_REPORT)
Bây giờ, hãy diễn giải tệp bằng chứng bằng cách tạo một đối tượng TSKUtil và lặp lại qua hệ thống tệp để tìm các tệp kết thúc bằng lnk. Nó có thể được thực hiện bằng cách xác địnhmain() chức năng như sau -
def main(evidence, image_type, report):
tsk_util = TSKUtil(evidence, image_type)
lnk_files = tsk_util.recurse_files("lnk", path="/", logic="endswith")
if lnk_files is None:
print("No lnk files found")
exit(0)
columns = [
'command_line_arguments', 'description', 'drive_serial_number',
'drive_type', 'file_access_time', 'file_attribute_flags',
'file_creation_time', 'file_modification_time', 'file_size',
'environmental_variables_location', 'volume_label',
'machine_identifier', 'local_path', 'network_path',
'relative_path', 'working_directory'
]
Bây giờ với sự trợ giúp của mã sau, chúng tôi sẽ lặp lại lnk bằng cách tạo một hàm như sau:
parsed_lnks = []
for entry in lnk_files:
lnk = open_file_as_lnk(entry[2])
lnk_data = {'lnk_path': entry[1], 'lnk_name': entry[0]}
for col in columns:
lnk_data[col] = getattr(lnk, col, "N/A")
lnk.close()
parsed_lnks.append(lnk_data)
write_csv(report, columns + ['lnk_path', 'lnk_name'], parsed_lnks)
Bây giờ chúng ta cần xác định hai hàm, một hàm sẽ mở pytsk đối tượng tệp và đối tượng khác sẽ được sử dụng để viết báo cáo CSV như được hiển thị bên dưới:
def open_file_as_lnk(lnk_file):
file_size = lnk_file.info.meta.size
file_content = lnk_file.read_random(0, file_size)
file_like_obj = StringIO.StringIO(file_content)
lnk = pylnk.file()
lnk.open_file_object(file_like_obj)
return lnk
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
Sau khi chạy tập lệnh trên, chúng tôi sẽ nhận được thông tin từ lnk các tệp trong báo cáo CSV -
Tìm nạp trước tệp
Bất cứ khi nào một ứng dụng đang chạy lần đầu tiên từ một vị trí cụ thể, Windows sẽ tạo prefetch files. Chúng được sử dụng để tăng tốc quá trình khởi động ứng dụng. Phần mở rộng cho các tệp này là.PF và chúng được lưu trữ trong ”\Root\Windows\Prefetch” thư mục.
Các chuyên gia pháp y kỹ thuật số có thể tiết lộ bằng chứng về việc thực hiện chương trình từ một vị trí xác định cùng với các thông tin chi tiết của người dùng. Các tệp tìm nạp trước là hiện vật hữu ích cho người kiểm tra vì mục nhập của họ vẫn còn ngay cả sau khi chương trình đã bị xóa hoặc không được cài đặt.
Hãy để chúng tôi thảo luận về tập lệnh Python sẽ lấy thông tin từ các tệp tìm nạp trước của Windows như được cung cấp bên dưới:
Đối với tập lệnh Python, hãy cài đặt các mô-đun của bên thứ ba, cụ thể là pylnk, pytsk3 và unicodecsv. Nhớ lại rằng chúng ta đã làm việc với các thư viện này trong các tập lệnh Python mà chúng ta đã thảo luận trong các chương trước.
Chúng tôi phải làm theo các bước dưới đây để trích xuất thông tin từ prefetch tập tin -
Đầu tiên, hãy quét tìm .pf tệp mở rộng hoặc tệp tìm nạp trước.
Bây giờ, hãy thực hiện xác minh chữ ký để loại bỏ các trường hợp dương tính giả.
Tiếp theo, phân tích cú pháp định dạng tệp tìm nạp trước của Windows. Điều này khác với phiên bản Windows. Ví dụ, đối với Windows XP là 17, đối với Windows Vista và Windows 7 là 23, 26 đối với Windows 8.1 và 30 đối với Windows 10.
Cuối cùng, chúng tôi sẽ ghi kết quả được phân tích cú pháp vào tệp CSV.
Mã Python
Hãy để chúng tôi xem cách sử dụng mã Python cho mục đích này -
Đầu tiên, nhập các thư viện Python sau:
from __future__ import print_function
import argparse
from datetime import datetime, timedelta
import os
import pytsk3
import pyewf
import struct
import sys
import unicodecsv as csv
from utility.pytskutil import TSKUtil
Bây giờ, cung cấp một đối số cho trình xử lý dòng lệnh. Ở đây nó sẽ chấp nhận hai lập luận, thứ nhất sẽ là đường dẫn đến tệp bằng chứng và thứ hai sẽ là loại tệp bằng chứng. Nó cũng chấp nhận một đối số tùy chọn để chỉ định đường dẫn để quét các tệp tìm nạp trước -
if __name__ == "__main__":
parser = argparse.ArgumentParser('Parsing Prefetch files')
parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
parser.add_argument("OUTPUT_CSV", help = "Path to write output csv")
parser.add_argument("-d", help = "Prefetch directory to scan",default = "/WINDOWS/PREFETCH")
args = parser.parse_args()
if os.path.exists(args.EVIDENCE_FILE) and \
os.path.isfile(args.EVIDENCE_FILE):
main(args.EVIDENCE_FILE, args.TYPE, args.OUTPUT_CSV, args.d)
else:
print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
sys.exit(1)
Bây giờ, hãy diễn giải tệp bằng chứng bằng cách tạo một đối tượng TSKUtil và lặp lại qua hệ thống tệp để tìm các tệp kết thúc bằng .pf. Nó có thể được thực hiện bằng cách xác địnhmain() chức năng như sau -
def main(evidence, image_type, output_csv, path):
tsk_util = TSKUtil(evidence, image_type)
prefetch_dir = tsk_util.query_directory(path)
prefetch_files = None
if prefetch_dir is not None:
prefetch_files = tsk_util.recurse_files(".pf", path=path, logic="endswith")
if prefetch_files is None:
print("[-] No .pf files found")
sys.exit(2)
print("[+] Identified {} potential prefetch files".format(len(prefetch_files)))
prefetch_data = []
for hit in prefetch_files:
prefetch_file = hit[2]
pf_version = check_signature(prefetch_file)
Bây giờ, hãy xác định một phương thức sẽ thực hiện việc xác nhận chữ ký như hình dưới đây:
def check_signature(prefetch_file):
version, signature = struct.unpack("^<2i", prefetch_file.read_random(0, 8))
if signature == 1094927187:
return version
else:
return None
if pf_version is None:
continue
pf_name = hit[0]
if pf_version == 17:
parsed_data = parse_pf_17(prefetch_file, pf_name)
parsed_data.append(os.path.join(path, hit[1].lstrip("//")))
prefetch_data.append(parsed_data)
Bây giờ, hãy bắt đầu xử lý các tệp tìm nạp trước của Windows. Ở đây chúng tôi đang lấy ví dụ về các tệp tìm nạp trước của Windows XP -
def parse_pf_17(prefetch_file, pf_name):
create = convert_unix(prefetch_file.info.meta.crtime)
modify = convert_unix(prefetch_file.info.meta.mtime)
def convert_unix(ts):
if int(ts) == 0:
return ""
return datetime.utcfromtimestamp(ts)
def convert_filetime(ts):
if int(ts) == 0:
return ""
return datetime(1601, 1, 1) + timedelta(microseconds=ts / 10)
Bây giờ, trích xuất dữ liệu được nhúng trong các tệp được tải trước bằng cách sử dụng cấu trúc như sau:
pf_size, name, vol_info, vol_entries, vol_size, filetime, \
count = struct.unpack("<i60s32x3iq16xi",prefetch_file.read_random(12, 136))
name = name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]
vol_name_offset, vol_name_length, vol_create, \
vol_serial = struct.unpack("<2iqi",prefetch_file.read_random(vol_info, 20))
vol_serial = hex(vol_serial).lstrip("0x")
vol_serial = vol_serial[:4] + "-" + vol_serial[4:]
vol_name = struct.unpack(
"<{}s".format(2 * vol_name_length),
prefetch_file.read_random(vol_info + vol_name_offset,vol_name_length * 2))[0]
vol_name = vol_name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]
return [
pf_name, name, pf_size, create,
modify, convert_filetime(filetime), count, vol_name,
convert_filetime(vol_create), vol_serial ]
Như chúng tôi đã cung cấp phiên bản tìm nạp trước cho Windows XP nhưng nếu gặp phải các phiên bản tìm nạp trước cho Windows khác thì sao. Sau đó, nó phải hiển thị một thông báo lỗi như sau:
elif pf_version == 23:
print("[-] Windows Vista / 7 PF file {} -- unsupported".format(pf_name))
continue
elif pf_version == 26:
print("[-] Windows 8 PF file {} -- unsupported".format(pf_name))
continue
elif pf_version == 30:
print("[-] Windows 10 PF file {} -- unsupported".format(pf_name))
continue
else:
print("[-] Signature mismatch - Name: {}\nPath: {}".format(hit[0], hit[1]))
continue
write_output(prefetch_data, output_csv)
Bây giờ, hãy xác định phương pháp ghi kết quả vào báo cáo CSV như sau:
def write_output(data, output_csv):
print("[+] Writing csv report")
with open(output_csv, "wb") as outfile:
writer = csv.writer(outfile)
writer.writerow([
"File Name", "Prefetch Name", "File Size (bytes)",
"File Create Date (UTC)", "File Modify Date (UTC)",
"Prefetch Last Execution Date (UTC)",
"Prefetch Execution Count", "Volume", "Volume Create Date",
"Volume Serial", "File Path" ])
writer.writerows(data)
Sau khi chạy đoạn mã trên, chúng ta sẽ lấy thông tin từ các tệp tìm nạp trước của phiên bản Windows XP vào một bảng tính.