Windows-IIの重要なアーティファクト
この章では、Windowsのいくつかのより重要なアーティファクトと、Pythonを使用したそれらの抽出方法について説明します。
ユーザーアクティビティ
持っているウィンドウ NTUSER.DATさまざまなユーザーアクティビティを保存するためのファイル。すべてのユーザープロファイルは次のようなハイブを持っていますNTUSER.DAT、そのユーザーに特に関連する情報と構成を格納します。したがって、フォレンジックアナリストによる調査の目的に非常に役立ちます。
次のPythonスクリプトは、のキーのいくつかを解析します NTUSER.DATシステム上のユーザーのアクションを調査するため。先に進む前に、Pythonスクリプトの場合、サードパーティのモジュールをインストールする必要があります。Registry, pytsk3、pyewfおよび Jinja2。pipを使用してインストールできます。
次の手順に従って、から情報を抽出できます。 NTUSER.DAT ファイル-
まず、すべてを検索します NTUSER.DAT システム内のファイル。
次に、 WordWheelQuery, TypePath and RunMRU それぞれのキー NTUSER.DAT ファイル。
最後に、すでに処理されたこれらのアーティファクトを、を使用してHTMLレポートに書き込みます。 Jinja2 fmodule。
Pythonコード
この目的のためにPythonコードを使用する方法を見てみましょう-
まず、次のPythonモジュールをインポートする必要があります-
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
ここで、コマンドラインハンドラーの引数を指定します。ここでは、3つの引数を受け入れます。1つ目は証拠ファイルへのパス、2つ目は証拠ファイルのタイプ、3つ目は以下に示すようにHTMLレポートへの目的の出力パスです。
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)
さて、定義しましょう main() すべてを検索するための機能 NTUSER.DAT 示されているように、ファイル-
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'}
}
今、私たちはで鍵を見つけようとします NTUSER.DAT ファイルを見つけたら、以下に示すようにユーザー処理関数を定義します-
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()
次に、辞書オブジェクトとそのパスをに渡します write_html() 次のような方法-
write_html(report, nt_rec)
次に、メソッドを定義します。 pytsk ファイルハンドルを作成し、を介してレジストリクラスに読み込みます。 StringIO クラス。
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)
次に、解析して処理する関数を定義します WordWheelQuery からのキー NTUSER.DAT 次のようにファイル-
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
次に、解析して処理する関数を定義します TypedPaths からのキー NTUSER.DAT 次のようにファイル-
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
次に、解析して処理する関数を定義します RunMRU からのキー NTUSER.DAT 次のようにファイル-
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
これで、次の関数が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)
ついにレポート用のHTMLドキュメントを書くことができます。上記のスクリプトを実行した後、HTMLドキュメント形式でNTUSER.DATファイルから情報を取得します。
LINKファイル
ショートカットファイルは、ユーザーまたはオペレーティングシステムが、接続されたストレージなどのシステムドライブから頻繁に使用、ダブルクリック、またはアクセスされるファイルのショートカットファイルを作成するときに作成されます。このような種類のショートカットファイルは、リンクファイルと呼ばれます。これらのリンクファイルにアクセスすることにより、調査員は、これらのファイルにアクセスした時間や場所などのウィンドウのアクティビティを見つけることができます。
これらのWindowsLINKファイルから情報を取得するために使用できるPythonスクリプトについて説明します。
Pythonスクリプトの場合、サードパーティのモジュールをインストールします。 pylnk, pytsk3, pyewf。次の手順に従って、から情報を抽出できます。lnk ファイル
まず、 lnk システム内のファイル。
次に、それらを反復処理して、そのファイルから情報を抽出します。
さて、ついにこの情報をCSVレポートに追加する必要があります。
Pythonコード
この目的のためにPythonコードを使用する方法を見てみましょう-
まず、次のPythonライブラリをインポートします-
from __future__ import print_function
from argparse import ArgumentParser
import csv
import StringIO
from utility.pytskutil import TSKUtil
import pylnk
ここで、コマンドラインハンドラーの引数を指定します。ここでは、3つの引数を受け入れます。1つ目は証拠ファイルへのパス、2つ目は証拠ファイルのタイプ、3つ目はCSVレポートへの目的の出力パスです。
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)
次に、のオブジェクトを作成して証拠ファイルを解釈します。 TSKUtil ファイルシステムを反復処理して、で終わるファイルを見つけます lnk。それは定義することによって行うことができますmain() 次のように機能します-
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'
]
次のコードの助けを借りて、繰り返します lnk 次のように関数を作成してファイルを作成します-
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)
次に、2つの関数を定義する必要があります。1つは pytsk 以下に示すように、ファイルオブジェクトなどをCSVレポートの作成に使用します。
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)
上記のスクリプトを実行した後、検出された情報から情報を取得します lnk CSVレポートのファイル-
プリフェッチファイル
アプリケーションが特定の場所から初めて実行されるときはいつでも、Windowsは prefetch files。これらは、アプリケーションの起動プロセスを高速化するために使用されます。これらのファイルの拡張子は.PF これらはに保存されます ”\Root\Windows\Prefetch” フォルダ。
デジタルフォレンジックの専門家は、ユーザーの詳細とともに、指定された場所からのプログラム実行の証拠を明らかにすることができます。プリフェッチファイルは、プログラムが削除またはアンインストールされた後もエントリが残るため、審査官にとって有用なアーティファクトです。
以下に示すように、Windowsプリフェッチファイルから情報をフェッチするPythonスクリプトについて説明します。
Pythonスクリプトの場合、サードパーティのモジュールをインストールします。 pylnk, pytsk3 そして unicodecsv。前の章で説明したPythonスクリプトで、これらのライブラリをすでに使用していることを思い出してください。
から情報を抽出するには、以下の手順に従う必要があります prefetch ファイル-
まず、スキャンします .pf 拡張ファイルまたはプリフェッチファイル。
次に、署名の検証を実行して、誤検知を排除します。
次に、Windowsプリフェッチファイル形式を解析します。これはWindowsのバージョンによって異なります。たとえば、Windows XPの場合は17、WindowsVistaおよびWindows7の場合は23、Windows 8.1の場合は26、Windows10の場合は30です。
最後に、解析結果をCSVファイルに書き込みます。
Pythonコード
この目的のためにPythonコードを使用する方法を見てみましょう-
まず、次のPythonライブラリをインポートします-
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
ここで、コマンドラインハンドラーの引数を指定します。ここでは、2つの引数を受け入れます。最初は証拠ファイルへのパスであり、2番目は証拠ファイルのタイプです。また、プリフェッチファイルをスキャンするパスを指定するためのオプションの引数も受け入れます-
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)
次に、のオブジェクトを作成して証拠ファイルを解釈します。 TSKUtil ファイルシステムを反復処理して、で終わるファイルを見つけます .pf。それは定義することによって行うことができますmain() 次のように機能します-
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)
次に、以下に示すように、署名の検証を行うメソッドを定義します。
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)
ここで、Windowsプリフェッチファイルの処理を開始します。ここでは、WindowsXPのプリフェッチファイルの例を取り上げています-
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)
ここで、次のようにstructを使用して、プリフェッチされたファイルに埋め込まれたデータを抽出します。
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 ]
Windows XPのプリフェッチバージョンを提供したので、他のWindowsのプリフェッチバージョンが発生した場合はどうなりますか。次に、次のようなエラーメッセージを表示する必要があります-
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)
ここで、結果をCSVレポートに書き込む方法を次のように定義します。
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)
上記のスクリプトを実行した後、WindowsXPバージョンのプリフェッチファイルからスプレッドシートに情報を取得します。