Sysrift v0.1.0 release

This project inspired was by my recent spare time efforts working through retired HackTheBox machines and grew increasingly frustrated with linPEAS — not with its coverage, which is excellent, but with how it operates: a 35,000-line Bash script that spawns a process for nearly every check, generates significant noise, and flags immediately on most modern EDR solutions.

I grew curious how a compiled binary that didn’t need any dependencies to run might work as an alternative option. Crystal was the right choice — crystal build --static targeting musl libc produces a single self-contained executable with no runtime dependencies. Drop it in /dev/shm, run it, delete it.

sysrift covers the 14 highest-signal linPEAS vectors: SUID/SGID with GTFOBins cross-referencing, sudo CVEs (Baron Samedit, CVE-2019-14287, CVE-2019-18634), kernel CVEs (DirtyCow, Dirty Pipe, eBPF), credential hunting, container escape detection, NFS no_root_squash, file capabilities, and more. Output is severity-tagged with a post-run summary that surfaces only critical and medium findings.

On the Crystal side, the interesting design decisions were around nil safety for parsing unreliable system output, replacing ~70 process spawns with native filesystem reads and /proc parsing, and a data layer modeled after linPEAS’s variable pre-computation pattern.

An ARCHITECTURE.md is included with the full design rationale if anyone wants to dig into the Crystal-specific decisions.

Would welcome any feedback on Crystal idioms, design choices, or coverage gaps.

Sidenote: You can run this on your own Linux system just to see how it functions although it will be more prone to noise and false positive findings that are both expected and normal for a personal Linux environment setup.

v0.1.1 is out — GitHub - xalynn/sysrift · GitHub

Biggest addition is a 15th module for security protections: AppArmor, SELinux, ASLR, lockdown mode, various kernel hardening sysctls. All procfs/sysfs reads, no spawns.

Also caught a subtle Crystal bug during testing — File::Info#owner_id returns a String, so the SUID root-owner filter was doing stat.owner_id == 0 which is "0" == 0, always false. GTFOBins matching was silently broken for every build. Good reminder to actually verify return types against the docs rather than assuming.

Did a full noise reduction pass on a desktop environment. The main culprits were Chromium/Electron processes flagging as critical for cap_sys_admin (that’s just their sandbox using clone(CLONE_NEWUSER), not exploitable) and minified JS files matching credential patterns. Report size dropped considerably. Also added mount option cross-referencing — SUID binaries on nosuid mounts get downgraded since the kernel ignores the bit anyway.

Still a work in progress but it’s getting closer to something that matches most of what linPEAS offers.

Probably not a bug? because System::User#group_id return a String too.

Maybe core developer can give some clarify.

Correct. Its not a Crystal bug, rather a logic bug of my own fault. This was found in the SUID module of the project (src/modules/mod_suid.cr) which is responsible for finding SUID and SGID binaries on the filesystem that might be writeable or not configured properly. I’ve already fixed it. owner_id returns String to accommodate non-numeric identifiers on other platforms (windows SIDs), which makes sense.

I was comparing stat.owner_id == 0 instead of == "0". Crystal doesn’t complain since String == Int is valid syntax, it just silently evaluates to false. Every SUID binary was bypassing my root-owner filter and I couldn’t figure out why until I tested it in crystal eval.

I wish Crystal had type-safe equality.

v0.2.0 is out — sysrift

Main addition is distro-aware kernel CVE detection. The problem with upstream version matching (which is what linPEAS does) is that it flags everything in the NVD range without checking whether the distro backported the fix. A patched Ubuntu 22.04 box gets 15+ kernel CVE hits, all noise. sysrift now compares the installed kernel package version against tracker-verified fixed versions using native dpkg/rpm version comparison. Below the fixed version = vulnerable, at or above = patched, skip it.

