Skip to main content

Linux privilege graph engine — model effective access, trace escalation paths.

Project description

privmap

tests License: MIT

Linux privilege graph engine. privmap models effective access on a Linux system as a directed graph and traces concrete privilege escalation paths through it.

[CRITICAL] 2 escalation paths found for user: www-data

Path 1 — www-data → root (4 hops)
  www-data
    MEMBER_OF  group: adm
    CAN_WRITE  file: /etc/logrotate.d/nginx  (mode: 0664)
    EXECUTES   cron: /etc/cron.daily  (runs-as: root)
  → root

  Risk: Writable logrotate config executed by root daily cron
  Remediation: chmod 644 /etc/logrotate.d/nginx; chown root:root /etc/logrotate.d/nginx

Why

Tools like LinPEAS, LinEnum, and BeRoot enumerate privilege-relevant findings as flat lists of independent observations. They report that a file is world-writable, and separately that the same file is executed by a root cron job, but they do not connect those facts into a single exploitable path. The analyst correlates the findings manually.

privmap treats this as a graph reachability problem. Every finding is a node or edge in a directed property graph. The question is not "what misconfigurations exist" but "given this user, what is reachable from here, and through what sequence of relationships."

Installation

pip install privmap

Or from source:

git clone https://github.com/isaacc2/privmap.git
cd privmap
pip install -e .

Requires Python 3.8 or later.

Usage

Live analysis

sudo privmap                              # full scan, all users
sudo privmap --user www-data --user bob   # specific users
sudo privmap --min-severity high          # filter by severity
sudo privmap --output json > report.json  # JSON for SIEM
sudo privmap --output markdown > report.md

Run as root for complete results. Without root, privmap cannot read /etc/shadow, walk all of /etc, or enumerate other users' processes, and findings will be incomplete.

Snapshot mode

For offline or forensic analysis, run the collector on the target:

sudo ./collect.sh

This produces privmap_snapshot_<hostname>_<date>.tar.gz. Transfer the archive to your analysis workstation and run:

privmap --snapshot ./privmap_snapshot_target_20250101.tar.gz

The collector is POSIX-compliant and has no runtime dependencies.

CI/CD integration

privmap --exit-code --min-severity critical

Returns non-zero if any path at or above the specified severity is found.

Other options

--scan-paths /etc,/usr,/opt    # custom filesystem scan paths
--max-depth 8                   # max traversal depth (default 10)
--export-graph graph.json       # dump full graph as JSON
-v / -vv                        # verbose / debug logging

How it works

  1. Ingestion. Reads system configuration: users, groups, sudo rules, file permissions, cron jobs, systemd units, capabilities, running processes.
  2. Graph construction. Each finding becomes a node or edge in a directed property graph.
  3. Reachability analysis. DFS traversal from each non-privileged principal toward high-value sinks (root, sudo ALL, dangerous capabilities).
  4. Semantic filtering. Eliminates structurally invalid paths, for example a writable file that no privileged process executes.
  5. Scoring. Each path is scored on exploitability and impact, then assigned a severity rating.
  6. Output. CLI, JSON, or Markdown with per-path remediation.

Architecture

privmap/
├── ingestion/
│   ├── identity.py       # passwd, shadow, group, sudo
│   ├── filesystem.py     # permission walk, SUID, ACL
│   ├── processes.py      # /proc, running services
│   ├── execution.py      # cron, systemd, init.d
│   └── capabilities.py   # linux capabilities, namespaces
├── graph/
│   ├── model.py          # node and edge types
│   ├── builder.py        # ingestion coordinator
│   └── traversal.py      # DFS reachability
├── analysis/
│   ├── paths.py          # extraction and deduplication
│   ├── scoring.py        # exploitability and impact
│   └── remediation.py    # per-path fix suggestions
├── output/
│   ├── cli_output.py     # rich terminal renderer
│   ├── json_export.py
│   └── markdown_export.py
└── cli.py                # entry point

Scope

privmap analyses local Linux privilege relationships. It does not perform network enumeration, run exploits, cover Windows or macOS, or replace a CVE-based vulnerability scanner. It is a structural analysis tool.

Known limitations

  • Argument-restricted sudo rules receive a reduced exploitability score but are not fully validated. Rules like sudo /usr/bin/systemctl restart nginx may still surface as findings.
  • Capability binaries from third-party packages are not on the known-safe allowlist and may produce false positives. The allowlist covers standard system binaries (snap-confine, ping, mtr, chronyd, and similar).
  • Snapshot mode falls back to conservative behavior for filesystem permission checks on capability binaries. Live mode is more accurate.
  • Cron command parsing uses regex matching on absolute paths, which can match path-like strings inside arguments or comments.
  • No CVE matching. privmap does not check binary versions against known vulnerabilities. Use a vulnerability scanner alongside it.

Use cases

  • System hardening. Validate least-privilege configurations and catch unintended escalation paths after changes.
  • Penetration testing. Replace manual enumeration with deterministic path mapping.
  • Incident response. Reconstruct how an attacker may have escalated privileges on a compromised host.
  • Education and CTF. Visualise permission chains that are difficult to reason about manually.

Development

pip install -e ".[dev]"
pytest tests/ -v
ruff check privmap/

Contributing

Issues and pull requests are welcome. Run the test suite before submitting a PR. For security vulnerabilities, see SECURITY.md.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

privmap-1.0.0.tar.gz (33.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

privmap-1.0.0-py3-none-any.whl (37.1 kB view details)

Uploaded Python 3

File details

Details for the file privmap-1.0.0.tar.gz.

File metadata

  • Download URL: privmap-1.0.0.tar.gz
  • Upload date:
  • Size: 33.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for privmap-1.0.0.tar.gz
Algorithm Hash digest
SHA256 c5e76ed7630be9a2b0a46d7430b8e2d8e8e4425f115603d35fd1dc9395329002
MD5 40de430bafcec3744d7da24bc6056662
BLAKE2b-256 01504c3a1ccaf746a6976641a549d95699f24cc2e0870044c7fb554c7d31838b

See more details on using hashes here.

File details

Details for the file privmap-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: privmap-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 37.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for privmap-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7df1c52fc51961e08b6ad8974ba6412c7549b90fa2630924dbc3aafd76f32e85
MD5 e6522f7b3d88cd3a7bb696ff82b609d4
BLAKE2b-256 c02880a2ee97044f098014ae478bedf98e15af186b56e5e5d8fc7b7604a1a34c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page