Skip to content

Alinthropisc/Storm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

 ███████╗████████╗ ██████╗ ██████╗ ███╗   ███╗
 ██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗████╗ ████║
 ███████╗   ██║   ██║   ██║██████╔╝██╔████╔██║
 ╚════██║   ██║   ██║   ██║██╔══██╗██║╚██╔╝██║
 ███████║   ██║   ╚██████╔╝██║  ██║██║ ╚═╝ ██║
 ╚══════╝   ╚═╝    ╚═════╝ ╚═╝  ╚═╝╚═╝     ╚═╝

unified offensive recon engine · cross-domain correlation

They scan. STORM understands.

[ network ]· [ web ]· [ tls ]· [ secrets ]· [ cve ]· [ audit ]· [ container ]· [ iac ]· [ git-history ]⚡ KILL-CHAINS

zero deps · pure stdlib · built from scratch


$ whoami
  STORM — an InfoSec scanner forged in Go. No third-party blood. Every line is ours.

Every scanner out there does one job. One reads ports. One greps secrets. One diffs CVEs. One audits configs. Each spits out a flat list and calls it a day.

Everyone's got their own fighter jet. STORM brought the B2-Spirit — the thing nobody else flies: it doesn't just collect findings across domains, it welds them into attack chains on a single asset and scores the combined blast radius.

An open SSH port? Noise. An open SSH port + a vulnerable OpenSSH build + a private key leaked in the repo? That's a takeover. STORM sees the chain. The others see three unrelated lines.


⚡ Strike fast

go build -o storm ./cmd/storm

# instant demo: scan the bundled intentionally-vulnerable target
./storm scan --path ./examples          # or: make demo

# what can we hit?
./storm probes

# multi-domain sweep + correlation
./storm scan \
    --host 10.0.0.5,10.0.0.6 \
    --pkg  openssh@7.1,log4j@2.14 \
    --path ./app \
    --min-severity medium

# machine output for the pipeline
./storm scan --host 10.0.0.5 --format json > loot.json

What the strike looks like

▓▓ KILL-CHAINS (correlated attack paths) ▓▓

  CRITICAL  Confirmed Exploitable Service  [10.0.0.5 · risk 90/100]
   STORM read the version straight off the wire and matched a live CVE — the
   vulnerable service is listening and reachable right now.
     1.  MEDIUM    Open port 9200 on 10.0.0.5
     2.  HIGH      CVE-2018-15473: openssh 7.4 exposed on 10.0.0.5

  CRITICAL  Unrotated Leaked Secret  [app.env · risk 90/100]
   A secret committed to git history AND still in the working tree — deleting the
   file won't save you. Rotate the credential.
     1.  HIGH      AWS Access Key committed to git history (app.env)
     2.  HIGH      AWS Access Key found in app.env

🧠 B2-Spirit: the correlation engine

Every probe speaks one language — a Finding with an Evidence map (host, package, secret_type, path, …). Those are the join keys. The correlator buckets findings by asset, runs scenario rules, and escalates severity when independent domains corroborate the same target:

network ─┐
secrets ─┤
cve     ─┼─►  group by asset  ─►  scenario rules  ─►  KILL-CHAIN (risk 0..100)
audit   ─┤
iac     ─┘

A new attack scenario = one Rule appended to internal/correlate/rules.go. The engine loop never moves. Scenarios shipping today:

Kill-chain Fires when
🔓 Remote SSH Takeover exposed SSH + (OpenSSH CVE or leaked key)
🎯 Confirmed Exploitable Service banner-read version + matching CVE
💥 Exposed Vulnerable Service risky service exposed + any CVE
☠️ Poisoned Container Image baked-in secret / curl|bash + runs as root
🪣 Internet-Exposed Data Store public IaC store + unencrypted
🗝️ Exposed Hardcoded Credential (IaC) internet-facing infra + hardcoded creds
🕳️ Unrotated Leaked Secret secret in git history + still in working tree
🌐 Reachable Web Secret Leak .git/.env over HTTP + CVE/risky service on host
🔒 Interceptable TLS Endpoint weak/broken TLS + exposed port on host
🔑 Credential Exposure Path secret + weak file permissions

🎯 The arsenal — 9 probes, one engine