8 kernel CVEs in the registry — the usual suspects plus CVE-2023-0386, CVE-2023-35001, CVE-2024-1086, and both GameOverlay CVEs. GameOverlay is Ubuntu-only so there’s a distro gate that skips it on non-Ubuntu systems. All fixed versions sourced from Debian security tracker, Ubuntu CVE pages, and Red Hat RHSA errata with a verification doc linking every source.

Also a lot of false positive reduction work since v0.1.1. Credential scanning filters out noise, SUID default install binaries are demoted, cron targets validate as actual files, and there’s identity-aware severity throughout. On a desktop environment the report went from 5 MB / 44 critical down to ~200 KB / 27 critical without losing any real findings.

v0.3.0 is out — sysrift

Biggest additions are software-level checks that linPEAS doesn’t really cover. Internal service detection cross-references running processes against known self-hosted services (GitLab, Jenkins, Grafana, Vault, etc.) and confirms with listener data. Config credential extraction for GitLab secrets and Splunk obfuscated passwords (those are reversible XOR), not real hashes, so the finding says so. Log4j jar scanning flags anything below 2.17.1.

Four userspace CVEs using the same distro-aware backport detection from v0.2.0: Firejail chroot escape, needrestart interpreter escalation, glibc Looney Tunables, and apport-cli pager escape. Also added AD domain membership detection, sshd_config directive parsing, and AuthorizedKeysFile path expansion with writability checks.

Kernel CVE registry is up to 15 entries now (was 8 in v0.2.0). Added Data.ss_output and Data.sshd_config to the cached data layer since both get consumed by multiple modules. README updated with cleaner usage instructions such as HTTP serve + drop pattern, report handling, etc.

Still a work in progress but the gap with linPEAS keeps shrinking.

v0.4.0 is out — sysrift

Biggest structural change since v0.3.0 is a unified filesystem walker. One in-process descent from / feeds typed sets into the Data layer - SUID/SGID, world-writable dirs, SSH keys, .netrc, sensitive configs, password vaults, tfstate, certs/keystores, log4j jars, the cred-pattern scan candidate set, log files. Replaces ~13 find spawns with one descent; module 4 (cred hunting) finishes in ~30s where it previously hung 10+ minutes on dev workstations. Inode-level dedup via {st_dev, st_ino} catches bind-mount cycles.

Internal service coverage now leads linPEAS master on Duplicati, Froxlor, and Portainer (zero linPEAS coverage on any three), and ships ISPConfig + TeamCity ahead of their unmerged linPEAS feature branches. Cacti at parity. Plus crontab-ui with systemd Environment= cred extraction, Kerberos /etc/krb5.keytab ownership + klist -k principal enumeration, and Logstash filter/output writability with ruby {} / exec {} detection. 24 of 24 verified retired HTB Linux intended privesc paths now covered end-to-end.

Credential hunting got a lot wider: wifi (NetworkManager + wpa_supplicant), Terraform state, Docker registry config, Kubernetes kubeconfig with ownership-aware severity, AI coding assistant tokens (.codex/.claude/.cursor/.gemini), GPG private keys with pass-store annotation, certs and keystores (.p12/.pfx/.jks/.keystore + .pem/.key with PRIVATE-header peek), browser stores for Firefox and 8 Chrome-family browsers, password manager DBs (.kdbx/.kdb/.psafe3), PHP sessions, .git exposure in web roots, database cred files, and self-hosted app configs (Mattermost/Gitea/Jenkins/Grafana, process-gated).

New mod_cloud (module 17) covers 10 passive cloud indicators (AWS/GCP/Azure/DO/IBM) with DMI fallback and active IMDS harvest for 9 provider variants via Crystal stdlib HTTP::Client. Container coverage expanded with pivot network enumeration (fib_trie/ARP/hosts), host mount writability, user namespace mapping, and K8s SA token + RBAC analysis across 20 dangerous verb+resource combos.

This release covers almost all the detection gaps missing from the last release. Project focus will now shift towards rigorous testing to identify and resolve false positives and noise that emerged from the new detection coverage, comparing previous reports, menu UX improvements, and findings summary output changes.