Linux Incident Response

>_ klint

Linux Kernel Security Scanner

A single-binary, one-shot incident response scanner written in C++23. Deploy into restricted environments with zero dependencies and detect hidden kernel modules, rootkits, compromised syscall tables, and more.

root@incident ~ #
$ |

Features

Built for real-world incident response

Modular Scanners

8 self-registering scanners covering kernel modules, processes, network, syscalls, entrypoints, and BPF. Add new scanners with zero framework changes.

Structured Output

Machine-readable JSON and human-friendly colored text output. Structured findings with severity levels, details, and key-value evidence.

Per-Scanner Timeouts

Each scanner runs in a forked child process with a configurable timeout. One hung scanner never blocks the rest of the assessment.

Static Binary

Build a fully static binary with no runtime dependencies beyond libc. Deploy via SCP into compromised environments with no package manager needed.

Root-Level Detection

Requires root privileges for deep kernel inspection. Accesses /proc/kcore, kernel symbol tables, cgroups, and raw network socket state.

Meaningful Exit Codes

Exit 0 when clean, 1 when findings detected, 2 on errors. Designed for automation, CI pipelines, and scripted incident response workflows.

Scanners

8 specialized detectors for kernel-level threats

hidden_lkm

kernel

Detects hidden Loadable Kernel Modules by comparing module visibility across /proc/modules, /sys/module, and /proc/kallsyms. Identifies modules present in kallsyms but missing from procfs/sysfs.

Critical on hidden modules

hidden_processes

process

Discovers hidden processes using multi-view cross-checks: /proc enumeration, kill(0) probing, cgroup task files, and /proc/loadavg analysis. Revalidation snapshots eliminate transient race conditions.

Critical on persistent hidden PIDs

hidden_network_sockets

network

Detects hidden or redirected network sockets by comparing /proc/net tables, netlink diagnostics via ss, and process file descriptor scanning. Two-snapshot validation reduces false positives.

Requires: ss Critical on hidden sockets

kernel_entrypoint_integrity

kernel

Validates syscall entrypoints by reading MSRs (IA32_LSTAR, IA32_CSTAR, IA32_SYSENTER_EIP) and IDT vectors via /proc/kcore. Detects entrypoint redirection to module code or trampolines. x86_64-specific.

Critical on redirected entrypoints

ftrace_redirection

kernel

Analyzes ftrace function hooks for suspicious kernel path redirection. Checks tracer configuration, filter functions against critical patterns covering syscalls, VFS, credentials, and LSM hooks.

Critical on unfiltered active tracing

unknown_kprobes

kernel

Discovers kprobe and kretprobe events targeting sensitive kernel functions. Matches against critical patterns including syscalls, credentials, module loading, VFS, network, LSM, and BPF functions.

Warning on sensitive kprobes

syscall_table_integrity

kernel

Examines syscall table entries by parsing /proc/kcore ELF core image. Verifies each entry resolves to core kernel text or legitimate modules. Detects entries pointing outside kernel memory.

Critical on hijacked entries

bpf_rootkit_detection

kernel network persistence process

Comprehensive eBPF/BPF security scanner analyzing programs, maps, and links via bpftool. Detects ownerless high-risk hooks, suspicious naming patterns, bpffs mount anomalies, and checks hardening sysctls.

Requires: bpftool Critical on ownerless hooks

Usage

Simple CLI for rapid deployment and scripting

Basic Scan

# sudo ./klint

[hidden_lkm] (kernel)
  OK

[hidden_processes] (process)
  WARNING cgroup task anomaly detected
    pid: 31337
    source: cgroup tasks vs /proc

[syscall_table_integrity] (kernel)
  CRITICAL sys_call_table entry points outside kernel text
    syscall: __x64_sys_getdents64
    address: 0xffffffffc0a01234

JSON Output

# sudo ./klint --json

{
  "scanners": [...],
  "summary": {
    "total": 8,
    "clean": 6,
    "findings": 2,
    "errors": 0,
    "skipped": 0,
    "timed_out": 0
  }
}

Selective Scanning

# Run only specific scanners
# sudo ./klint --scanner hidden_lkm --scanner hidden_processes

# Exclude a scanner
# sudo ./klint --exclude bpf_rootkit_detection

# List available scanners
# ./klint --list
SCANNER                      CATEGORIES                      REQUIRES
-----------------------------------------------------------------------
bpf_rootkit_detection        kernel, network, persistence,   tool:bpftool
                             process
ftrace_redirection           kernel                          -
hidden_lkm                   kernel                          -
hidden_network_sockets       network                         tool:ss
hidden_processes             process                         -
kernel_entrypoint_integrity  kernel                          -
syscall_table_integrity      kernel                          -
unknown_kprobes              kernel                          -

Timeout & Options

# Set per-scanner timeout (default: 30s)
# sudo ./klint --timeout 60

# Disable colored output
# sudo ./klint --no-color

# Combine for CI pipelines
# sudo ./klint --json --timeout 45 \
    --exclude bpf_rootkit_detection

# Check exit code
# sudo ./klint --json; echo "Exit: $?"

Exit Codes

0 All scanners clean or skipped, no errors
1 At least one scanner reported findings
2 Errors, timeouts, or invalid CLI arguments

Architecture

Designed for reliability in hostile environments

01

Self-Registering Scanners

Each scanner is a standalone .cpp file that auto-registers at static initialization time via a Registrar object. Adding a new scanner requires zero changes to the framework—just drop in a new file and rebuild.

// Each scanner self-registers:
static Registrar reg_{Scanner{
    .name = "hidden_lkm",
    .func = run,
    .categories = kCategories,
    .requirements = kRequirements,
}};
02

Fork & Pipe Isolation

Every scanner executes in a forked child process with results serialized as JSON over a pipe. This provides crash isolation, timeout enforcement, and prevents one scanner's failure from affecting the rest of the assessment.

main
fork()
scanner
pipe → JSON
03

Multi-View Validation

Scanners cross-reference multiple kernel data sources to detect inconsistencies. Hidden LKM compares /proc/modules vs /sys/module vs /proc/kallsyms. Hidden processes checks /proc vs kill() vs cgroups. This multi-view approach is resilient to single-source tampering.

04

Structured Results

Every finding carries a Severity (Info, Warning, Critical), a one-line summary, optional detail text, and structured key-value evidence. Results aggregate into a typed ScanResult with clean separation of findings and errors.

Info Warning Critical

Installation

Build from source in under a minute

1

Requirements

  • CMake 3.28+
  • GCC 13+ or Clang 17+ (C++23)
  • nlohmann_json (system package)
  • Linux kernel 5.10+
2

Build

$ git clone https://github.com/h2337/klint.git klint
$ cd klint
$ mkdir build && cd build
$ cmake ..
$ cmake --build .
3

Static Build

# Fully static, no runtime deps
$ cmake -DSTATIC_BUILD=ON ..
$ cmake --build .

# Deploy to target
$ scp klint root@target:/tmp/
$ ssh root@target /tmp/klint --json
4

Build Options

# Enable sanitizers (dev)
$ cmake -DENABLE_SANITIZERS=ON ..

# Treat warnings as errors
$ cmake -DWERROR=ON ..