ma2tl:
macOS Forensic Timeline Generator
Using mac_apt Analysis Results
Japan Security Analyst Conference 2022
株式会社インターネットイニシアティブ
小林 稔

Who am I?

小林 稔
•
•

•

株式会社インターネットイニシアティブ セキュリティ本部 セキュリティ情報統括室
技術調査、社内インシデントレスポンス
外部活動
セキュリティキャンプ全国大会講師 2017-2019
Japan Security Analyst Conference Speaker 2018/2020
Black Hat USA 2018 Briefing Speaker
Twitter: @unkn0wnbit

2

Table of Contents

1. モチベーション
2. mac_aptの解析結果を用いたタイムライン作成方法
3. ma2tlの実装
4. Future work
5. まとめ
3

0

はじめに

4

はじめに

◦ 今回の発表内容は全てIntel Macで行った調査や検証に基づいている◦ M1 Macでは仕様が異なる点がある可能性がある◦ しかし、多くの点において、M1 Macの調査にも流用できるのではないかと思われる
5

1

モチベーション

6

フォレンジックにおけるタイムラインの必要性◦ アーティファクト収集後にやること▪ OSやアプリケーションのアーティファクトをツールで解析し、その結果からタイムラインを作成する◦ タイムライン作成の目的▪ 被害端末の状況（疑わしい点）を把握する▪ ユーザーやマルウェア、攻撃者の主だったアクティビティをタ
イムスタンプを基に整理する▸プログラム実行、ファイルダウンロード、ボリュームマウント、パーシ
ステンス設定など▪ タイムラインを作成することで、調査を行う上でのバイアス

や思考の飛躍、調査対象の漏れを低減することができる
7

どのツールを選択するか？

◦ Plaso▪ https://github.com/log2timeline/plaso▪ スーパータイムラインの自動生成▪ 様々なOSのアーティファクトを解析可能でmacOSにも対応▪ メンテナンスがアクティブ◦ Plasoはスーパータイムラインを生成可能🤩
% log2timeline.py --storage-file victim.plaso victim.E01% psort.py -o l2tcsv -w victime.csv victim.plaso
8Plasoで解析する

30GBのディスクイメージ処理に4日半以上かかる（デフォルト設定の場合）

9

Plasoによるスーパータイムライン

ほとんどがファイルシステムのイベント

10Plasoが生成するスーパータイムラインの問題点◦ デフォルトでファイルシステムの全てのメタデータが解析される▪ 調査上、重要でないファイル数の方が圧倒的に多い▪ 1つのファイルメタデータが4つのイベント(MACB)に分割される◦ システムログは行単位でイベントとして記録される▪ 単なる行単位のイベントではなく、何が起こったのか意味のある情報が欲しい（単なるログメッセージは必要ない）▪ Unified Logsは解析対象外◦ 結果として、スーパータイムラインのほとんどはファイルシステムとシステムログのイベントで埋まってしまう◦ そもそも、解析完了まで時間がかかりすぎる◦ フォレンジック解析者が最初に確認したい情報は、このような情
報ではない
11

フォレンジック解析者が欲しい情報と調査方針◦ マルウェア感染調査の場合▪ パーシステンスの設定状況▪ プログラムの実行履歴▪ ボリューム（USBメモリやディスクイメージ）マウント▪ ファイルダウンロード◦ このような情報を最も基本的なタイムラインとする◦ 必要に応じて調査の範囲を広げたり、より深く調査を行って、タイムラ
インを肉付けする◦ 調査のたたき台となるタイムラインが欲しい◦ アーティファクト解析にフォーカスしたツールの解析結果から、必要なア
クティビティだけでタイムラインを作成する方が要望に合致する

12

アーティファクト解析にフォーカスしたツール◦ 候補となる解析ツールは2つ▪ AutoMacTC▸https://github.com/CrowdStrike/automactc▸メンテナンスは停滞気味▪ mac_apt▸https://github.com/ydkhatri/mac_apt▸メンテナンスがアクティブ13

どちらのツールを使うべきか？

◦ メンテナンス状況および機能から鑑みて、薦められるのは「mac_apt」◦ なぜ、メンテナンスが重要なのか▪ macOSのアーティファクトはバージョンアップによって、ファイ

ル名やパスが変わることが多い▪ メンテナンスが行われていない解析ツールを使うと、時間とともに解析できないアーティファクトが増えていく◦ Unified Logsパーサーが実装されている▪ Unified Logsには有益な情報が多く記録されているが、OSSでパーサーが実装されているのはmac_aptのみ

14

