Skip to content

cvewatcher/mulval

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

MulVAL (as a Service)

Attack graph generation over gRPC, backed by first-order Datalog inference

License Go reference
CI Docker pulls

MulVAL (as a Service) wraps MulVAL β€” a logic-based network security analyser β€” behind a gRPC/REST API to distribute its capabilities to third-party services. Clients submit EDB facts and optional IDB interaction rules; the service runs MulVAL in the background and returns a Long-Running Operation (LRO) that resolves to the generated attack graph.

Note

This project is research-grade software. Changes can happen at any time in a non-backward-compatible way.

πŸš€ What MulVal (as a Service) Does

  • Simplify MulVal usage β€” Running MulVal can become quite complex depending on your infrastructure, so running it as a Service helps bootstrapping it fast to experiment;
  • Manages multi-experiments β€” Every analysis is stored so can be shared among researchers and engineers in a lab, or used to iterate;
  • Reusability β€” Designed as a microservice, MulVal (as a Service) provides a gRPC/HTTP REST API that can be used by third-party services to run their experiment;
  • Visualization β€” Provide a UI that maps the API features for running in-browser experiments and visualize the results.

🧩 Architecture

The service is stateless between requests; all durable state lives in PostgreSQL. NATS JetStream is used only for completion notifications β€” WaitOperation subscribes to a per-operation subject and blocks until the executor publishes a state change, avoiding poll loops. If NATS is unavailable the service degrades gracefully: WaitOperation returns after its timeout with done=false.

⚑ Quick start

# Write the configuration file config.yaml
# An example:
#
# logLevel: info
# events:
#   url: nats://localhost:4222
#   instanceID:
#     from_env: HOSTNAME
# storage:
#   dsn: postgres://user:secret@localhost:5432/mulval-backend
#   schema: mulval
#   migrate: true
#   minConns: 4

# Start the MulVal (as a Service) Docker container.
# Add --ui for the web graphical interface.
docker run -p 8080:8080 -v config.yaml:/config.yaml cvewatcher/mulval:latest --config=/config.yaml --ui

# The service is now available at localhost:8080 (gRPC/HTTP REST)
# The web UI is at http://localhost:8080/ui/

Submitting an analysis via curl

curl -s -X POST http://localhost:8080/api/v1/analyses \
  -H 'Content-Type: application/json' \
  -d '{
    "edbFacts": [
      "attackerLocated(internet).",
      "attackGoal(execCode(fileServer,_)).",
      "hacl(internet, webServer, tcp, 80).",
      "hacl(webServer, fileServer, tcp, 445).",
      "hacl(H, H, _, _).",
      "networkServiceInfo(webServer, httpd, tcp, 80, apache).",
      "vulExists(webServer, '\''CVE-2021-44228'\'', httpd).",
      "vulProperty('\''CVE-2021-44228'\'', remoteExploit, privEscalation).",
      "networkServiceInfo(fileServer, smb, tcp, 445, root).",
      "vulExists(fileServer, '\''CVE-2017-0144'\'', smb).",
      "vulProperty('\''CVE-2017-0144'\'', remoteExploit, privEscalation)."
    ]
  }'

This returns an LRO immediately:

{
  "name": "operations/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "done": false
}

Poll until complete:

curl -s -X POST http://localhost:8080/api/v1/operations/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:wait \
  -H 'Content-Type: application/json' \
  -d '{"timeout": "30s"}'

When done: true, the response contains the full Analysis resource including verticesCsv, arcsCsv, and the parsed graph.

πŸ–ΌοΈ User Interface

CaptureDetail
All analyses MulVal (as a Service) ran.
The details of an analysis, with a graph display of the results.
The creation form.

πŸ”¨ Development setup

OpenTelemetry

  • Setup:
    export OTEL_EXPORTER_OTLP_ENDPOINT=dns://localhost:4317
    export OTEL_EXPORTER_OTLP_INSECURE=true
    export OTEL_EXPORTER_OTLP_PROTOCOL=grpc

PostgreSQL

  • Setup:

    docker run -d \
        --name postgres \
        -e POSTGRES_DB=mulval-backend \
        -e POSTGRES_USER=user \
        -e POSTGRES_PASSWORD=secret \
        -p 5432:5432 \
        postgres:16-alpine
  • Teardown:

    docker rm -f postgres
  • Adminer, for debug purposes:

    docker run -p 8082:8080 adminer

    You can connect with:

    • System: PostgreSQL
    • Server: The result of echo "$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' postgres):5432"
    • Username: user
    • Password: secret
    • Database: mulval-backend

NATS JetStream

  • Setup:

    docker run -d \
        --name nats-js \
        -p 4222:4222 \
        -p 8222:8222 \
        nats:latest -js -m 8222
  • Teardown:

    docker rm -f nats-js

About

MulVal (as a Service)

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors