
Outil de collecte d'artefacts pour systèmes *nix
fennec est un outil de collecte d'artefacts écrit en Rust, destiné à être utilisé lors de la réponse à incident sur les systèmes *nix. fennec permet d'écrire un fichier de configuration qui définit comment collecter les artefacts.
| Détails du système | Architecture | Succès ? | Détails |
|---|
| 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 nécessite libc >= 2.12 |
| Ubuntu 20.04 | aarch64 | ✅ | |
| MacOS Monterey v12.0.1 | x86_64 | ✅ | un ajustement de la configuration est nécessaire. Si vous avez de l'expérience dans les artefacts MacOS, n'hésitez pas à contribuer |
| 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` : Utiliser le fichier de configuration spécifié au lieu de la configuration intégrée
* `-f`, `--log-file` : Modifier le nom par défaut du fichier journal (par défaut : `fennec.log`)
* `-h`, `--help` : Afficher le message d'aide
* `-l`, `--log-level` : Modifier le niveau de journalisation par défaut (par défaut : `info`)
* `-o`, `--output` : Modifier le nom de fichier de sortie par défaut pour le fichier zip (par défaut : `{HOSTNAME}.zip`, où hostname est le nom de la machine évalué à l'exécution)
* `--osquery-path` : Chemin vers l'exécutable osquery. Cette valeur sera utilisée selon ces conditions :
* Si le binaire osquery est intégré dans `fennec`, alors l'extraire et le déposer dans `--osquery-path`
* Si osquery n'est pas intégré dans `fennec`, alors utiliser le binaire osquery au chemin `--osquery-path`
* `--output-format` : Choisir le format de sortie. Formats pris en charge :
* jsonl : Objets JSON séparés par des sauts de ligne (par défaut)
* csv : Valeurs séparées par des virgules
* kjson : Utiliser ce format si vous souhaitez télécharger le fichier résultant vers la plateforme d'analyse [Kuiper](https://github.com/DFIRKuiper/Kuiper).
* `-q`, `--quiet` : Ne pas afficher les journaux sur `stdout`
* `--non-root` : Exécuter Fennec avec des permissions non root. Par défaut, Fennec nécessite des permissions `root` et quittera avec un message d'erreur s'il n'est pas root.
* `--show-config` : Afficher la configuration intégrée puis quitter
* `--show-embedded` : Afficher les fichiers intégrés
* `-t`, `--timeout` : Définit le délai d'attente en secondes pour chaque osquery dans le type d'artefact de requête
* `-u`, `--upload-artifact` : Télécharger le package d'artefact vers un serveur distant. Protocoles pris en charge :
* `s3` : Télécharger le package d'artefact vers un bucket S3
* `Format` : s3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@(http|https)://<HOSTNAME>:<PORT>/<BUCKET_NAME>:<PATH>
* `Exemple` : s3://minioadmin:minioadmin@http://192.168.100.190:9000/fennec:/
* `aws3` : Télécharger le package d'artefact vers un bucket AWS S3
* `Format` : aws3://<ACCESS_KEY>:<SECRET_ACCESS_KEY>@<AWS_REGOIN>.<BUCKET_NAME>:<PATH>
* `Exemple` : aws3://AKIAXXXXXXXXXXXXXXXXX:[email protected]:/
* `scp` : Télécharger le package d'artefact vers un serveur en utilisant le protocole SCP
* `Format` : scp://`<USERNAME>`:`<PASSWORD>`@`<HOSTNAME>`:`<PORT>`:`<PATH>`
* `Exemple` : scp://testusername:[email protected]:22:/dev/shm
* `-V`, `--version` : Afficher la version de `fennec` puis quitter
## Compiler avec les dépendances 👨💻
fennec dépend de `osquery` pour exécuter les artefacts de type `query`. Le répertoire appelé `deps` contient le fichier qui sera intégré dans le binaire selon le système d'exploitation et l'architecture cibles. Avant de compiler, suivez les étapes ci-dessous :
* Modifier le fichier de configuration `deps/<TARGET_OS>/fennec.yaml` selon les besoins
* Construire le binaire en utilisant l'une des commandes ci-dessous :
* Lié dynamiquement : ```bash
cargo build --release
Vous pouvez également utiliser les binaires précompilés dans la section des versions.
Voici un exemple exécuté sur Ubuntu 20 avec les mêmes configurations de ce dépôt :

Pour générer des données au format supporté par Kuiper, exécutez Fennec avec l'argument suivant :```bash sudo ./fennec --output-format kjson
ou ajouter ce qui suit à la section `args` dans la configuration :```yaml
args:
- "--output-format"
- "kjson"
Recompilez puis exécutez :```bash sudo ./fennec
téléchargez ensuite le fichier zip résultant vers Kuiper, voici un exemple :