ツール作成のモチベーション◦ mac_aptの解析結果からたたき台となるタイムラインを作成するのが現状ではベスト◦ mac_aptの解析結果からタイムラインを作成するには、様々なテーブルを参照する必要がある▪ 解析に使用したプラグインの数だけテーブルが作られる▪ Spotlightのテーブルはカラム数が多く煩雑◦ Unified Logsには有益な情報が含まれているが、mac_aptでは解析されない（パースはされる）▪ OSのバージョンアップによってメッセージが変わることがある▪ 手動で多くのフィルタリングを行うのは煩雑▪ フィルタリングを行っても出力結果が大量になる場合があり、目視で漏れなく確認するのは困難な場合がある◦ 自動的にフォレンジックタイムラインを生成するツールが欲しい！
15

類似ツール◦ mac_aptの解析結果を整理して表示および確認するという観点では以下のようなツールも存在する▪ mac_int▸https://burnhamforensics.com/projects/mac_int/▪ Building a Visualization Tool for mac_apt▸https://leahycenterblog.champlain.edu/2020/05/01/buildinga-visualization-tool-for-mac_apt/◦ 以下の点で異なる▪ mac_aptの解析結果をGUIで確認するのが主目的で、タイムラ
インを生成するツールではない▪ 現在はメンテナンスが行われていない

16

2

mac_aptの解析結果を用いた
タイムライン作成方法

17

mac_aptの解析結果◦ mac_aptが解析結果を保存するDB▪ mac_apt.db : アーティファクトの解析結果▪ UnifiedLogs.db : パースされたUnified Logs
▪ APFS_Volumes_<GUID>.db : パースされたAPFS
メタデータ▪ ExportおよびSPOTLIGHT_DATA : ディスクイメージからエクスポートされたアーティファクトファイルが保存されるフォルダ18

mac_apt.db

解析に使われたプラグインの数だけテーブルが作られる

19

UnifiedLogs.db

logコマンドと同等のフィルタをかけられる

20

APFS_Volumes_<GUID>.db
ファイルのタイムスタンプ等を確認できるが、整形されていない21

タイムラインの作成方針◦ タイムスタンプを持つ解析結果を中心に調査を行う▪ タイムスタンプがない場合、他のテーブルや
APFS_Volumes_xxxx.dbを参照する◦ 以下のアクティビティのタイムラインを作成する▪ パーシステンスの設定状況▪ プログラムの実行履歴▪ ボリューム（USBメモリやディスクイメージ）マウント▪ ファイルダウンロード

22

パーシステンスの調査 (1/3)◦ mac_apt.db : AutoStart▪ 最初は一般ユーザーの設定を確認する▪ タイムスタンプは記録されていない

自動実行プログラム

自動実行設定ファイル

23パーシステンスの調査 (2/3)◦ 自動実行の設定ファイルと実行ファイルのタ
イムスタンプをAPFS_Volumes_xxxx.dbで確認する
SELECT * FROM Combined_Paths LEFT JOIN Combined_Inodes ON Combined_Paths.CNID = Combined_Inodes.CNID WHERE
Combined_Paths.Path = "/path/to/file" LIMIT 1;

ファイル作成日時
24

パーシステンスの調査 (3/3)◦ 多くの自動実行プログラムは、右記のフォルダ以下に存在する◦ macOS 10.15以降、システムボ
リュームとデータボリュームが分割された▪ システムボリュームはread-onlyでマウ▪

ントされており、改ざんされる危険性は以前よりも低いmacOS 11以降はシステムボリュームに署名もされる

ma2tlのソースコードより抜粋

macOS 10.15以降、
リードオンリーでマウントされるため、改ざんされる
危険性は低いシステムボリューム◦ したがって、システムボリューム上のプログラムは、最初は調査対象から外しても良いと考えられる

データボリューム
25

プログラム実行履歴の調査◦ mac_apt.db : SpotlightShortcuts
Spotlightに入力した文字列▪ Spotlight経由で実行したアプリケーションが記録さタイムスタンプ
れる（最後に実行した日時のみ）
アプリケーションパス

アプリケーション名

26

ボリュームマウントの調査◦ mac_apt.db : RecentItems

ボリューム名は分かるが、タイムスタンプはない◦ mac_apt.db : FsEvents

アーティファクトファイルの修正日時（マウントしたタイムスタンプではない）

ボリュームマウントのフィルタリング条件（Volumes/以下にフォルダを作成）
27

ファイルダウンロードの調査 (1/5)◦ mac_apt.db : Quarantine▪ Webブラウザ等でダウンロードしたファイルに付与されるcom.apple.quarantine拡張属性と同じ内容が保存されるDBの解析結果
タイムスタンプ

アプリケーション名

