MCPcopy Index your code
hub / github.com/AbdulRhmanAlfaifi/Fennec

github.com/AbdulRhmanAlfaifi/Fennec @v0.4.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.4.1 ↗ · + Follow
45 symbols 70 edges 8 files 20 documented · 44%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Fennec 🦊

fennec is an artifact collection tool written in Rust to be used during incident response on *nix based systems. fennec allows you to write a configuration file that contains how to collect artifacts.

Features 🌟

  • 🦀 A single statically compiled binary
  • 🔬 Execute any osquery SQL query
  • 💻 Execute system commands
  • 📚 Parse any text file using regex
  • 🧰 Ability to collect system logs and files
  • 🧱 Return data in structured manner
  • 🃏 Support multiple output formats (JSONL, CSV and KJSON)
  • 🤸‍♀️ Flexible configuration file
  • 💾 Directly write to ZIP file to save space
  • ⚡ Very fast!

Tests 🧪

OS Details Architecture Success? Details
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 requires libc >= 2.12
Ubuntu 20.04 aarch64
MacOS Monterey v12.0.1 x86_64 configuration tuning is required. If you have experience in MacOS artifact feel free to contribute

Usage ✍

fennec 0.4.0
AbdulRhman Alfaifi <aalfaifi@u0041.co>
Aritfact collection tool for *nix systems

USAGE:
    fennec [OPTIONS]

OPTIONS:
    -c, --config <FILE>
            Sets a custom config file (Embedded : true)

    -f, --log-file <FILE>
            Sets the log file name [default: fennec.log]

    -h, --help
            Print help information

    -l, --log-level <LEVEL>
            Sets the log level [default: info] [possible values: trace, debug, info, error]

    -o, --output <FILE>
            Sets output file name [default: ABDULRHMAN-PC.zip]

        --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]

    -q, --quiet
            Do not print logs to stdout

        --show-config
            Show the embedded configuration file

        --show-embedded
            Show the embedded files metadata

    -t, --timeout <SEC>
            Sets osquery queries timeout in seconds [default: 60]

    -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:XXX@us-east-1.fennecbucket:/
            * scp : Upload artifact package to a server using SCP protocol
                * Format : scp://<USERNAME>:<PASSWORD>@<HOSTNAME>:<PORT>:<PATH>
                * Example: scp://testusername:testpassword@192.168.100.190:22:/dev/shm

    -V, --version
            Print version information
  • -c, --config : Use the specified configuration file instead of the embedded configuration
  • -f, --log-file : Change the default name for the log file (default: fennec.log)
  • -h, --help : Print help message
  • -l, --log-level : Change the default log level (default: info)
  • -o, --output : Change the default output file name for the zip file (default: {HOSTNAME}.zip, where hostname is the runtime evaluated machine hostname)
  • --osquery-path : Path to osquery executable, This value will be used based on these conditions:
  • If osquery binary is embedded into fennec then extract it and dump it to --osquery-path
  • If osquery is not embedded into fennec then use the osquery binary in the path --osquery-path
  • --output-format : Choose the output format, Supported formats:
  • jsonl : A new line separated JSON objects (default)
  • csv: Comma separated values
  • kjson: Use this format if you want to upload the resulting file to Kuiper analysis platform.
  • -q, --quiet : Do not print logs to stdout
  • --show-config : Print the embedded configuration then exit
  • --show-embedded : Show embedded files
  • -t, --timeout : Sets the timeout in seconds for each osquery in query artifact type
  • -u, --upload-artifact : Upload artifact package to a remote server. Supported protocoles:
  • s3 : Upload artifact package to S3 bucket
    • Format : s3://:@(http|https)://:/:
    • Example: s3://minioadmin:minioadmin@http://192.168.100.190:9000/fennec:/
  • aws3 : Upload artifact package to AWS S3 bucket
    • Format : aws3://:@.:
    • Example: aws3://AKIAXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@us-east-1.fennecbucket:/
  • scp : Upload artifact package to a server using SCP protocol
    • Format : scp://<USERNAME>:<PASSWORD>@<HOSTNAME>:<PORT>:<PATH>
    • Example: scp://testusername:testpassword@192.168.100.190:22:/dev/shm
  • -V, --version : Print fennec version then exit

Compile with dependencies 👨‍💻

fennec depends on osquery to run the artifacts with the type query. The directory called deps contains the file that will be embedded into the binary depending on the target OS and architecture, Before compiling follow the below steps:

  • Modify the configuration file deps/<TARGET_OS>/fennec.yaml as needed

  • Build the binary using one of the commands below:

  • dynamically linked:

bash cargo build --release

  • statically linked (compile all dependencies):

bash RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target x86_64-unknown-linux-gnu

You can also use the precompiled binaries in the release section.