## Configuration🔨
Par défaut, la configuration située dans le chemin `deps/<TARGET_OS>/fennec.yaml` sera intégrée dans l'exécutable lors de la compilation. La configuration est au format YAML et comporte deux sections :
### Args
contient une liste d'arguments à passer à l'exécutable en tant qu'arguments de ligne de commande. Voici un exemple pour la section `args` qui définira le format de sortie sur `jsonl` et le nom du fichier journal sur `fennec.log` :```yaml
args:
- "--output-format"
- "jsonl"
- "--log-file"
- "fennec.log"
...
Les arguments de ligne de commande seront utilisés selon les priorités suivantes :
Contient une liste d'artifacts à collecter. Chaque artifact contient les champs suivants :
stdout dans le cas d'un artifact commandExécute des requêtes SQL osquery. L'exemple suivant d'artifact pour récupérer tous les utilisateurs du système :```yaml artifacts:
#### Types d'artefacts : Collection
Ce type d'artefact collecte les fichiers/dossiers spécifiés dans le champ **paths**. Voici un exemple de ce type d'artefact qui collecte les journaux système :```yaml
artifacts:
- name: logs
type: collection
description: "Collect system logs"
paths:
- '/var/log/**/*'
...
Exécutez des commandes système en utilisant l'interpréteur de commandes shell dans l'ordre de priorité suivant :
Ceci est un exemple de ce type d'artefact qui récupère les mauvaises connexions :```yaml artifacts:
Ce type d'artefact exécutera les commandes de la liste `commands` et analysera le `stdout` à l'aide de l'expression régulière spécifiée dans le champ `regex`. Notez que l'expression régulière ne sera traitée que sur le flux `stdout` et non sur `stderr`. De plus, le champ `regex` est facultatif. Voici un exemple des résultats avec et sans le champ `regex` :
##### Sans le champ `regex````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" }
#### Types d'artefacts : Analyse
Ce type d'artefact permet d'analyser des fichiers texte à l'aide d'expressions régulières et de renvoyer les données dans un format structuré. L'exemple ci-dessous analyse les logs d'accès nginx et renvoie les résultats dans un format structuré :```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>.*?)"'
Cette configuration lira les fichiers dans le chemin /var/log/nginx/access.* ligne par ligne et exécutera l'expression régulière pour extraire les champs. Cet artefact vérifie également si le fichier est au format gzip, qui est utilisé pour compresser les anciens journaux afin d'économiser de l'espace, les décompresse et les analyse. L'expression régulière doit être au format captures nommées comme documenté dans la bibliothèque regex de Rust. Voici un exemple d'enregistrement d'accès nginx avant et après l'analyse :
* enregistrement analysé ```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"
}
Ce champ optionnel peut être utilisé pour modifier les noms de champs de résultats et exécuter un post-traitement appelé modificateurs sur la valeur du champ.
L'exemple ci-dessous montrera les résultats pour l'analyse de l'enregistrement d'accès nginx sans maps :```yaml artifcats:
* enregistrement original```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"
Pour changer le nom du champ `time` en `@timestamp`, nous ajoutons la configuration de mappage suivante aux configurations d'artefact :```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
Après avoir exécuté l'outil de collecte avec la configuration sur le même journal d'accès nginx, nous obtenons la sortie suivante :```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" }
#### Modificateurs
Les modificateurs fournissent un post-traitement sur la valeur de champ des résultats d'artefact. Par exemple, le reformatage de la date et de l'heure. Poursuivant sur l'exemple ci-dessus, nous pouvons modifier le format de date et d'heure dans le champ `@timestamp` vers le format `%Y-%m-%d %H:%M:%S`. Nous pouvons ajouter ce qui suit aux configurations d'artefact pour y parvenir :```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'
Le résultat ressemblera à ceci :```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" }
Les modificateurs disponibles sont :
| Nom | Détails | format_entrée_temps | format_sortie_temps |
| ------------------------ | ------------------------------------------------------------ | -------------------------------------- | ------------------------------------------------------------ |
| epoch_to_iso | Convertit un timestamp epoch en un format de date et heure personnalisé | N/A | spécifiez le format de date et heure de sortie, par défaut est `%Y-%m-%d %H:%M:%S` |
| datetime_to_iso | Reformate la date et l'heure du format `input_time_format` vers le format `output_time_format` | spécifiez le format de date et heure d'entrée | spécifiez le format de date et heure de sortie, par défaut est `%Y-%m-%d %H:%M:%S` |
| time_without_year_to_iso | Formate la date et l'heure sans donnée d'année du format `input_time_format` vers le format `output_time_format` | spécifiez le format de date et heure d'entrée | spécifiez le format de date et heure de sortie, par défaut est `%Y-%m-%d %H:%M:%S` |
| to_int | Convertit des données string (comme les types d'artefacts `command` & `parse`) en entiers (`i64` c'est-à-dire entier 64 bits signé). Ceci est utile avec des champs comme la taille du fichier pour effectuer des vérifications comme `size < 1024` en utilisant la plateforme de données de notre choix | N/A | N/A |
Le modificateur `time_without_year_to_iso` fonctionne comme suit :
* Ajoute l'année en cours puis vérifie si le temps du parseur est inférieur au temps actuel ; si c'est le cas, alors c'est le bon moment
* sinon, il s'agit de l'année précédente
Ce modificateur suppose que les journaux concernent **UNIQUEMENT** une année, utilisez ce modificateur avec précaution