ファイルのダウンロードURL

ダウンロード元URL

28

ファイルダウンロードの調査 (2/5)◦ mac_apt.db : Safari▪ ファイルの保存先が記録される▪ タイムスタンプがないため、QuarantineテーブルのDataUrlと紐づけて、タイムスタンプを推測する▪ Safariのダウンロード履歴はデフォルト1日で削除されるファイルのダウンロードURL

タイムスタンプなし

保存先ファイルパス

29

ファイルダウンロードの調査 (3/5)◦ mac_apt.db : Chrome

ファイルのダウンロードURL
ダウンロード開始日時

ダウンロード完了日時

ダウンロード元URL

保存先ファイルパス30

ファイルダウンロードの調査 (4/5)◦ mac_apt.db : SpotlightDataView
保存先ファイルパス

ファイルのダウンロード元URL

ダウンロード完了日時
31

ファイルダウンロードの調査 (5/5)◦ macOS標準コマンドのcurlでファイルをダウンロードされるとアーティファクトが残らない▪ curlが実行されたこと自体の痕跡は残るが、アクセス先は分からない◦ このような場合、マルウェア解析など他の調
査も必要

32

mac_aptの解析結果から確認できた情報 (1/2)◦ パーシステンスの設定状況▪ 自動実行の設定ファイルおよび自動実行されるプログラムは分かる▪ 上記のファイルのタイムスタンプも分かる◦ プログラムの実行履歴▪ Spotlight経由で実行されたアプリケーションは分かる▪ 最後に実行された日時は分かる▪ 他にタイムスタンプを伴う実行履歴はない
情報が足りない◦ ボリュームマウント▪ マウントしたボリューム名は分かる▪ マウントした正確な日時は不明◦ ファイルダウンロード▪ ダウンロード日時、ダウンロード元URL、保存先のファイルパスが分かる
33

mac_aptの解析結果から確認できた情報 (2/2)◦ mac_apt.dbの情報だけでは、タイムラインを作成するための情報が明らかに足りない◦ 他に調査すべきデータは？

34

“UnifiedLogs.db”
35UnifiedLogs.db is a goldmine (1/5)◦ Unified Logsには、他のアーティファクトに残らないプログラムの実行履歴やボリュームマウ
ント履歴など、タイムライン作成に必要な情報が記録されている◦ macOSフォレンジックにとって、まさに金鉱◦ しかし、このような情報を解説する記事やブ
ログは、何故かほぼ見かけない36

UnifiedLogs.db is a goldmine (2/5)◦ 商用製品であってもUnified Logsのパースは行うが、メッセージの内容に基づく解析は行わない◦ データベースのロード時間やフィルタリング等の処理時間もUnifiedLogs.dbを処理するより遅い
37

UnifiedLogs.db is a goldmine (3/5)

フィルタリングはできるが、処理はあまり速くない
UnifiedLogもパースはされる

38

UnifiedLogs.db is a goldmine (4/5)◦ logコマンド% log show --predicate 'FILTERING CONDITION' --start 'YYYY-MM-DD hh:mm:ss' --end 'YYYY-MM-DD hh:mm:ss'◦ フィルタリングキーワード
eventTypeThe type of event: activityCreateEvent, activityTransitionEvent, logEvent, signpostEvent, stateEvent,timesyncEvent, traceEvent and userActionEvent.
eventMessage
The pattern within the message text, or activity name of a log/trace entry.
messageType
For logEvent and traceEvent, the type of the message itself: default, info, debug, error or fault.
process
The name of the process the originated the event.
processImagePath
The full path of the process that originated the event.
sender
The name of the library, framework, kernel extension, or mach-o image, that originated the event.
senderImagePath
The full path of the library, framework, kernel extension, or mach-o image, that originated the event.
subsystem
The subsystem used to log an event. Only works with log messages generated with os_log(3) APIs.
category
The category used to log an event. Only works with log messages generated with os_log(3) APIs. When
category is used, the subsystem filter should also be provided.

39

UnifiedLogs.db is a goldmine (5/5)◦ Unified Logsフォーマット
Timestamp

Thread ID

Activity ID
Log Type

TTL% log show --info --debug --predicate 'sender == "TimeMachine"'
Filtering the log data using "sender == "TimeMachine""
Timestamp
ThreadType
Activity
PID
2021-11-09 18:41:17.571449+0900 0x23fb85
Info
0x0
259
[com.apple.TimeMachine:General] Mountpoint '/Volumes/TimeMachine' is still valid

Subsystem

Category

Process Name

Process ID

Sender (Library)TTL
0backupd: (TimeMachine)

Event Message▪ 実際は1行
40

