
*nixシステム向けアーティファクト収集ツール
fennec は、Rust で記述されたアーティファクト収集ツールであり、*nix ベースのシステムにおけるインシデントレスポンスで使用するためのものです。fennec では、アーティファクトを収集する方法を記載した設定ファイルを記述できます。
| OS 詳細 | アーキテクチャ | 成功? | 詳細 |
|---|---|---|---|
| Ubuntu 20.04.3 LTS | x86_64 | ✅ | |
| Ubuntu 19.04 | x86_64 | ✅ | |
| Ubuntu 18.04.6 LTS | x86_64 | ✅ | |
| Ubuntu 17.04 | x86_64 | ✅ | |
| Ubuntu 16.04.7 LTS | x86_64 | ✅ | |
| Ubuntu 15.10 | x86_64 | ✅ | |
| Ubuntu 14.04.6 LTS | x86_64 | ✅ | |
| Ubuntu 13.04 | x86_64 | ✅ | |
| Ubuntu 12.04.5 LTS | x86_64 | ✅ | |
| CentOS 8.4.2105 | x86_64 | ✅ | |
| CentOS 7.9.2009 | x86_64 | ✅ | |
| CentOS 6.10 | x86_64 | ✅ | |
| CentOS 5.11 | x86_64 | ❌ | osquery には libc >= 2.12 が必要です |
| Ubuntu 20.04 | aarch64 | ✅ | |
| MacOS Monterey v12.0.1 | x86_64 | ✅ | 設定の調整が必要です。MacOS アーティファクトの経験があれば、ぜひコントリビュートしてください |
| Oracle Linux Server 7.9 | x86_64 | ✅ |
fennec 0.4.1 AbdulRhman Alfaifi [email protected] Aritfact collection tool for *nix systems
USAGE: fennec [OPTIONS]
OPTIONS: -c, --config Sets a custom config file (Embedded : true)
-o, --output <FILE>
Sets output file name [default: ABDULRHMAN-PC.zip]
-l, --log-level <LEVEL>
Sets the log level [default: info] [possible values: trace, debug, info, error]
-f, --log-file <FILE>
Sets the log file name [default: fennec.log]
-u, --upload-artifact <CONFIG>...
Upload configuration string. Supported Protocols:
* s3 : Upload artifact package to S3 bucket (ex. minio)
* Format :
s3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@(http|https)://<HOSTNAME>:<PORT>/<BUCKET_NAME>:<PATH>
* Example (minio): s3://minioadmin:minioadmin@http://192.168.100.190:9000/fennec:/
* aws3 : Upload artifact package to AWS S3 bucket
* Format : aws3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@<AWS_REGOIN>.<BUCKET_NAME>:<PATH>
* Example: aws3://AKIAXXX:[email protected]:/
* scp : Upload artifact package to a server using SCP protocol
* Format : scp://<USERNAME>:<PASSWORD>@<HOSTNAME>:<PORT>:<PATH>
* Example: scp://testusername:[email protected]:22:/dev/shm
-q, --quiet
Do not print logs to stdout
-t, --timeout <SEC>
Sets osquery queries timeout in seconds [default: 60]
-h, --help
Print help information
--non-root
Run Fennec with non root permisions. This isn't recommended, most artifacts require root
permissions
--osquery-path <PATH>
Sets osquery path, if osquery is embedded it will be writen to this path otherwise the
path will be used to spawn osquery instance (Embedded : true) [default: ./osqueryd]
--output-format <FORMAT>
Sets output format [default: jsonl] [possible values: jsonl, csv, kjson]
--show-config
Show the embedded configuration file
--show-embedded
Show the embedded files metadata
-V, --version
Print version information
* `-c`, `--config` : 指定された設定ファイルを埋め込みの設定の代わりに使用します
* `-f`, `--log-file` : ログファイルのデフォルト名を変更します(デフォルト: `fennec.log`)
* `-h`, `--help` : ヘルプメッセージを表示します
* `-l`, `--log-level` : デフォルトのログレベルを変更します(デフォルト: `info`)
* `-o`, `--output` : zipファイルのデフォルト出力ファイル名を変更します(デフォルト: `{HOSTNAME}.zip`。hostnameは実行時に評価されるマシンのホスト名です)
* `--osquery-path` : osquery実行可能ファイルへのパス。この値は以下の条件に基づいて使用されます:
* osqueryバイナリが`fennec`に埋め込まれている場合、それを抽出して`--osquery-path`にダンプします
* osqueryが`fennec`に埋め込まれていない場合、`--osquery-path`のパスにあるosqueryバイナリを使用します
* `--output-format` : 出力形式を選択します。サポートされている形式:
* jsonl : 改行区切りのJSONオブジェクト(デフォルト)
* csv: カンマ区切りの値
* kjson: 結果ファイルを[Kuiper](https://github.com/DFIRKuiper/Kuiper)分析プラットフォームにアップロードする場合にこの形式を使用します
* `-q`, `--quiet` : `stdout`へのログ出力を行いません
* `--non-root`: Fennecを非root権限で実行します。デフォルトでは、Fennecは`root`権限を必要とし、rootでない場合はエラーメッセージを表示して終了します
* `--show-config` : 埋め込み設定を表示して終了します
* `--show-embedded` : 埋め込みファイルを表示します
* `-t`, `--timeout` : クエリアーティファクトタイプの各osqueryのタイムアウトを秒単位で設定します
* `-u`, `--upload-artifact` : アーティファクトパッケージをリモートサーバーにアップロードします。サポートされているプロトコル:
* `s3` : アーティファクトパッケージをS3バケットにアップロードします
* `形式` : s3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@(http|https)://<HOSTNAME>:<PORT>/<BUCKET_NAME>:<PATH>
* `例` : s3://minioadmin:minioadmin@http://192.168.100.190:9000/fennec:/
* `aws3` : アーティファクトパッケージをAWS S3バケットにアップロードします
* `形式` : aws3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@<AWS_REGOIN>.<BUCKET_NAME>:<PATH>
* `例` : aws3://AKIAXXXXXXXXXXXXXXXXX:[email protected]:/
* `scp` : SCPプロトコルを使用してアーティファクトパッケージをサーバーにアップロードします
* `形式` : scp://`<USERNAME>`:`<PASSWORD>`@`<HOSTNAME>`:`<PORT>`:`<PATH>`
* `例` : scp://testusername:[email protected]:22:/dev/shm
* `-V`, `--version` : `fennec`のバージョンを表示して終了します
## 依存関係と共にコンパイルする 👨💻
fennecは`query`タイプのアーティファクトを実行するために`osquery`に依存しています。`deps`ディレクトリには、ターゲットOSとアーキテクチャに応じてバイナリに埋め込まれるファイルが含まれています。コンパイルする前に、以下の手順に従ってください:
* 必要に応じて設定ファイル`deps/<TARGET_OS>/fennec.yaml`を修正します
* 以下のコマンドのいずれかを使用してバイナリをビルドします:
* 動的リンク: ```bash
cargo build --release
リリースセクションのプリコンパイル済みバイナリも使用できます。
以下は、このリポジトリと同じ設定で Ubuntu 20 上で実行した例です:

Kuiper がサポートする形式でデータを出力するには、以下の引数を指定して Fennec を実行します:```bash sudo ./fennec --output-format kjson
または、設定の `args` セクションに以下を追加してください:```yaml
args:
- "--output-format"
- "kjson"
再コンパイルしてから実行:```bash sudo ./fennec
次に、結果のzipファイルをKuiperにアップロードします。以下が例です:

## Configuration🔨
デフォルトでは、パス `deps/<TARGET_OS>/fennec.yaml` の設定がコンパイル時に実行ファイルに埋め込まれます。設定はYAML形式で、2つのセクションがあります:
### Args
実行ファイルにコマンドライン引数として渡される引数のリストが含まれます。以下は、出力形式を `jsonl` に設定し、ログファイル名を `fennec.log` に設定する `args` セクションの例です:```yaml
args:
- "--output-format"
- "jsonl"
- "--log-file"
- "fennec.log"
...
コマンドライン引数は、以下の優先順位で使用されます:
収集するartifactのリストを含みます。各artifactには以下のフィールドがあります:
stdoutを解析するための正規表現を含みます。osquery SQLクエリを実行します。次の例は、システム上のすべてのユーザーを取得するartifactです:```yaml artifacts:
#### アーティファクトタイプ: 収集
このアーティファクトタイプは、**paths**フィールドで指定されたファイルやフォルダを収集します。以下は、システムログを収集するこのアーティファクトタイプの例です。```yaml
artifacts:
- name: logs
type: collection
description: "Collect system logs"
paths:
- '/var/log/**/*'
...
シェルコマンドインタプリタを使用してシステムコマンドを以下の優先順位で実行します:
これは不正なログインを取得するこのアーティファクトタイプの例です:```yaml artifacts:
このアーティファクトタイプは、リスト `commands` 内のコマンドを実行し、`stdout` をフィールド `regex` で指定された正規表現を使用して解析します。この正規表現は `stdout` ストリームに対してのみ処理され、`stderr` には適用されないことに注意してください。また、`regex` フィールドはオプションです。以下に、`regex` フィールドを使用した場合と使用しない場合の結果の例を示します。
##### `regex` フィールドなし```json
{
"line": 0,
"stdout": "root pts/1 2023-09-12T17:13:28+03:00 - 2023-09-12T17:13:28+03:00 (00:00)"
}
regex フィールドを使用した```json{ "username": "root", "tty": "pts/1", "src_ip": null, "login_time": "2023-09-12 14:13:28", "logout_time": "2023-09-12T17:13:28+03:00", "duration": "00:00", "@timestamp": "2023-09-12 14:13:28" }
#### 成果物タイプ: パース
この成果物タイプは、正規表現を使用してテキストファイルをパースし、データを構造化形式で返す機能を提供します。以下の例では、nginxアクセスログをパースし、結果を構造化形式で返します:```yaml
artifcats:
- name: nginx_access
type: parse
description: "Nginx access logs"
paths:
- /var/log/nginx/access.*
regex: '(?P<c_ip>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) - (?P<remote_user>[^ ]+) \[(?P<time>[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2} \+[0-9]{4})\] "(?P<method>[A-Z]+)?[ ]?(?P<uri>.*?)[ ]?(HTTP/(?P<http_prot>[0-9\.]+))?" (?P<status_code>[0-9]{3}) (?P<body_bytes_sent>[0-9]+) "(?P<referer>.*?)" "(?P<user_agent>.*?)"'
この設定は、パス /var/log/nginx/access.* のファイルを一行ずつ読み込み、正規表現を実行してフィールドを抽出します。このアーティファクトは、ファイルが gzip 形式(古いログを圧縮して容量を節約するために使用される)かどうかを確認し、解凍して解析します。正規表現は、rust regex library で文書化されている 名前付きキャプチャ 形式に従う必要があります。以下は、解析前と解析後のnginxアクセスレコードの例です:
* 解析されたレコード ```json
{
"c_ip": "192.168.133.70",
"remote_user": "-",
"time": "23/Jan/2022:19:14:37 +0000",
"method": "GET",
"uri": "/blog/",
"http_prot": "1.1",
"status_code": "200",
"body_bytes_sent": "2497",
"referer": "https://u0041.co/",
"user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",
"full_path": "/var/log/nginx/access.log.9.gz"
}
このオプションフィールドは、結果のフィールド名を変更したり、フィールド値に対して「modifiers」と呼ばれる後処理を実行するために使用できます。以下の例では、マップを使用せずにnginxアクセスレコードを解析した結果を示しています。
* 元のレコード```verilog
192.168.133.70 - - [23/Jan/2022:19:14:37 +0000] "GET /blog/ HTTP/1.1" 200 2497 "https://u0041.co/" "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"
フィールド名 `time` を `@timestamp` に変更するには、以下のマップ構成をアーティファクト構成に追加します。```yaml
artifcats:
- name: nginx_access
type: parse
description: "Nginx access logs"
paths:
- /var/log/nginx/access.*
regex: '(?P<c_ip>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) - (?P<remote_user>[^ ]+) \[(?P<time>[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2} \+[0-9]{4})\] "(?P<method>[A-Z]+)?[ ]?(?P<uri>.*?)[ ]?(HTTP/(?P<http_prot>[0-9\.]+))?" (?P<status_code>[0-9]{3}) (?P<body_bytes_sent>[0-9]+) "(?P<referer>.*?)" "(?P<user_agent>.*?)"'
maps:
- from: time #change field name from
to: '@timestamp' # to this name
同じnginxアクセスログに対して、設定を用いて収集ツールを実行した後、以下の出力が得られます。```json { "c_ip": "192.168.133.70", "remote_user": "-", "@timestamp": "23/Jan/2022:19:14:37 +0000", "method": "GET", "uri": "/blog/", "http_prot": "1.1", "status_code": "200", "body_bytes_sent": "2497", "referer": "https://u0041.co/", "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0", "full_path": "/var/log/nginx/access.log.9.gz" }
#### Modifiers
modifiersは、アーティファクト結果のフィールド値に対して後処理を提供します。例えば、日付と時刻の再フォーマットなどです。上記の例を続けて、フィールド `@timestamp` の日付と時刻の形式を `%Y-%m-%d %H:%M:%S` に変更できます。これを実現するには、次のようにアーティファクト設定に追加します:```yaml
artifacts:
- name: nginx_access
type: parse
description: "Nginx access logs"
paths:
- /var/log/nginx/access.*
regex: '(?P<c_ip>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) - (?P<remote_user>[^ ]+) \[(?P<time>[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2} \+[0-9]{4})\] "(?P<method>[A-Z]+)?[ ]?(?P<uri>.*?)[ ]?(HTTP/(?P<http_prot>[0-9\.]+))?" (?P<status_code>[0-9]{3}) (?P<body_bytes_sent>[0-9]+) "(?P<referer>.*?)" "(?P<user_agent>.*?)"'
maps:
- from: time
to: "@timestamp"
modifier:
name: datetime_to_iso
parameters:
input_time_format: '%d/%b/%Y:%H:%M:%S %z'
output_time_format: '%Y-%m-%d %H:%M:%S'
結果のレコードは次のようになります:```json { "c_ip": "192.168.133.70", "remote_user": "-", "@timestamp": "2022-01-23 19:14:37", "method": "GET", "uri": "/blog/", "http_prot": "1.1", "status_code": "200", "body_bytes_sent": "2497", "referer": "https://u0041.co/", "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0", "full_path": "/var/log/nginx/access.log.9.gz" }
使用可能な修飾子は以下のとおりです:
| 名前 | 詳細 | input_time_format | output_time_format |
| --- | --- | --- | --- |
| epoch_to_iso | エポックタイムスタンプをカスタム日時形式に変換します | N/A | 出力する日時形式を指定します。デフォルトは `%Y-%m-%d %H:%M:%S` |
| datetime_to_iso | `input_time_format` の形式から `output_time_format` の形式へ日時を再フォーマットします | 入力する日時形式を指定します | 出力する日時形式を指定します。デフォルトは `%Y-%m-%d %H:%M:%S` |
| time_without_year_to_iso | 年の情報がない日時を `input_time_format` の形式から `output_time_format` の形式へフォーマットします | 入力する日時形式を指定します | 出力する日時形式を指定します。デフォルトは `%Y-%m-%d %H:%M:%S` |
| to_int | 文字列データ(`command` や `parse` アーティファクトタイプなど)を整数(`i64`、すなわち符号付き64ビット整数)に変換します。これはファイルサイズのようなフィールドで有用であり、選択したデータプラットフォームを使用して `size < 1024` のようなチェックが可能になります | N/A | N/A |
`time_without_year_to_iso` 修飾子は次のように動作します:
* 現在の年を追加し、パーサーの時刻が現在時刻より前であれば正しい時刻と判断します
* そうでなければ前年とみなします
この修飾子はログが **1年間のみ** であることを前提としています。注意して使用してください。