Probe Domain Hunts for
📡 network.portscan network open TCP ports, service banner-grab → version
🌐 web.http web missing security headers, leaky cookies, exposed .git/.env
🔒 tls.scan tls expired/self-signed certs, obsolete TLS 1.0/1.1, weak ciphers
🔐 secrets.scan secret leaked keys/tokens/passwords in files
🕰️ git.history secret secrets buried in commit history (survive deletion)
🐛 cve.packages cve installed packages vs. vuln DB
🛡️ audit.hardening audit insecure perms, debug flags, PermitRootLogin
🐳 container.dockerfile container root user, :latest, baked secrets, curl|bash
☁️ iac.terraform iac public S3, 0.0.0.0/0, unencrypted, IAM *:*

🏗️ Architecture — a design-patterns playbook that actually runs

Component Pattern Job
🧩 core.Probe Strategy every scanner is interchangeable
🏭 core.Registry Singleton + Factory probes self-register via init()
🔧 config.Builder Builder fluent scan assembly
📣 core.EventBus Observer progress/events, zero coupling
⛓️ core.Pipeline Chain of Responsibility enrich → filter findings
🛡️ WithTimeout/WithRetry Decorator cross-cutting armor on any probe
🧬 core.Enricher post-processing banner→CVE fusion between probe & correlate
📤 report.Reporter Visitor / Strategy console / JSON / SARIF / HTML
🧱 baseline.Filter Chain of Responsibility suppress accepted findings (CI gate)
🎮 cli.Command Command subcommands, no switch monolith
✈️ correlate.Correlator ★ B2 welds findings into kill-chains
storm/
├── cmd/storm/            # entry point (binary)
├── examples/             # intentionally-vulnerable demo target (make demo)
└── internal/
    ├── core/             # Finding, Probe, Registry, Engine, Pipeline, Decorator, EventBus, Enricher
    ├── config/           # scan-config Builder
    ├── probes/           # network · web · tls · secrets · git.history · cve · audit · container · iac
    ├── secretrules/      # shared secret-detection patterns (DRY)
    ├── vulndb/           # neutral vulnerability-data layer
    ├── enrich/           # post-scan fusion: banner→CVE
    ├── correlate/        # B2-Spirit: kill-chain engine
    ├── baseline/         # finding suppression (CI gate)
    ├── report/           # console · json · sarif · html · progress
    ├── cli/              # Command router
    └── app/              # composition root (everything is wired here)

internal/ is deliberate: Go physically forbids foreign modules from importing our guts.


🛡️ STORM as a CI gate

# 1. snapshot the current state as accepted (baseline)
./storm scan --path . --write-baseline .storm-baseline.json

# 2. in PRs: SARIF into code scanning + fail only on NEW high+ findings
./storm scan --path . --baseline .storm-baseline.json --format sarif > storm.sarif
./storm scan --path . --baseline .storm-baseline.json --fail-on high
  • --format html → self-contained dashboard (one file, kill-chain cards + risk bars), open straight off disk.
  • --format sarif → SARIF 2.1.0, uploaded to GitHub code scanning (findings inline on the PR).
  • --baseline → suppresses accepted findings by stable fingerprint.
  • --fail-on high → non-zero exit when a finding lands at/above the threshold. That's the gate.

The bundled .github/workflows/ci.yml self-scans the repo and ships the SARIF.


🔌 Forge your own probe

package myscan

import "storm/internal/core"

func init() { core.Register(&Probe{}) }

type Probe struct{}

func (p *Probe) Name() string               { return "my.scan" }
func (p *Probe) Domain() core.Domain        { return core.DomainNetwork }
func (p *Probe) Accepts(t core.Target) bool { return t.Host != "" }
func (p *Probe) Scan(ctx context.Context, t core.Target, out chan<- core.Finding) error {
    out <- core.Finding{ /* ... */ }
    return nil
}

Drop a blank import in cmd/storm/main.go and the engine picks it up. No central switch to touch.


⚠️ Rules of engagement

STORM is a weapon for authorized security work: your own systems, contracted pentests, CTFs, research, education. Point it only at targets you're cleared to hit.


forged in Go · zero deps · stdlib only · the rest is up to you

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors