🔍

log2timeline/plasoでAWS CloudTrailを扱うまで

2024/11/23に公開

はじめに

少し前に以下のブログを見て、plasoがAWS CloudTrailを扱えることを初めて知りました。
https://dfir-kev.medium.com/plaso-super-timelines-and-cloudtrails-46277ac07972

plasoはフォレンジック調査に用いるツールでログ等からタイムラインを作成します。
界隈では有名なツールでlog2timelineplasoで検索するといろいろ情報がでてきます。AWSも検索ワードに加わえるとEBSボリュームを対象にした使い方なんかがも見つかります。
今回は、先ほどの記事に倣ってCloudTrailのタイムラインを作成してみます。

タイムラインの作成

Plasoにするためのログ整形

ややこしいでしいですが、CloudTrailのログを使ってタイムラインを作るには、まずCloudTrailのログをPlasoで扱えるフォーマットである必要があります。
前述のブログに記載されている通りですが、S3に保存される形式とplasoが扱える形式には差分があるためです。

前述のブログではS3に保存されたCloudTrailの証跡を利用しています。基本的にはこちらのブログの方法を利用するほうが(後述するdfTimewolfより)扱いやすい気がします。
もう一つはdfTimewolfを使う方法で、こちらはcloudtrailから直接ログを取得します。

plasoが扱える形式

jsonl形式でイベントが格納されています。この形式がplasoが扱うことができるフォーマットです。

複数イベントを改行されて記載されるjsonl形式になっています。

{"EventId": "11111111-1111-1111-1111-111111111111","EventName": "ListBuckets","ReadOnly": 'true',"AccessKeyId": 'AKIAIOSFODNN7EXAMPLE',"EventTime": "2022-02-08 09:23:37+11:00","EventSource": "s3.amazonaws.com","Username": "myUserName","Resources": [],"CloudTrailEvent": <snip>}
{"EventId": "22222222-2222-2222-2222-222222222222","EventName": "ListBuckets","ReadOnly": 'true',"AccessKeyId": 'AKIAIOSFODNN7EXAMPLE',"EventTime": "2022-02-08 09:23:37+11:00","EventSource": "s3.amazonaws.com","Username": "myUserName2","Resources": [],"CloudTrailEvent": <snip>}

S3の証跡からログ整形

後述するCloudTrailのAPIから取得するより、基本的にはこちらのほうがやりやすいと思います。

証跡としてS3に保存される形式

CloudTrailからS3には以下のサンプルログのように保存されます。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/cloudtrail-logging-understanding-s3-entries.html

Records配下にリストで格納されていたり、時間表記が違ったり、いくつか部分的に異なっていることがわかります。

サンプル:証跡としてS3に保存される形式
sample(一部省略)
{
    "Records": [
    {
        "eventVersion": "1.03",
        "userIdentity": {
            "type": "IAMUser",
            "principalId": "111122223333",
            "arn": "arn:aws:iam::111122223333:user/myUserName",
            "accountId": "111122223333",
            "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
            "userName": "myUserName"
        },
        "eventTime": "2019-02-01T03:18:19Z",
        "eventSource": "s3.amazonaws.com",
        "eventName": "ListBuckets",
        "awsRegion": "us-west-2",
        "sourceIPAddress": "127.0.0.1",
        "userAgent": "[]",
        "requestParameters": {
            "host": [
                "s3.us-west-2.amazonaws.com"
            ]
        },
        "responseElements": null,
        "additionalEventData": {
            "SignatureVersion": "SigV2",
            "AuthenticationMethod": "QueryString",
            "aclRequired": "Yes"
    },
        "requestID": "47B8E8D397DCE7A6",
        "eventID": "cdc4b7ed-e171-4cef-975a-ad829d4123e8",
        "eventType": "AwsApiCall",
        "recipientAccountId": "444455556666",
        "tlsDetails": {
            "tlsVersion": "TLSv1.2",
            "cipherSuite": "ECDHE-RSA-AES128-GCM-SHA256",
            "clientProvidedHostHeader": "s3.amazonaws.com"
    }
  ]
}

plasoで扱えるログへの事前変換

S3に保存されたCloudTrailログをブログのPythonスクリプトを使ってplasoで変換できる形式にします。

利用するログはInbvictusが公開しているCloudTrailのデータを使います。これはS3に保存されているフォーマットと同じです。
https://github.com/invictus-ir/aws_dataset/tree/main

以下のようなディレクトリで作業します。

tree
|--aws-cloudtrail2plaso.py
|--aws_dataset
|  |--CloudTrail
|  |  |--218007301253_CloudTrail_us-east-1_20230710T1145Z_7xgocspSowgK0Gto.json
|  |  |--218007301253_CloudTrail_us-east-1_20230710T1145Z_s7dpHbl38neqZbm2.json
|  |  |--<snip>

input_directoryoutput_filepathを指定します。

$ python aws-cloudtrail2plaso.py ./aws_dataset/CloudTrail/ ./out.jsonl
Processed 1 of 55 files: ./aws_dataset/CloudTrail/218007301253_CloudTrail_us-east-1_20230710T1230Z_04rtp9DpvIpSZzMr.json
Processed 2 of 55 files: ./aws_dataset/CloudTrail/218007301253_CloudTrail_us-east-1_20230710T1215Z_nBsuPO1qSTEVerMD.json
...
<snip>
...
Processed 55 of 55 files: ./aws_dataset/CloudTrail/218007301253_CloudTrail_us-east-1_20230710T1220Z_8sBQhbu5YO94UV8p.json
Total records processed: 2900
Unique records found: 2900
Duplicates removed: 0
$ ls
aws-cloudtrail2plaso.py  aws_dataset  out.jsonl
out.jsonlの一部
out.jsonl
$ more out.jsonl
{"EventId": "27c5df2d-9179-4690-bcc4-94bde49772cd", "EventName": "DescribeEventAggregates", "ReadOnly": "true"
, "AccessKeyId": "ASIATFQR7NSCQCITXUXC", "EventTime": "2023-07-10 12:23:30+00:00", "EventSource": "health.amaz
onaws.com", "Username": "bert-jan", "Resources": [], "CloudTrailEvent": "{\"eventVersion\":\"1.08\",\"userIden
tity\":{\"type\":\"IAMUser\",\"principalId\":\"AIDATFQR7NSC5AU2ZV3IE\",\"arn\":\"arn:aws:iam::123837392027:use
r/bert-jan\",\"accountId\":\"123837392027\",\"accessKeyId\":\"ASIATFQR7NSCQCITXUXC\",\"userName\":\"bert-jan\"
,\"sessionContext\":{\"sessionIssuer\":{},\"webIdFederationData\":{},\"attributes\":{\"creationDate\":\"2023-0
7-10T12:13:16Z\",\"mfaAuthenticated\":\"true\"}},\"invokedBy\":\"health.amazonaws.com\"},\"eventTime\":\"2023-
07-10T12:23:30Z\",\"eventSource\":\"health.amazonaws.com\",\"eventName\":\"DescribeEventAggregates\",\"awsRegi
on\":\"us-east-1\",\"sourceIPAddress\":\"health.amazonaws.com\",\"userAgent\":\"AWSInternal\",\"requestParamet
ers\":{\"filter\":{\"startTimes\":[{\"from\":\"Jul3,2023,12:23:30PM\"}],\"eventStatusCodes\":[\"open\",\"upcom
ing\"]},\"aggregateField\":\"eventTypeCategory\"},\"responseElements\":null,\"requestID\":\"7811d310-eb20-4376
-a5af-482fbf452a78\",\"eventID\":\"27c5df2d-9179-4690-bcc4-94bde49772cd\",\"readOnly\":true,\"eventType\":\"Aw
sApiCall\",\"managementEvent\":true,\"recipientAccountId\":\"123837392027\",\"eventCategory\":\"Management\",\
"sessionCredentialFromConsole\":\"true\"}"}
<snip>

dfTimewolfを使ったログ収集

そもそもPlasoはどうやってログを取得するつもりだったんだろう?と思って調べたら見つけました。
Resipesを指定することで、Plasoで処理するためのデータを収集したり、Plasoの処理とTimesketchへのアップデートなどを行うツールです。
https://dftimewolf.readthedocs.io/en/dev/index.html
https://github.com/log2timeline/dftimewolf

導入ちょっと苦戦した

ドキュメントの導入手順はうまくいかなかったので、GitHubレポジトリにあるDockerfileを基にPoetryを使った。

dftimewolf -hを実行で利用できるRecipesの一覧を取得

git clone https://github.com/log2timeline/dftimewolf.git && cd dftimewolf
poetry install
poetry run dftimewolf -h
<snip>
Available recipes:

 aws_disk_to_gcp                    Copies EBS volumes from within AWS, and transfers them to GCP.
 aws_forensics                      Copies a volume from an AWS account to an analysis VM.
 aws_logging_collect                Collects logs from an AWS account and dumps the results to the filesystem.
 aws_logging_ts                     Collects logs from an AWS account, processes the logs with Plaso and uploads the result to Timesketch.
 aws_turbinia_ts                    Copies EBS volumes from within AWS, transfers them to GCP, analyses with Turbinia and exports the results to Timesketch.
 azure_forensics                    Copies a disk from an Azure account to an analysis VM.
<snip>

dftimewolf "recipe name" -hで各Recipeの使い方を表示

$ poetry run dftimewolf aws_logging_collect -h
[2024-11-13 00:28:14,002] [dftimewolf          ] SUCCESS  dfTimewolf tool initialized with UUID: 2505e11d-767c-43b8-b475-8cf9f65240fe
usage: dftimewolf aws_logging_collect [-h] [--profile_name PROFILE_NAME] [--query_filter QUERY_FILTER]
                                      [--start_time START_TIME] [--end_time END_TIME]
                                      region

Collects logs from an AWS account using a specified query filter and date ranges, and dumps them on the filesystem. If no args are provided this recipe will collect 90 days of logs for the default AWS profile.

positional arguments:
  region                AWS Region

options:
  -h, --help            show this help message and exit
  --profile_name PROFILE_NAME
                        Name of the AWS profile to collect logs from. (default: None)
  --query_filter QUERY_FILTER
                        Filter expression to use to query logs. (default: None)
  --start_time START_TIME
                        Start time for the query. (default: None)
  --end_time END_TIME   End time for the query. (default: None)

aws_logging_collectがcloudtrailからログを取得するRecipeになっている。
helpを見ても時間のフォーマットがわからなかったので、GitHubのこのあたりを見てRecipeの内容やオプションの推察をした。
boto3を使っているので、--start_timeなどはboto3のドキュメントを見ながら設定する。

AWSの認証情報は通常のboto3と同じで./aws/credentialsなどに置くか環境変数に設定すれば実行できる。profileの指定も可能。

poetry run dftimewolf aws_logging_collect --start_time "2024
-11-01 00:00:00" --end_time "2024-11-10 00:00:00" ap-northeast-1
実行ログ
$ poetry run dftimewolf aws_logging_collect --start_time "2024
-11-01 00:00:00" --end_time "2024-11-10 00:00:00" ap-northeast-1
[2024-11-13 00:33:59,453] [dftimewolf          ] SUCCESS  dfTimewolf tool initialized with UUID: 0c89e862-d840-4793-8de5-14dcf52df632
[2024-11-13 00:33:57,977] [dftimewolf          ] INFO     Loading recipe aws_logging_collect...
[2024-11-13 00:33:58,390] [dftimewolf          ] INFO     Loaded recipe aws_logging_collect with 2 modules
[2024-11-13 00:33:58,390] [dftimewolf          ] INFO     Running preflights...
[2024-11-13 00:33:59,252] [dftimewolf          ] INFO     Setting up modules...
[2024-11-13 00:33:59,253] [dftimewolf.state    ] INFO     Setting up module: AWSLogsCollector
[2024-11-13 00:33:59,253] [dftimewolf          ] INFO     Modules successfully set up!
[2024-11-13 00:33:59,253] [dftimewolf          ] INFO     Running modules...
[2024-11-13 00:33:59,253] [dftimewolf.state    ] INFO     Running module: AWSLogsCollector
[2024-11-13 00:33:59,254] [AWSLogsCollector    ] SUCCESS  Downloading logs to /tmp/tmp0z9lo0oa.jsonl
[2024-11-13 00:36:03,273] [AWSLogsCollector    ] SUCCESS  Downloaded logs to /tmp/tmp0z9lo0oa.jsonl
[2024-11-13 00:36:03,275] [dftimewolf.state    ] INFO     Module AWSLogsCollector finished execution
[2024-11-13 00:36:03,276] [dftimewolf          ] INFO     Modules run successfully!

実行ログから/tmp/tmp0z9lo0oa.jsonlにダウンロードされていることが確認できる。
中身は対象のAWSアカウントのCloudTrailで、Plasoで扱えるフォーマットに変換されています。

$ ls /tmp/ | grep jsonl
tmp0z9lo0oa.jsonl
$ cat /tmp/tmp0z9lo0oa.jsonl | wc -l
10599
$ more -1 /tmp/tmp0z9lo0oa.jsonl 
{"EventId": "33333333-3333-3333-3333-333333333333", "EventName": "AssumeRole", "ReadOnly": "true", "EventTime":

Plasoでのタイムライン作成

先ほどまでの結果を使って、いよいよPlasoでタイムラインを作成します。
今回は公式で公開されているDockerイメージを使います。

以下のようなディレクトリで作業します。

tree
|--data
|  |--evidences
|  |  |--output.jsonl // aws-cloudtrail2plaso.pyで生成したファイル

--helpで使い方が見れます。実際には時間指定などを入れてタイムライン作成することになると思います。

docker run --rm -v ./data/:/data log2timeline/plaso log2timeline --storage-file /data/evidences.plaso /data/evidences

実行すると./data/evidences.plasoが作成されます。この程度のログ量ではあれば時間はかからないはずです。

Plaso実行ログ
plaso - log2timeline version 20240826

Source path             : /data/evidences
Source type             : directory
Processing time         : 00:00:10

Tasks:          Queued  Processing      Merging         Abandoned       Total
                0       0               0               0               2

Identifier      PID     Status          Memory          Sources         Event Data      File
Main            7       completed       158.6 MiB       2 (0)           2900 (0)        
Worker_00       11      idle            104.9 MiB       1 (0)           0 (0)           OS:/data/evidences
Worker_01       15      idle            124.4 MiB       0 (0)           2900 (0)        OS:/data/evidences/output.jsonl
Worker_02       19      idle            103.8 MiB       0 (0)           0 (0)           
Worker_03       23      idle            103.9 MiB       0 (0)           0 (0)           
Worker_04       27      idle            104.0 MiB       0 (0)           0 (0)           
Worker_05       31      idle            104.0 MiB       0 (0)           0 (0)           
Worker_06       35      idle            104.1 MiB       0 (0)           0 (0)           
Worker_07       39      idle            104.2 MiB       0 (0)           0 (0)           
Worker_08       43      idle            104.1 MiB       0 (0)           0 (0)           
Worker_09       47      idle            104.3 MiB       0 (0)           0 (0)           
Worker_10       51      idle            104.4 MiB       0 (0)           0 (0)           
Worker_11       55      idle            104.3 MiB       0 (0)           0 (0)           
Worker_12       59      idle            104.3 MiB       0 (0)           0 (0)           
Worker_13       63      idle            104.5 MiB       0 (0)           0 (0)           
Worker_14       67      idle            104.6 MiB       0 (0)           0 (0)           

Processing completed.

おまけのPsort

Plasoと同じDockerイメージを使います。

以下のようなディレクトリで作業します。

tree
|--data
|  |--evidences
|  |  |--evidences.plaso // Plasoで生成したファイル

フィルターなどのオプションは以下から
https://plaso.readthedocs.io/en/latest/sources/user/Using-psort.html

docker run -v ./data/:/data log2timeline/plaso psort -w /data/timeline.log /data/evidences.plaso
実行ログ
plaso - psort version 20240826

Storage file            : /data/evidences.plaso
Processing time         : 00:00:03

Events:         Filtered        In time slice   Duplicates      MACB grouped    Total
                0               0               17410           182             20492

Identifier              PID     Status          Memory          Events          Tags            Reports
Main                    8       completed       135.1 MiB       20492 (0)       0 (0)           0 (0)

Processing completed.

data/timeline.logにはevidences.plasoから抽出されたログが出力される。(特にフィルターをかけていないのでそのまま出力)

$ more -2 data/timeline.log 
datetime,timestamp_desc,source,source_long,message,parser,display_name,tag
2023-07-10T11:42:18.000000+00:00,Recorded Time,LOG,AWS CloudTrail Log,User benjamin performed GetRegionOptStatus using access key AKIATF

おわりに

CloudTrailのログにlog2timelineを使いました。

Discussion