Examples 🚀

Default Configurations

The following is an example ran on Ubuntu 20 with the same configurations in this repo:

example

Using Fennec with Kuiper

To output data to Kuiper supported format execute Fennec with the following argument:

sudo ./fennec --output-format kjson

or add the following to the args section in the configuration:

args:
  - "--output-format"
  - "kjson"

recompile then execute:

sudo ./fennec

then upload the resulting zip file to Kuiper, the following is an example:

kuiper_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:

args:
- "--output-format"
- "jsonl"
- "--log-file"
- "fennec.log"
...

The command line arguments will be used in the following priorities:

  • arguments passed to the executable
  • arguments in the configuration file
  • default arguments

Artifacts

Contains a list of artifacts to be collected. Each artifact contains the following fields:

  • name: the name of the artifact, the results of the artifact will be written to a file with this name
  • type: the type of the artifact, the supported artifacts are:
  • query
  • collection
  • command
  • parse
  • description (optional): contain description about the artifact
  • quires OR paths OR commands: quires if the artifact type is query and it contains a list of osquery SQL queries. paths if the artifact type is collection OR parse and it contains a list of paths. commands if the artifact type is command and it contains a list commands. These names are for the sake of readability ,you can use any of them in any artifact type.
  • regex: this field is only used if the artifact type parse or command is used, this field contains regex to parse the text file in case of parse artifact or the stdout in case of command artifact
  • maps (optional): contains a list of mappers to modify key names and format values, check the maps section for more details

Artifact Types: Query

Execute osquery SQL queries. The following example artifact to retrieve all users on the system:

artifacts:
  - name: users
    type: query
    description: "List all local users"
    queries: 
      - 'select * from groups join user_groups using (gid) join users using (uid)'
...

Artifact Types: Collection

This artifact type collect files/folders specified in the field paths. The following is an example of this artifact type that collect system logs:

artifacts:
  - name: logs
    type: collection
    description: "Collect system logs"
    paths:
      - '/var/log/**/*'
...

Artifact Types: Command

Execute system commands using the shell command interpreter in the following priority:

  • $SHELL environment variable
  • /bin/bash
  • /bin/sh

This is an example of this artifact type that retrieve bad logins:

artifacts:
  - name: bad_logins
    type: command
    description: "Get failed logins (/var/log/btmp)"
    commands:
      - "lastb --time-format=iso | head -n -1"
    timeout: 30
    regex: '(?P<username>[^ ]+)[ ]+?(?P<tty>[^ ]+)[ ]+?(?P<src_ip>[^ ]+)?[ ]+?(?P<login_time>[^ ]+) - (?P<logout_time>[^ ]+)[ ]+?(\()?(?P<duration>[^ ]+)(\))'

This artifact type will execute the commands in the list commands and parse the stdout using the regular expression specified in the field regex. Note that the regex will only be processed on stdout stream and not stderr. Also, the field regex is optional. Here is an example of the results both using regex field and without it:

Without regex field
{
  "line": 0,
  "stdout": "root     pts/1                         2023-09-12T17:13:28+03:00 - 2023-09-12T17:13:28+03:00  (00:00)"
}
With regex field
{
  "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"
}

Artifact Types: Parse

This artifact type provides the ability to parse text files using regex and return the data it in structured format. The example bellow parse nginx access logs and return the results in structured format:

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>.*?)"'

This configuration will read the files in the path /var/log/nginx/access.* line by line and run the regex to extract fields. This artifact also check if the file is in gzip format which is used to compress old logs to save space and decompresses them and parses them. The regex should be in named captures format as documented in the rust regex library. The following is an example nginx access record before and after parsing:

  • original record

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"

  • parsed record

```json { "c_ip": "192.168.133.70", "remote_user": "-",

Extension points exported contracts — how you extend this code

ReadUntil (Interface)
(no doc) [2 implementers]
src/lib/traits.rs

Core symbols most depended-on inside this repo

format
called by 11
src/lib/mod.rs
map
called by 7
src/lib/mod.rs
get_param
called by 4
src/lib/modifiers.rs
read_until
called by 2
src/lib/traits.rs
set_timeout
called by 2
src/lib/mod.rs
init_logger
called by 1
src/main.rs
set_options
called by 1
src/lib/mod.rs
set_output_format
called by 1
src/lib/mod.rs

Shape

Method 24
Class 12
Enum 5
Function 3
Interface 1

Languages

Rust100%

Modules by API surface

src/lib/mod.rs18 symbols
src/lib/upload.rs8 symbols
src/lib/errors.rs7 symbols
src/lib/modifiers.rs5 symbols
src/main.rs4 symbols
src/lib/traits.rs2 symbols
build.rs1 symbols

For agents

$ claude mcp add Fennec \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page