Skip to content

Latest commit

 

History

History
173 lines (129 loc) · 9.03 KB

File metadata and controls

173 lines (129 loc) · 9.03 KB

AIMS — Attacked Infrastructure Modular Specification

A shared data model and object store for offensive-security tooling. AIMS declares the objects an attacker cares about — hosts, networks, services, credentials, scans, C2 agents — and gives them first-class facilities so that many different tools can contribute to and consume the same database of the same objects.

Think MISP/STIX, but for the attacker's side — with the emphasis on being easy to move around, easy to store in SQL, and interoperable across languages and tools.

It ships as three things at once:

  • a specification — Protobuf definitions that are the source of truth for every object;
  • a library — generated Go types you can embed in your own tool, SQL-storable out of the box;
  • a binaryaims, a teamserver + client + CLI to populate, query, and browse the store.

Status. The data model and generated layer are mature. The user-facing server/CLI is a vertical slice that fills out domain by domain — see the status matrix below. A plain go build ./... builds the whole tree and the aims binary runs.


Quickstart

Requirements: Go 1.24+. All dependencies are pinned to published versions, so a plain build works.

# Build the binary
go build -o aims ./cmd/aims

# The binary is a self-contained teamserver + in-process client + CLI.
# First run migrates the embedded database automatically.
./aims --help

Run a scan and browse what it found:

# Scan a subnet with nmap (args after `nmap` are passed straight through) and store the results
aims scan run nmap -- -sV -O 10.0.0.0/24

# List what's in the store
aims hosts list                 # discovered hosts (responsive, colored, weight-ranked columns)
aims services list              # network services across all hosts
aims scan list                  # scans, with live run-state

# Drill into one object by ID prefix
aims hosts show a1b2            # detail view; add --traceroute for the route
aims scan show 5f3c

# See what changed between two scans (attack-surface drift)
aims scan diff <id-a> <id-b>

Credentials and C2:

aims credentials list
aims credentials add            # Metasploit-style Private/Public/Realm/Origin model
aims agents list                # C2 agents
aims channels list

Completions are rich and live — a Tab on any show/rm queries the store and renders described, aligned candidates (results are briefly cached so repeated Tabs are instant). Wire them into your shell with carapace (aims is carapace-instrumented).

Multi-user / remote operation is available too: aims embeds a reeflective/team teamserver (extracted from Sliver), so you can serve the store to remote operators over mTLS. See the teamserver command group.


What it stores

Each domain mirrors the object model of a tool people already trust, so tool-native output maps onto the types with little friction:

Domain Core objects Model heritage
Host Host, Hostname, Port, OS/OSMatch, User, Group, Process, FileSystem, Uptime nmap
Network Address, Service, Trace/Hop, Distance, TCPSequence/IPIDSequence, packets nmap
Credential Core (Private/Public/Realm/Origin), Login, passwords, hashes, keys, certificates Metasploit
Scan Run, Info, Stats, Target, ScanTask, TaskProgress (nmap Script/Table/Element) nmap et al.
C2 Agent, Channel, Task Sliver-like
Provenance Source — per-tool origin stamped on co-produced objects, for "give me only my data" queries

Many host/network proto fields carry xml:"…" tags that map directly onto nmap's XML output, so nmap results unmarshal straight into the types. Re-importing the same scan does not duplicate rows — a shared merge/dedup fold folds new facts into existing objects.


Status

The model + generated layer is solid. The server/CLI slice is filling out domain by domain; read paths work broadly, mutation is landing service by service.

Service Read / List Create Update / Delete / Upsert Notes
host (Hosts) ✅ (dedup) Upsert ✅ · Delete stub reference impl; deep in-place child merge on insert
credential Upsert ✅ · Delete ✅ full CRUD; Delete resolves by identity
scan Upsert ✅ · Delete ✅ full CRUD; cross-run host unification; live state
network (Services) stub stub display/CLI slice done; server CRUD pending
c2 (Agents/Channels) stub Upsert/Delete pending
host Users · cred Logins services scaffolded but stubbed

Also in flight: a scanner-plug substrate (live/streaming scans, Ingestor/Scanner plug interfaces, stored-object → Target bridge, run-to-run diff) and bring — sourcing a C2 agent context into your live shell.


Architecture

One code-generation pipeline runs the whole repo: .proto → generated Go PB types → generated GORM ORM types → hand-written helpers + per-domain gRPC services + CLI.

 proto definitions          generated code                    hand-written layers
 ─────────────────          ──────────────                    ───────────────────
 <domain>/pb/*.proto    ─►  *.pb.go       (protoc-gen-go)
                            *.pb.gorm.go  (protoc-gen-gorm)  ─►  server/<domain>/  gRPC CRUD
 <domain>/pb/rpc/*.proto ─► *_grpc.pb.go  (gRPC)             ─►  client/           client wrappers
                                                             ─►  <domain>/*.go     native helpers, display, dedup
                                                             ─►  cmd/<domain>/     cobra CLI + completions
  • Two representations per object (via infobloxopen/protoc-gen-gorm): pb.Host (the user-facing Protobuf Go type) and pb.HostORM (the GORM-storable type), with ToPB/ToORM converters. Services convert PB→ORM to query/write, then ORM→PB to return.
  • Struct tags drive everything. // @gotags: comments attach xml: (nmap ingest), display: (CLI columns), readonly, strict; GORM relations come from (gorm.field) proto options. IDs are UUID strings; relations cascade.
  • One generic display engine (cmd/display/) — a type-parameterized map[string]func(T) string per object feeds tables, detail views, and completions, with weight-driven responsive column dropping. Define an object's presentation once.
  • Multi-user layer built on reeflective/team — auth, transports (mTLS, optional Tailscale), and RPC plumbing.

Documentation

See CLAUDE.md for the architectural overview — the code-generation pipeline, the domain object catalog, and repo conventions. Deeper design and context notes (scan model, dedup/merge, display engine, per-domain deep-dives) are kept as local working docs under .claude/ and aren't published.


Building & regenerating

  • Canonical module path: github.com/d3c3ptive/aims — module, remote, and local checkout are all on d3c3ptive. Always use d3c3ptive imports.
  • Build / vet: go build ./... — deps are published (no local replaces). First build pulls a large tree (gRPC, teamserver, nmap fork) — expect a slow initial download.
  • Optional build tags: -tags maltego enables the AsEntity() Maltego integration; -tags tailscale enables the Tailscale transport. Both are opt-in and off by default.
  • Regenerate from proto: make gen (buf: go + gorm + gotemplate, then go-grpc, then protoc-go-inject-tag for the xml:/display: tags). make deps installs the plugins.

When extending: prefer changing the .proto and regenerating over editing generated *.pb.go/*.pb.gorm.go by hand; put Go-idiomatic behavior in the domain root <name>.go files; wire new CRUD in server/<domain> + client + cmd/<domain>, following the host domain as the reference implementation.


License — GPLv3

AIMS is licensed under GPLv3.