
Инструмент сбора артефактов для *nix систем
fennec — это инструмент для сбора артефактов, написанный на Rust и предназначенный для реагирования на инциденты в системах на базе *nix. fennec позволяет вам написать файл конфигурации, который определяет, как собирать артефакты.
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 по пути `--osquery-path`
* `--output-format` : Выберите формат вывода. Поддерживаемые форматы:
* jsonl : Объекты JSON, разделенные новой строкой (по умолчанию)
* csv: Значения, разделенные запятыми
* kjson: Используйте этот формат, если хотите загрузить полученный файл на платформу анализа [Kuiper](https://github.com/DFIRKuiper/Kuiper).
* `-q`, `--quiet` : Не выводить журналы в `stdout`
* `--non-root`: Запустить Fennec без прав root. По умолчанию Fennec требует права `root` и завершится с сообщением об ошибке, если они отсутствуют.
* `--show-config` : Вывести встроенную конфигурацию и завершить работу
* `--show-embedded` : Показать встроенные файлы
* `-t`, `--timeout` : Устанавливает тайм-аут в секундах для каждого osquery в типе артефакта запроса
* `-u`, `--upload-artifact` : Загрузить пакет артефакта на удаленный сервер. Поддерживаемые протоколы:
* `s3` : Загрузить пакет артефакта в корзину S3
* `Format` : s3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@(http|https)://<HOSTNAME>:<PORT>/<BUCKET_NAME>:<PATH>
* `Example`: s3://minioadmin:minioadmin@http://192.168.100.190:9000/fennec:/
* `aws3` : Загрузить пакет артефакта в корзину AWS S3
* `Format` : aws3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@<AWS_REGOIN>.<BUCKET_NAME>:<PATH>
* `Example`: aws3://AKIAXXXXXXXXXXXXXXXXX:[email protected]:/
* `scp` : Загрузить пакет артефакта на сервер по протоколу SCP
* `Format` : scp://`<USERNAME>`:`<PASSWORD>`@`<HOSTNAME>`:`<PORT>`:`<PATH>`
* `Example`: scp://testusername:[email protected]:22:/dev/shm
* `-V`, `--version` : Вывести версию `fennec` и завершить работу
## Сборка с зависимостями 👨💻
fennec зависит от `osquery` для выполнения артефактов типа `query`. Каталог с именем `deps` содержит файл, который будет встроен в двоичный файл в зависимости от целевой ОС и архитектуры. Перед сборкой выполните следующие шаги:
* Измените файл конфигурации `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
then upload the resulting zip file to Kuiper, the following is an example:

## Configuration🔨
By default the configuration in the path `deps/<TARGET_OS>/fennec.yaml` will be embedded into the executable during compilation. The configuration is in YAML format and have two sections:
### Args
contains a list of arguments to be passed to the executable as command line arguments, the following is an example for the `args` section that will set the output format to `jsonl` and the log file name to `fennec.log`:```yaml
args:
- "--output-format"
- "jsonl"
- "--log-file"
- "fennec.log"
...
Аргументы командной строки будут использоваться в следующем порядке приоритетов:
Содержит список артефактов для сбора. Каждый артефакт содержит следующие поля:
stdout в случае артефакта commandВыполняет osquery SQL-запросы. Следующий пример артефакта для получения всех пользователей в системе:```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`, так и без него:
##### Without `regex` field```json
{
"line": 0,
"stdout": "root pts/1 2023-09-12T17:13:28+03:00 - 2023-09-12T17:13:28+03:00 (00:00)"
}
{ "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" }
#### Типы артефактов: Parse
Этот тип артефакта предоставляет возможность разбирать текстовые файлы с помощью регулярных выражений и возвращать данные в структурированном формате. Пример ниже разбирает логи доступа 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, который используется для сжатия старых логов для экономии места, и распаковывает их, а затем парсит. Регулярное выражение должно быть в формате именованных захватов, как описано в библиотеке regex для Rust. Ниже приведен пример записи доступа 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"
}
Это необязательное поле может использоваться для изменения имен полей результатов и выполнения постобработки, называемой модификаторами, над значением поля. Приведенный ниже пример покажет результаты разбора записи доступа 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`, мы добавляем следующую конфигурацию отображений (maps) в конфигурации артефактов:```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" }
#### Модификаторы
Модификаторы обеспечивают постобработку значений полей результатов артефактов. Например, переформатирование даты и времени. Продолжая приведенный выше пример, мы можем изменить формат даты и времени в поле `@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 | Преобразует временную метку эпохи в пользовательский формат даты и времени | Н/Д | укажите выходной формат даты и времени, по умолчанию `%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` с помощью выбранной платформы данных | Н/Д | Н/Д |
Модификатор `time_without_year_to_iso` работает следующим образом:
* Добавляет текущий год, затем проверяет, меньше ли время парсера текущего времени; если да, то это правильное время;
* в противном случае это предыдущий год.
Этот модификатор предполагает, что журналы относятся **ТОЛЬКО** к одному году. Используйте этот модификатор с осторожностью.
| Сведения об ОС | Архитектура | Успешно? | Подробности |
|---|
| 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 | ✅ |