Windowsの重要なアーティファクト-I
この章では、Microsoft Windowsフォレンジックに関連するさまざまな概念と、調査員が調査プロセスから取得できる重要な成果物について説明します。
前書き
アーティファクトは、コンピューターユーザーによって実行されるアクティビティに関連する重要な情報を持つ、コンピューターシステム内のオブジェクトまたは領域です。この情報の種類と場所は、オペレーティングシステムによって異なります。フォレンジック分析中、これらのアーティファクトは、調査員の観察を承認または不承認にする上で非常に重要な役割を果たします。
フォレンジックのためのWindowsアーティファクトの重要性
Windowsアーティファクトは、次の理由により重要性を帯びています-
世界のトラフィックの約90%は、オペレーティングシステムとしてWindowsを使用しているコンピューターから来ています。そのため、デジタルフォレンジックの審査官にとってWindowsアーティファクトは非常に重要です。
Windowsオペレーティングシステムは、コンピュータシステムでのユーザーアクティビティに関連するさまざまな種類の証拠を保存します。これは、デジタルフォレンジックにおけるWindowsアーティファクトの重要性を示すもう1つの理由です。
多くの場合、調査員は、ユーザーが作成したデータなど、古くて伝統的な領域を中心に調査を展開します。Windowsアーティファクトは、システムで作成されたデータやアーティファクトなどの非伝統的な領域に向けて調査を導くことができます。
非常に豊富なアーティファクトがWindowsによって提供されており、調査者だけでなく、非公式の調査を行う企業や個人にも役立ちます。
近年のサイバー犯罪の増加は、Windowsアーティファクトが重要であるもう1つの理由です。
WindowsアーティファクトとそのPythonスクリプト
このセクションでは、いくつかのWindowsアーティファクトとそれらから情報をフェッチするためのPythonスクリプトについて説明します。
ごみ箱
これは、フォレンジック調査のための重要なWindowsアーティファクトの1つです。Windowsのごみ箱には、ユーザーによって削除されたが、システムによってまだ物理的に削除されていないファイルが含まれています。ユーザーがファイルをシステムから完全に削除した場合でも、それは重要な調査ソースとして機能します。これは、審査官が削除されたファイルから、元のファイルパスやごみ箱に送信された時刻などの貴重な情報を抽出できるためです。
ごみ箱の証拠の保存は、Windowsのバージョンによって異なることに注意してください。次のPythonスクリプトでは、2つのファイルを作成するWindows7を扱います。$R リサイクルされたファイルの実際の内容を含むファイルと $I ファイルが削除されたときの元のファイル名、パス、ファイルサイズを含むファイル。
Pythonスクリプトの場合、サードパーティのモジュールをインストールする必要があります。 pytsk3, pyewf そして unicodecsv。使用できますpipそれらをインストールします。次の手順に従って、ごみ箱から情報を抽出できます。
まず、再帰的な方法を使用してスキャンする必要があります $Recycle.bin フォルダを開き、で始まるすべてのファイルを選択します $I。
次に、ファイルの内容を読み取り、使用可能なメタデータ構造を解析します。
次に、関連する$ Rファイルを検索します。
最後に、結果をCSVファイルに書き込んで確認します。
この目的のためにPythonコードを使用する方法を見てみましょう-
まず、次のPythonライブラリをインポートする必要があります-
from __future__ import print_function
from argparse import ArgumentParser
import datetime
import os
import struct
from utility.pytskutil import TSKUtil
import unicodecsv as csv
次に、コマンドラインハンドラーの引数を指定する必要があります。以下に示すように、ここでは3つの引数を受け入れることに注意してください。1つ目は証拠ファイルへのパス、2つ目は証拠ファイルのタイプ、3つ目はCSVレポートへの目的の出力パスです。
if __name__ == '__main__':
parser = argparse.ArgumentParser('Recycle Bin evidences')
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)
ここで、 main()すべての処理を処理する関数。検索します$I 次のようにファイル-
def main(evidence, image_type, report_file):
tsk_util = TSKUtil(evidence, image_type)
dollar_i_files = tsk_util.recurse_files("$I", path = '/$Recycle.bin',logic = "startswith")
if dollar_i_files is not None:
processed_files = process_dollar_i(tsk_util, dollar_i_files)
write_csv(report_file,['file_path', 'file_size', 'deleted_time','dollar_i_file', 'dollar_r_file', 'is_directory'],processed_files)
else:
print("No $I files found")
今、私たちが見つけた場合 $I ファイルの場合は、に送信する必要があります process_dollar_i() を受け入れる関数 tsk_util オブジェクトとのリスト $I 以下に示すように、ファイル-
def process_dollar_i(tsk_util, dollar_i_files):
processed_files = []
for dollar_i in dollar_i_files:
file_attribs = read_dollar_i(dollar_i[2])
if file_attribs is None:
continue
file_attribs['dollar_i_file'] = os.path.join('/$Recycle.bin', dollar_i[1][1:])
ここで、次のように$ Rファイルを検索します-
recycle_file_path = os.path.join('/$Recycle.bin',dollar_i[1].rsplit("/", 1)[0][1:])
dollar_r_files = tsk_util.recurse_files(
"$R" + dollar_i[0][2:],path = recycle_file_path, logic = "startswith")
if dollar_r_files is None:
dollar_r_dir = os.path.join(recycle_file_path,"$R" + dollar_i[0][2:])
dollar_r_dirs = tsk_util.query_directory(dollar_r_dir)
if dollar_r_dirs is None:
file_attribs['dollar_r_file'] = "Not Found"
file_attribs['is_directory'] = 'Unknown'
else:
file_attribs['dollar_r_file'] = dollar_r_dir
file_attribs['is_directory'] = True
else:
dollar_r = [os.path.join(recycle_file_path, r[1][1:])for r in dollar_r_files]
file_attribs['dollar_r_file'] = ";".join(dollar_r)
file_attribs['is_directory'] = False
processed_files.append(file_attribs)
return processed_files
ここで、定義します read_dollar_i() 読む方法 $Iつまり、ファイルはメタデータを解析します。我々は使用するだろうread_random()署名の最初の8バイトを読み取るメソッド。署名が一致しない場合、これはnoneを返します。その後、値を読み取って解凍する必要があります$I それが有効なファイルである場合はファイル。
def read_dollar_i(file_obj):
if file_obj.read_random(0, 8) != '\x01\x00\x00\x00\x00\x00\x00\x00':
return None
raw_file_size = struct.unpack('<q', file_obj.read_random(8, 8))
raw_deleted_time = struct.unpack('<q', file_obj.read_random(16, 8))
raw_file_path = file_obj.read_random(24, 520)
次に、これらのファイルを抽出した後、を使用して整数を人間が読める値に解釈する必要があります。 sizeof_fmt() 以下のように機能します−
file_size = sizeof_fmt(raw_file_size[0])
deleted_time = parse_windows_filetime(raw_deleted_time[0])
file_path = raw_file_path.decode("utf16").strip("\x00")
return {'file_size': file_size, 'file_path': file_path,'deleted_time': deleted_time}
今、私たちは定義する必要があります sizeof_fmt() 次のように機能します-
def sizeof_fmt(num, suffix = 'B'):
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
ここで、解釈された整数をフォーマットされた日付と時刻に次のように定義します。
def parse_windows_filetime(date_value):
microseconds = float(date_value) / 10
ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(
microseconds = microseconds)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
今、私たちは定義します write_csv() 次のように、処理された結果をCSVファイルに書き込む方法-
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
上記のスクリプトを実行すると、$ Iファイルと$ Rファイルからデータが取得されます。
ポストイット
Windows付箋は、書くという現実の習慣をペンと紙に置き換えます。これらのメモは、色やフォントなどのさまざまなオプションを使用してデスクトップに表示されていました。Windows7では、付箋ファイルはOLEファイルとして保存されるため、次のPythonスクリプトでは、このOLEファイルを調査して付箋からメタデータを抽出します。
このPythonスクリプトでは、サードパーティのモジュールをインストールする必要があります。 olefile, pytsk3, pyewfおよびunicodecsv。コマンドを使用できますpip それらをインストールします。
付箋ファイルから情報を抽出するために、以下で説明する手順に従うことができます。 StickyNote.sn −
まず、証拠ファイルを開き、すべてのStickyNote.sntファイルを見つけます。
次に、OLEストリームからメタデータとコンテンツを解析し、RTFコンテンツをファイルに書き込みます。
最後に、このメタデータのCSVレポートを作成します。
Pythonコード
この目的のためにPythonコードを使用する方法を見てみましょう-
まず、次のPythonライブラリをインポートします-
from __future__ import print_function
from argparse import ArgumentParser
import unicodecsv as csv
import os
import StringIO
from utility.pytskutil import TSKUtil
import olefile
次に、このスクリプト全体で使用されるグローバル変数を定義します-
REPORT_COLS = ['note_id', 'created', 'modified', 'note_text', 'note_file']
次に、コマンドラインハンドラーの引数を指定する必要があります。ここでは、3つの引数を受け入れることに注意してください。1つ目は証拠ファイルへのパス、2つ目は証拠ファイルのタイプ、3つ目は次のように目的の出力パスです。
if __name__ == '__main__':
parser = argparse.ArgumentParser('Evidence from Sticky Notes')
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_FOLDER', help="Path to report folder")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT_FOLDER)
今、私たちは定義します main() 以下に示すように、前のスクリプトと同様の関数-
def main(evidence, image_type, report_folder):
tsk_util = TSKUtil(evidence, image_type)
note_files = tsk_util.recurse_files('StickyNotes.snt', '/Users','equals')
次に、結果のファイルを繰り返し処理してみましょう。次に、parse_snt_file() ファイルを処理する関数を実行してから、RTFファイルを write_note_rtf() 次のような方法-
report_details = []
for note_file in note_files:
user_dir = note_file[1].split("/")[1]
file_like_obj = create_file_like_obj(note_file[2])
note_data = parse_snt_file(file_like_obj)
if note_data is None:
continue
write_note_rtf(note_data, os.path.join(report_folder, user_dir))
report_details += prep_note_report(note_data, REPORT_COLS,"/Users" + note_file[1])
write_csv(os.path.join(report_folder, 'sticky_notes.csv'), REPORT_COLS,report_details)
次に、このスクリプトで使用されるさまざまな関数を定義する必要があります。
まず最初に定義します create_file_like_obj() ファイルのサイズを読み取るための関数 pytskファイルオブジェクト。次に、定義しますparse_snt_file() ファイルのようなオブジェクトを入力として受け取り、付箋ファイルを読み取って解釈するために使用される関数。
def parse_snt_file(snt_file):
if not olefile.isOleFile(snt_file):
print("This is not an OLE file")
return None
ole = olefile.OleFileIO(snt_file)
note = {}
for stream in ole.listdir():
if stream[0].count("-") == 3:
if stream[0] not in note:
note[stream[0]] = {"created": ole.getctime(stream[0]),"modified": ole.getmtime(stream[0])}
content = None
if stream[1] == '0':
content = ole.openstream(stream).read()
elif stream[1] == '3':
content = ole.openstream(stream).read().decode("utf-16")
if content:
note[stream[0]][stream[1]] = content
return note
次に、定義してRTFファイルを作成します write_note_rtf() 次のように機能します
def write_note_rtf(note_data, report_folder):
if not os.path.exists(report_folder):
os.makedirs(report_folder)
for note_id, stream_data in note_data.items():
fname = os.path.join(report_folder, note_id + ".rtf")
with open(fname, 'w') as open_file:
open_file.write(stream_data['0'])
次に、ネストされた辞書を、CSVスプレッドシートにより適した辞書のフラットリストに変換します。それは定義することによって行われますprep_note_report()関数。最後に、定義しますwrite_csv() 関数。
def prep_note_report(note_data, report_cols, note_file):
report_details = []
for note_id, stream_data in note_data.items():
report_details.append({
"note_id": note_id,
"created": stream_data['created'],
"modified": stream_data['modified'],
"note_text": stream_data['3'].strip("\x00"),
"note_file": note_file
})
return report_details
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
上記のスクリプトを実行した後、付箋ファイルからメタデータを取得します。
レジストリファイル
Windowsレジストリファイルには、フォレンジックアナリストの情報の宝庫のような多くの重要な詳細が含まれています。これは、オペレーティングシステムの構成、ユーザーアクティビティ、ソフトウェアのインストールなどに関連する詳細を含む階層型データベースです。次のPythonスクリプトでは、から一般的なベースライン情報にアクセスします。SYSTEM そして SOFTWARE じんましん。
このPythonスクリプトでは、サードパーティのモジュールをインストールする必要があります。 pytsk3, pyewf そして registry。使用できますpip それらをインストールします。
Windowsレジストリから情報を抽出するには、以下の手順に従います。
まず、名前とパスで処理するレジストリハイブを見つけます。
次に、StringIOモジュールとRegistryモジュールを使用してこれらのファイルを開きます。
最後に、すべてのハイブを処理し、解析された値をコンソールに出力して解釈する必要があります。
Pythonコード
この目的のためにPythonコードを使用する方法を見てみましょう-
まず、次のPythonライブラリをインポートします-
from __future__ import print_function
from argparse import ArgumentParser
import datetime
import StringIO
import struct
from utility.pytskutil import TSKUtil
from Registry import Registry
ここで、コマンドラインハンドラーの引数を指定します。ここでは、2つの引数を受け入れます。1つ目は証拠ファイルへのパス、2つ目は以下に示すように証拠ファイルのタイプです。
if __name__ == '__main__':
parser = argparse.ArgumentParser('Evidence from Windows Registry')
parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE', help = "Evidence file format",
choices = ('ewf', 'raw'))
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE)
今、私たちは定義します main() 検索機能 SYSTEM そして SOFTWARE 内のじんましん /Windows/System32/config 次のようにフォルダ-
def main(evidence, image_type):
tsk_util = TSKUtil(evidence, image_type)
tsk_system_hive = tsk_util.recurse_files('system', '/Windows/system32/config', 'equals')
tsk_software_hive = tsk_util.recurse_files('software', '/Windows/system32/config', 'equals')
system_hive = open_file_as_reg(tsk_system_hive[0][2])
software_hive = open_file_as_reg(tsk_software_hive[0][2])
process_system_hive(system_hive)
process_software_hive(software_hive)
次に、レジストリファイルを開くための関数を定義します。この目的のために、ファイルのサイズをから収集する必要がありますpytsk 次のようなメタデータ-
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)
今、次の方法の助けを借りて、私たちは処理することができます SYSTEM> ハイブ−
def process_system_hive(hive):
root = hive.root()
current_control_set = root.find_key("Select").value("Current").value()
control_set = root.find_key("ControlSet{:03d}".format(current_control_set))
raw_shutdown_time = struct.unpack(
'<Q', control_set.find_key("Control").find_key("Windows").value("ShutdownTime").value())
shutdown_time = parse_windows_filetime(raw_shutdown_time[0])
print("Last Shutdown Time: {}".format(shutdown_time))
time_zone = control_set.find_key("Control").find_key("TimeZoneInformation")
.value("TimeZoneKeyName").value()
print("Machine Time Zone: {}".format(time_zone))
computer_name = control_set.find_key("Control").find_key("ComputerName").find_key("ComputerName")
.value("ComputerName").value()
print("Machine Name: {}".format(computer_name))
last_access = control_set.find_key("Control").find_key("FileSystem")
.value("NtfsDisableLastAccessUpdate").value()
last_access = "Disabled" if last_access == 1 else "enabled"
print("Last Access Updates: {}".format(last_access))
ここで、次のように、整数をフォーマットされた日付と時刻に解釈するための関数を定義する必要があります。
def parse_windows_filetime(date_value):
microseconds = float(date_value) / 10
ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds = microseconds)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
def parse_unix_epoch(date_value):
ts = datetime.datetime.fromtimestamp(date_value)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
次の方法で処理できます SOFTWARE ハイブ−
def process_software_hive(hive):
root = hive.root()
nt_curr_ver = root.find_key("Microsoft").find_key("Windows NT")
.find_key("CurrentVersion")
print("Product name: {}".format(nt_curr_ver.value("ProductName").value()))
print("CSD Version: {}".format(nt_curr_ver.value("CSDVersion").value()))
print("Current Build: {}".format(nt_curr_ver.value("CurrentBuild").value()))
print("Registered Owner: {}".format(nt_curr_ver.value("RegisteredOwner").value()))
print("Registered Org:
{}".format(nt_curr_ver.value("RegisteredOrganization").value()))
raw_install_date = nt_curr_ver.value("InstallDate").value()
install_date = parse_unix_epoch(raw_install_date)
print("Installation Date: {}".format(install_date))
上記のスクリプトを実行した後、Windowsレジストリファイルに保存されているメタデータを取得します。