Unified Logsの調査 (1/13)◦ プログラム実行履歴 (1)▪ アプリケーションバンドル (1)▪ macOS 10.15

Senderが「LaunchServices」かつメッセージが「LAUNCHING:0x」で始まる

起動元アプリケーション% log show --info --debug --predicate 'sender == "LaunchServices" AND eventMessage beginswith "LAUNCHING:0x"'
Filtering the log data using "sender == "LaunchServices" AND composedMessage BEGINSWITH "LAUNCHING:0x""
Timestamp
ThreadType
Activity
PID
TTL
2021-07-26 12:56:05.393696+0900 0x77b0f8
Default
0x0
78164 0Evernote: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCHING:0x0-0x68c68c Safari foreground=1 bringForward=1 seed=7287 userActivityCount=02021-07-27 14:43:16.966842+0900 0x61b6f
Default0x0
4820Electron: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCHING:0x0-0xe50e5 Safari foreground=1 bringForward=1 seed=683 userActivityCount=02021-07-29 11:26:05.382074+0900 0x102e4d 起動されたアプリケーション
Default
0x0
4980Dock: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCHING:0x0-0x189189 Safari foreground=1 bringForward=1 seed=1579 userActivityCount=02021-07-29 11:28:03.749083+0900 0x10362b
Default
0x029622 0open: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCHING:0x0-0x18e18e Safari foreground=1 bringForward=1 seed=1587 userActivityCount=041

Unified Logsの調査 (2/13)◦ 起動元アプリケーション例▪ Finder▪ Dock▪ Spotlight▪ loginwindow▸ログアウト時のダイアログで「再ログイン時にウィンドウを再度開く」
をチェックし、再ログインした際に実行されたアプリケーション▸「ユーザとグループ」の「ログイン項目」で指定されたアプリケーション▪ open▸openコマンドでアプリケーションを実行した場合

42

Unified Logsの調査 (3/13)◦ プログラム実行履歴 (2)▪ アプリケーションバンドル (2)▪ macOS 11.0.1 – 12.0.1

メッセージが「LAUNCH: 0x」に変わる% log show --info --debug --predicate 'sender == "LaunchServices" AND eventMessage beginswith "LAUNCH: 0x"'
Filtering the log data using "sender == "LaunchServices" AND composedMessage BEGINSWITH "LAUNCH: 0x""
起動元アプリケーション
Timestamp
ThreadType
Activity
PID
TTL
2021-08-19 14:19:54.319840+0900 0x1676
Default
0x04270Dock: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCH: 0x0-0x3d03d com.apple.Maps starting stopped process.
2021-08-19 14:21:52.526205+0900 0x21fb
Default
0x04270Dock: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCH: 0x0-0x4d04d com.apple.Safari starting stopped process.
起動されたアプリケーション
2021-08-19 14:48:38.978195+0900
0x186bDefault
0x0
3880Dock: (LaunchServices)[com.apple.processmanager:front-35286506]
LAUNCH: 0x0-0x3e03e com.apple.MobileSMS starting stopped process.
（アプリケーションバンドルID）
2021-08-19 14:57:09.230491+0900 0x246e
Default
0x0
3880Dock: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCH: 0x0-0x73073 com.apple.Safari starting stopped process.
2021-08-19 15:01:09.077054+0900 0x329
Info
0x0
153
0
loginwindow: (LaunchServices)[com.apple.launchservices:open] LAUNCH: 0x0-0x17017 com.apple.Terminal launched with launchInStoppedState=true, and not starting theapplication.
2021-08-19 15:01:09.228395+0900 0x329
Info
0x0
153
0
loginwindow: (LaunchServices)[com.apple.launchservices:open] LAUNCH: 0x0-0x18018 com.google.Chrome launched with launchInStoppedState=true, and not starting theapplication.

43

Unified Logsの調査 (4/13)◦ macOS 11以降の挙動 (1)▪ openコマンドで実行されたアプリケーションは記録されない▪ macOS 11.6のバグ（？）▸起動元が「loginwindow」、「SystemUIServer」、「SoftwareUpdateNotificationManager」以外はログが記録されない▸macOS 11.6.1以降は11.5.2までと同じ仕様に戻った▸macOS 11.6.xのリリースノートは公開されていないため詳細は不明● https://developer.apple.com/documentation/macosrelease-notes

