149 lines
6.0 KiB
Markdown
149 lines
6.0 KiB
Markdown
# NetScaler Triage
|
|||
|
|
|
||
|
|
Offline forensic triage for Citrix NetScaler ADC and Gateway logs. Point it at a
|
||
|
|
folder or archive to find suspicious requests, public indicators, encoded
|
||
|
|
payloads, update records and related events across logs.
|
||
|
|
|
||
|
|
Original inputs are not modified. Payloads are decoded as data, never executed
|
||
|
|
or downloaded. A finding is an investigation lead, **not proof of compromise**.
|
||
|
|
|
||
|
|
## Quick start
|
||
|
|
|
||
|
|
Requires **Python 3.14 or newer**.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
git clone https://tea.karlcom.de/karl/NetScaler_forensik.git
|
||
|
|
cd NetScaler_forensik
|
||
|
|
python3 -m venv .venv
|
||
|
|
source .venv/bin/activate
|
||
|
|
python -m pip install .
|
||
|
|
netscaler-triage ./logs.7z
|
||
|
|
```
|
||
|
|
|
||
|
|
On Windows PowerShell, create and activate the environment with:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
py -3.14 -m venv .venv
|
||
|
|
.venv\Scripts\Activate.ps1
|
||
|
|
python -m pip install .
|
||
|
|
netscaler-triage .\logs.7z
|
||
|
|
```
|
||
|
|
|
||
|
|
Installation may require internet access. Analysis runs offline.
|
||
|
|
|
||
|
|
## Everyday use
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# Unpacked logs, an archive, or multiple appliance exports
|
||
|
|
netscaler-triage ./logs
|
||
|
|
netscaler-triage export.tar.gz
|
||
|
|
netscaler-triage ./appliance-a ./appliance-b export.zip
|
||
|
|
|
||
|
|
# Discover inputs in the current directory
|
||
|
|
netscaler-triage
|
||
|
|
|
||
|
|
# Encrypted archive: prompt for a password without displaying it
|
||
|
|
netscaler-triage export.7z --password
|
||
|
|
```
|
||
|
|
|
||
|
|
ZIP (including ZipCrypto/AES), TAR, TAR.GZ/TGZ, GZIP and 7z inputs are supported,
|
||
|
|
including nested archives within preparation limits. Unsupported formats are
|
||
|
|
reported. `--password VALUE` is also supported, but can expose the password in
|
||
|
|
shell history or process listings. Passwords are not stored in results.
|
||
|
|
|
||
|
|
The tool prints the result directory. Use `--output PATH` to choose a new one;
|
||
|
|
existing results are not overwritten. Appliance grouping is inferred from
|
||
|
|
directories; review the preparation manifest for unusual export layouts.
|
||
|
|
|
||
|
|
## Read the results
|
||
|
|
|
||
|
|
| File | Purpose |
|
||
|
|
| --- | --- |
|
||
|
|
| `summary.json` | Processing status, counts and incomplete coverage |
|
||
|
|
| `findings.jsonl` | Events, source lines, matching rules and decoding explanations |
|
||
|
|
| `IOCS.csv` | Exact SIEM search values and separate defanged display values |
|
||
|
|
| `updates.jsonl` | Installation and software-version evidence |
|
||
|
|
| `correlations.jsonl` | Related events on the same appliance; temporal candidates, not causal proof |
|
||
|
|
| `coverage.json` | Per-file coverage and errors |
|
||
|
|
| `input_manifest.json` | Original relative paths and SHA-256 checksums |
|
||
|
|
| `preparation_manifest.json` | Archive preparation and appliance grouping |
|
||
|
|
|
||
|
|
The output also includes an SQLite event index, effective configuration and
|
||
|
|
indicator/hash hit files. JSONL contains one JSON object per line. URL/Base64
|
||
|
|
decoding retains original values, transformation steps, checksums and errors.
|
||
|
|
An installer command alone does not establish successful patch completion.
|
||
|
|
|
||
|
|
## Add indicators and Sigma rules
|
||
|
|
|
||
|
|
Put your packs in a directory and validate them before scanning:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
netscaler-triage rules --config ./my-rules
|
||
|
|
netscaler-triage ./logs --config ./my-rules
|
||
|
|
```
|
||
|
|
|
||
|
|
Directories load Sigma YAML, JSON, CSV and TXT recursively. Repeat `--config`
|
||
|
|
to combine packs. No Python changes are needed to add an IP, path or rule.
|
||
|
|
For example, an IOC CSV can contain:
|
||
|
|
|
||
|
|
```csv
|
||
|
|
type,value,status,source,description
|
||
|
|
ipv4,192.0.2.42,reference_only,local-review,Investigate matching events
|
||
|
|
path,/example/suspicious-file,reference_only,local-review,Check file context
|
||
|
|
```
|
||
|
|
|
||
|
|
These are synthetic examples. Use original, non-defanged values for matching.
|
||
|
|
TXT accepts one value per line; unambiguous IP addresses, SHA-256 hashes, URLs
|
||
|
|
and Unix paths are inferred. Other values remain literal strings.
|
||
|
|
|
||
|
|
Sigma is parsed with pySigma and evaluated locally using the subset documented
|
||
|
|
in [RULES.txt](RULES.txt). Unsupported features fail explicitly. Sigma metadata
|
||
|
|
does not bypass detection conditions. Rule packs are data, not executable plugins.
|
||
|
|
|
||
|
|
Defaults include 47 Sigma rules and 246 public reference indicators. Attribution
|
||
|
|
and limitations are recorded in [THREAT_INTELLIGENCE.txt](THREAT_INTELLIGENCE.txt)
|
||
|
|
and [config/threat_intel.json](config/threat_intel.json). This is a dated reference
|
||
|
|
collection, not a promise of exhaustive intelligence or zero false positives.
|
||
|
|
|
||
|
|
Keep confidential packs in `private/`, excluded from Git and release archives.
|
||
|
|
Load them explicitly. Never put customer logs or generated findings in a public
|
||
|
|
repository. Examples under [examples/](examples/) use synthetic data.
|
||
|
|
|
||
|
|
## Limits and interpretation
|
||
|
|
|
||
|
|
- Exit `0`: configured processing completed; **not** a clean-system verdict.
|
||
|
|
- Exit `2`: an error or incomplete processing; inspect `summary.json`.
|
||
|
|
- Missing years/timezones are not guessed. See [README.txt](README.txt) for time configuration.
|
||
|
|
- Binary appliance logs may need an external decoder. Decode failures can also come from ordinary text.
|
||
|
|
- Damaged inputs and regex timeouts are reported. Archive path traversal, unsafe links and exhausted quotas stop preparation.
|
||
|
|
- Processing uses one worker, incremental reads and disk-backed SQLite. There is no hard process-wide RAM/CPU quota or automatic resume.
|
||
|
|
- Default limits: 2 GiB preparation budget, 100,000 archive entries, depth 3, 1 MiB per line and 512 MiB expanded per log file. Advanced options can raise limits.
|
||
|
|
|
||
|
|
Tests were executed on macOS/ARM64. Windows and Linux instructions are provided,
|
||
|
|
but those platforms have not yet been validated in the recorded test environment.
|
||
|
|
|
||
|
|
## Help and development
|
||
|
|
|
||
|
|
```sh
|
||
|
|
netscaler-triage --help
|
||
|
|
netscaler-triage scan --help-all
|
||
|
|
netscaler-triage decode payload.txt
|
||
|
|
netscaler-triage inventory ./logs
|
||
|
|
|
||
|
|
uv sync --locked
|
||
|
|
uv run python -W error -m unittest discover -s tests
|
||
|
|
uv run mypy
|
||
|
|
uv run ruff check src tests typing_stubs
|
||
|
|
uv run ruff format --check src tests typing_stubs
|
||
|
|
uv build
|
||
|
|
```
|
||
|
|
|
||
|
|
See [README.txt](README.txt) for the detailed plain-text manual and
|
||
|
|
[VALIDATION.txt](VALIDATION.txt) for test scope and known coverage limits.
|
||
|
|
|
||
|
|
## License
|
||
|
|
|
||
|
|
Project code is licensed under the [MIT License](LICENSE.txt).
|
||
|
|
Third-party dependencies and referenced external materials retain their own
|
||
|
|
licenses. Source attribution does not imply affiliation with Citrix or the
|
||
|
|
referenced researchers, and does not relicense their original publications.
|