44Unified Logsの調査 (5/13)◦ macOS 11以降の挙動 (2)▪ 起動元が「loginwindow」の場合▸「再ログイン時にウィンドウを再度開く」の対象になったアプリケーションは、記録されるログが「Type = Info」となり、メモリ上にのみ記録される● メッセージに「launchInStoppedState=true」が含まれる▸「ユーザとグループ」の「ログイン項目」で指定されたアプリケー
ションは、ログが「Type = Default」であるため、再起動後もログが残る「再ログイン時にウィンドウを再度開く」で実行されたアプリケーションのログ% log show --info --debug --predicate 'sender == "LaunchServices" and eventMessage beginswith "LAUNCH: 0x"' --start '2022-01-14'
Filtering the log data using "sender == "LaunchServices" AND composedMessage BEGINSWITH "LAUNCH: 0x""
Timestamp
ThreadType
Activity
PID
TTL
2022-01-14 08:21:21.918761+0900 0x21efb
Info
0x0
4067
0
loginwindow: (LaunchServices) [com.apple.launchservices:open]
LAUNCH: 0x0-0x9ee9ee com.apple.Terminal launched with launchInStoppedState=true, and not starting the application.

45

Unified Logsの調査 (6/13)◦ macOS 11以降の挙動 (3)▪ インターネットからダウンロードしたアプリケーションの初回実行時、Gakekeeperのチェックが行われる▪ その際のログは「Type = Info」で記録される（メモリ上にのみ記録される）▪ メッセージに「launchInQuarantine == true」が含まれる% log show --info --debug --predicate 'sender == "LaunchServices" and eventMessage beginswith "LAUNCH: 0x"' --start '2022-01-14 13:00:00'
Filtering the log data using "sender == "LaunchServices" AND composedMessage BEGINSWITH "LAUNCH: 0x""
Timestamp
ThreadType
Activity
PID
TTL
2022-01-14 13:17:44.405335+0900 0x4786
Default
0x0
11240Dock: (LaunchServices) [com.apple.processmanager:front-35286506]
LAUNCH: 0x0-0xd80d8 com.apple.Safari starting stopped process.
2022-01-14 13:18:44.148002+0900 0x50ea
Info
0x0
1124
0
Dock: (LaunchServices) [com.apple.launchservices:open] LAUNCH:
0x0-0xeb0eb com.apple.DiskImageMounter launched with launchInQuarantine == true, so not starting the application.
2022-01-14 13:19:19.907199+0900 0x523c
Info
0x0
1127
0
Finder: (LaunchServices) [com.apple.launchservices:open] LAUNCH:
0x0-0xf10f1 com.ridiculousfish.HexFiend launched with launchInQuarantine == true, so not starting the application.
2022-01-14 13:21:21.389996+0900 0x5472
Default
0x0
1127
0Finder: (LaunchServices) [com.apple.processmanager:front35286506] LAUNCH: 0x0-0x100100 com.ridiculousfish.HexFiend starting stopped process.

ダウンロードしたアプリケーションを実行（1回目）

ダウンロードしたアプリケーションを実行（2回目）

46

Unified Logsの調査 (7/13)◦ プログラム実行履歴 (3)▪ アプリケーションバンドルIDがない場合 (1)▸アプリケーションバンドルIDが「(null)」で記録される▸macOS 11以降
% log show --predicate 'eventMessage beginswith "LAUNCH: 0x"' --start '2022-01-12'
Filtering the log data using "composedMessage BEGINSWITH "LAUNCH: 0x""
Skipping info and debug messages, pass --info and/or --debug to include.
Timestamp
ThreadType
Activity
PID
TTL
2022-01-12 03:57:14.516187+0900 0x1693
Default
0x0
358
0Finder: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCH: 0x0-0x4d04d com.apple.DiskImageMounter starting stopped process.
2022-01-12 03:57:25.281130+0900 0x1d25
Default
0x0
358
0Finder: (LaunchServices)[com.apple.processmanager:front-35286506] LAUNCH: 0x0-0x50050 (null) starting stopped process.

47

Unified Logsの調査 (8/13)◦ プログラム実行履歴 (4)▪ アプリケーションバンドルがない場合 (2)▸(null)で記録されたアプリケーションの特定

プロセス名「lsd」、メッセージ「Nonfatal error enumerating」、(null)が記録される直前の時刻でフィルタリング% log show --predicate 'process == "lsd" and eventMessage beginswith "Non-fatal error enumerating"' --start '2022-01-12 03:57:24' -end '2022-01-12 03:57:26'
Filtering the log data using "process == "lsd" AND composedMessage BEGINSWITH "Non-fatal error enumerating""
Skipping info and debug messages, pass --info and/or --debug to include.
Timestamp
ThreadType
Activity
PID
TTL
2022-01-12 03:57:25.245990+0900 0x18fd
Default
0x0
3572
lsd: (LaunchServices)(null)が記録される直前[com.apple.launchservices:default] Non-fatal error enumerating at <private>, continuing: Error Domain=NSCocoaErrorDomain Code=260"The file “PlugIns” couldn’t
be opened because there is no such file." UserInfo={NSURL=PlugIns/ -（0.1秒程度以内？）
file:///Volumes/FakeTest/FakeApp.app/Contents/, NSFilePath=/Volumes/FakeTest/FakeApp.app/Contents/PlugIns,
NSUnderlyingError=0x7fc1edd290c0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}2022-01-12 03:57:25.255719+0900 0x18fd
Default
0x0
3572
lsd: (LaunchServices)[com.apple.launchservices:default] Non-fatal error enumerating at <private>, continuing: Error Domain=NSCocoaErrorDomain Code=260"The file “PlugIns” couldn’t be opened because there is no such file." UserInfo={NSURL=PlugIns/ -file:///Volumes/FakeTest/FakeApp.app/Contents/, NSFilePath=/Volumes/FakeTest/FakeApp.app/Contents/PlugIns,
NSUnderlyingError=0x7fc1edc2d550 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

アプリケーションパス
48

Unified Logsの調査 (9/13)◦ プログラム実行履歴 (5)▪ Gatekeeperに実行許可された未署名プログラム▪ 未署名DMGのマウント時のログも残る▪ 初回実行時にのみログが残る▪ macOS 10.15 – 12.0.1% log show --info --debug --predicate 'category == "gk" and eventMessage BEGINSWITH "temporarySigning"'
Filtering the log data using "category == "gk" AND composedMessage BEGINSWITH "temporarySigning""
Timestamp
ThreadType
Activity
PID
TTL
2021-08-10 16:41:11.730226+0900 0x1dc9
Default
0x0
212
0
syspolicyd: (Security)[com.apple.securityd:gk] temporarySigning type=3 matchFlags=0x0 path=/Users/macforensics/Downloads/FakeTest2-bash.dmg
2021-08-10 16:41:26.286794+0900 0x206c
Default
0x0
212
0
syspolicyd: (Security)[com.apple.securityd:gk] temporarySigning type=1 matchFlags=0x0 path=/Volumes/FakeTest2-bash/FakeApp.app/Contents/MacOS/FakeApp

実行許可されたプログラム
またはマウントしたDMG

49

Unified Logsの調査 (10/13)◦ プログラム実行履歴 (6)▪ adhoc署名されたプログラム▪ macOS 10.15 – 12.0.1% log show --predicate '(process == "kernel" and eventMessage beginswith "AMFI: " and eventMessage contains " adhoc ") or (process =="amfid" and eventMessage contains "signature")'Filtering the log data using "(process == "kernel" AND composedMessage BEGINSWITH "AMFI: " AND composedMessage CONTAINS " adhoc ") OR(process == "amfid" AND composedMessage CONTAINS "signature")"実行されたプログラムとSkipping info and debug messages, pass --info and/or --debug to include.
Timestamp
ThreadType
Activity
PIDadhoc署名である旨を示すログ
TTL
2022-01-19 16:06:09.001258+0900 0x3753
Default
0x0
00kernel: (AppleMobileFileIntegrity) AMFI:'/Users/macforensics/Downloads/SysJoker/types-config.ts' is adhoc signed.
2022-01-19 16:06:09.002729+0900 0x1c8c
Default
0x0
215
0
amfid:/Users/macforensics/Downloads/SysJoker/types-config.ts signature not valid: -67050

実行されたプログラムと署名が無効である旨を示すログ
50

Unified Logsの調査 (11/13)◦ プログラム実行履歴 (7)▪ セキュリティポリシーによる実行拒否▪ macOS 10.15

メッセージに「Security policy would notallow process」が含まれる% log show --predicate 'eventMessage contains "Security policy would not allow process"'
Filtering the log data using "composedMessage CONTAINS "Security policy would not allow process""
Skipping info and debug messages, pass --info and/or --debug to include.
Timestamp
ThreadType
Activity
PID
TTL
2022-01-12 02:35:12.569186+0900 0xa980
Default
0x0
00kernel: (AppleSystemPolicy) Security policy
would not allow process: 822, /Users/macforensics/Downloads/floss

実行が拒否されたプログラム▪ macOS 11.0.1 – 12.0.1

macOS 10.15と同じ条件で検索できるが、メッセージのフォーマットが少し変わる% log show --info --debug --predicate 'eventMessage contains "Security policy would not allow process"'
Filtering the log data using "composedMessage CONTAINS "Security policy would not allow process""
Timestamp
ThreadType
Activity
PID
TTL
2021-08-20 17:26:24.667681+0900 0x1b6ba
Default
0x0
00kernel: (AppleSystemPolicy) ASP: Security
policy would not allow process: 2954, /Users/macforensics/Downloads/floss

macOS 11以降追加された

51

Unified Logsの調査 (12/13)◦ ボリュームマウント (1)▪ macOS 10.15 – 12.0.1▪ HFS+

メッセージに「mounted」または「unmount」が含まれる% log show --info -debug --predicate 'process == "kernel" AND (eventMessage CONTAINS[cd] "mounted" OR eventMessage CONTAINS[cd]"unmount")'
Filtering the log data using "process == "kernel" AND (composedMessage CONTAINS[cd] "mounted" OR composedMessage CONTAINS[cd]"unmount")"
マウント
ファイルシステム
Timestamp
ThreadType
Activity
PID
TTL
2022-01-08 01:06:05.705926+0900 0x5d2a6
Default
0x0
00kernel: (HFS) hfs: mounted Script Debugger
8.0 on device disk4s2
2022-01-08 01:06:12.082076+0900 0x5d4e9
Default
0x0
00kernel: (HFS) hfs: unmount initiated on
Script Debugger 8.0 on device disk4s2

ボリューム名

アンマウント52

Unified Logsの調査 (13/13)◦ ボリュームマウント (2)▪ macOS 10.15 – 12.0.1▪ APFS（HFS+と同じフィルタリング条件）% log show --info -debug --predicate 'process == "kernel" AND (eventMessage CONTAINS[cd] "mounted" OR eventMessage CONTAINS[cd]"unmount")'
Filtering the log data using "process == "kernel" AND (composedMessage
CONTAINS[cd] "mounted" OR composedMessage CONTAINS[cd]ローカルスナップショットは"unmount")"
無視できる
Timestamp
ThreadType
Activity
PID
TTL
2022-01-08 01:04:48.911752+0900 0x5cfc7
Default
0x0
00kernel: (apfs) apfs_vfsop_unmount:2441:
disk1: unmounting volume 'com.apple.TimeMachine.2022-01-08-000409.local'
2022-01-08 01:04:48.911778+0900 0x5cfc7
Default
0x0
00kernel: (apfs) apfs_vfsop_unmount:2733:
snapshot deletion completed on the livefs
2022-01-08 01:04:48.911782+0900 0x5cfc7
Default
0x0
00kernel: (apfs) apfs_vfsop_unmount:2798:
nx_num_vols_mounted is 5
マウント or
アンマウント
ボリューム名2022-01-08
01:04:48.911788+0900
0x5cfc7
Default
0x0
00kernel: (apfs) apfs_vfsop_unmount:2807: all
done. going home. (numMountedAPFSVolumes 44)
ファイルシステム
2022-01-08 01:07:39.919784+0900 0x5d869
Default
0x0
00kernel: (apfs) apfs_vfsop_mount:2234:
disk5s1: mounted volume: FakeTest2-bash
2022-01-08 01:07:45.865955+0900 0x5d9f4
Default
0x0
00kernel: (apfs) apfs_vfsop_unmount:2441:
disk5: unmounting volume 'FakeTest2-bash'

53

3

ma2tlの実装

54

ma2tl実装方針 (1/2)◦ mac_apt to timeline → ma2tl◦ macOS 10.15以降をサポート◦ 前出した各アクティビティの確認手順を自動化▪ タイムスタンプを持つ解析結果は主要なデータからイベントを作る▸mac_apt.db : SpotlightShortcuts▪ タイムスタンプがない解析結果は関連するテーブルとイベントを作る▸mac_apt.db : AutoStart + APFS_Volumes_xxxx.db▸mac_apt.db : Safari + Quarantine▪ UnifiedLogs.dbにフィルタリングを行い、メッセージから必要な情報を抽出する

55

ma2tl実装方針 (2/2)◦ アクティビティの種類毎に解析プラグインを実装▪ アクティビティの記録は複数の解析結果にまたがって記録されている
場合があり、タイムラインとして出力するには情報の統合が必要▪ 新しいアクティビティが必要な場合、新しいプラグインを追加すればよい◦ Unified Logsのイベントメッセージは、意味を理解しやすい内容に置き換える◦ タイムラインのタイムレンジは手動で指定▪ スーパータイムラインではなく、調査のたたき台になる必要最低限のタイムラインが欲しい▪ フォレンジック解析者が気になる日時の範囲を指定する

56

ma2tlの構成

📜Analysis resultsof mac_apt

mac_apt.db
UnifiedLogs.db
APFS_Volumes_xxxx.db

Read⚙ma2tl
Invoke[🔌Plugins]🚀Program Execution
🤿Persistence🔽File Download
🗻Volume Mount📰ma2tl result
OutputSQLite
XLSX
TSV

57

プラグイン実装例：ファイルダウンロード①mac_apt.dbのSafariテーブルとQuarantineテーブルから、
ファイルダウンロードのイベントに必要な情報を構成する②データを抽出③重複判定④タイムラインに追加
58

プラグイン実装例：ボリュームマウント①ボリュームマウントのログをフィルタリング

無視するボリューム名

ボリュームをマウントした際のメッセージの正規表現②正規表現でメッセージからボリューム名を抽出する
59

実行例

mac_aptの解析結果が保存されているパス

ma2tlの出力先生成するタイムラインのタイムレンジ% python ./ma2tl.py -i ~/Documents/test -o ../ma2tl_output/test -s '2022-01-13 11:00:00' -e '202201-13 11:59:59' ALL
Output path: /Users/macforensics/Documents/GitHub/ma2tl_output/test
使用するプラグイン
MA2TL-INFO-Command line: ./ma2tl.py -i /Users/macforensics/Documents/test -o ../ma2tl_output/test -s
ALL: すべてのプラグイン
2022-01-13 11:00:00 -e 2022-01-13 11:59:59 ALL
MA2TL-INFO-Input path : /Users/macforensics/Documents/GitHub/forked/mac_apt_out/test
MA2TL-INFO--------------------------------------------------MA2TL-INFO-Running plugin FILE_DOWNLOAD
プラグインの出力
MA2TL.PLUGINS.FILE_DOWNLOAD-INFO-Detected 1 events.
MA2TL-INFO--------------------------------------------------MA2TL-INFO-Running plugin PERSISTENCE
MA2TL.PLUGINS.PERSISTENCE-INFO-Detected 8 events.
MA2TL-INFO--------------------------------------------------MA2TL-INFO-Running plugin PROG_EXEC
MA2TL.PLUGINS.PROG_EXEC-INFO-Detected 2 events.
MA2TL-INFO--------------------------------------------------MA2TL-INFO-Running plugin VOLUME_MOUNTMA2TL.PLUGINS.VOLUME_MOUNT-INFO-Detected 2 events.
60解析結果の例◦ macOS 11.5.2でSafariを使って、Script Debuggerをダ

ウンロードおよびインストール後、実行した際のタイムライン

タイムスタンプ（ユーザー指定タイムゾーン）
デフォルト：システムローカル
タイムスタンプ(UTC)

Safariを起動

アクティビティタイプ

アクティビティの説明

プラグイン名macOS 11なので初回のScript Debuggerの起動は残っていないDMGをダウンロード
ボリュームマウント
Script Debuggerからシステム環境設定を起動
61

ma2tl demo
62

ma2tl demo scenario①ツールに偽装したマルウェアのダウンローダーをダウンロード②ダウンローダーを実行⚙ 💻被害者

👾
😈攻撃者のサーバー

macOS 10.15.5

🚀④マルウェアの実行とパーシステンスの設定

👹
③マルウェア本体をダウンロード63

ma2tl demo timeline③👹マルウェア本体のダウンロードはcurlが使われたので、
ma2tlが生成するタイムラインには含まれない①👾

②⚙
adhoc署名されている④🚀

自動実行されるプログラムのパスが標準的なフォルダではない64

4

Future work

65

Future work

◦ より多くのmac_apt解析結果のサポート▪ タイムスタンプがある解析結果▪ APFS_Volumes_xxxx.dbと組み合わせてタイムスタンプがわかる解析結果◦ 継続的なUnified Logsの調査▪ アプリケーション実行▪ システムに実行拒否されたプログラム▪ exFAT, NTFS, SMBボリュームマウント◦ タイムラインの最適化▪ 重複イベントの排除▪ 注意を促すメッセージを入れるイベントの対象を拡大◦ メンテナンス▪ 新しいバージョンのmacOSでもma2tlが認識できるログメッセージが記録さ
れるか

66

5

まとめ

67

まとめ

◦ mac_aptの解析結果とUnified Logsからタイムラインを作成するハウハウを共有した◦ ma2tlの実装と機能を紹介した▪ mac_aptの解析結果とUnified Logsからタイムライ
ンを自動生成する▪ プラグインでサポートするアクティビティを増やせる◦ ma2tl GitHub repository▪ https://github.com/mnrkbys/ma2tl
68

Thank you for listening!

Any questions?
69

CREDITS for this presentation template and Icons

Special thanks to all the people who made andreleased these awesome resources for free:◦ Presentation template by SlidesCarnival70