Threat Signal Correlator written in F#
Part of the NullSec offensive security toolkit
Twitter: x.com/AnonAntics
Portal: bad-antics.github.io
FSharpSignal is a threat intelligence correlation engine that aggregates indicators of compromise (IOCs) and identifies attack patterns through functional programming paradigms. Built with F#'s discriminated unions, pattern matching, and immutable data structures.
- Discriminated Unions: Type-safe threat categories
- Active Patterns: Custom pattern matching
- Computation Expressions: Signal builder monad
- Higher-Order Functions: Composable pipelines
- Record Types: Immutable data structures
- Pattern Matching: Exhaustive case handling
- List Comprehensions: Functional collections
- Type Inference: Clean, concise code
| Rule | Description | Required Types | MITRE |
|---|---|---|---|
| APT Campaign | Multi-vector campaign detection | IP, Domain, Hash | TA0001 |
| C2 Infrastructure | Command & control patterns | IP, Domain | T1071 |
| Lateral Movement | Network traversal indicators | IP, Process | TA0008 |
| Data Staging | Exfiltration preparation | Hash, Process, Registry | T1074 |
| Phishing Infrastructure | Phishing campaign IOCs | Domain, Email, URL | T1566 |
# Clone
git clone https://github.com/bad-antics/nullsec-fsharpsignal.git
cd nullsec-fsharpsignal
# Build with .NET SDK
dotnet build
# Or compile directly
fsharpc FSharpSignal.fs -o fsharpsignal.exe# Run demo mode
dotnet run
# Process IOC file
dotnet run -- -f indicators.json
# Enable verbose correlation
dotnet run -- -v -f indicators.jsonUSAGE:
fsharpsignal [OPTIONS]
OPTIONS:
-h, --help Show help
-f, --file IOC file to process
-v, --verbose Verbose output
-r, --rules Custom correlation rules
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NullSec FSharpSignal - Threat Signal Correlator β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[Demo Mode]
Loading threat intelligence indicators...
Loaded 13 indicators
Running correlation engine...
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CORRELATED SIGNAL: APT Campaign Detection β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Severity: CRITICAL
Score: 42.5/100
MITRE ID: TA0001
Correlation: 2024-01-15 14:30:22 UTC
Indicators:
[HIGH] IP: 185.220.101.45
[HIGH] Domain: update-service.duckdns.org
[CRITICAL] Hash: 44d88612fea8a8f36de82e1278abb02f
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CORRELATED SIGNAL: C2 Infrastructure β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Severity: HIGH
Score: 28.0/100
MITRE ID: T1071
Correlation: 2024-01-15 14:30:22 UTC
Indicators:
[HIGH] IP: 185.220.101.45
[HIGH] Domain: c2-beacon.no-ip.com
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Summary:
Total Signals: 4
Critical: 1
High: 2
Medium: 1
Combined Score: 112.5
type Severity =
| Critical
| High
| Medium
| Low
| Informational
type IndicatorType =
| IPAddress
| Domain
| FileHash
| URL
| Email
| Registry
| ProcessName
| Mutexlet (|C2Domain|PhishingDomain|LegitDomain|) (domain: string) =
let c2Patterns = [".onion"; ".bit"; "duckdns.org"; "no-ip.com"]
let phishingKeywords = ["login"; "secure"; "verify"]
let lowerDomain = domain.ToLowerInvariant()
if c2Patterns |> List.exists (fun p -> lowerDomain.EndsWith(p)) then C2Domain
elif phishingKeywords |> List.exists (fun k -> lowerDomain.Contains(k)) then PhishingDomain
else LegitDomain
// Usage
let enrichDomain indicator =
match indicator.Value with
| C2Domain -> { indicator with Category = C2Infrastructure }
| PhishingDomain -> { indicator with Category = Phishing }
| LegitDomain -> indicatortype SignalBuilder() =
member _.Bind(x, f) =
match x with
| Some value -> f value
| None -> None
member _.Return(x) = Some x
member _.Zero() = None
let signal = SignalBuilder()
// Usage
let result = signal {
let! indicator = findIndicator "185.220.101.45"
let! enriched = enrichIndicator indicator
return correlate enriched
}let correlate (indicators: Indicator list) =
defaultRules
|> List.map (fun rule -> matchRule rule indicators)
|> List.choose (function
| SignalFound signal -> Some signal
| _ -> None)
|> List.sortByDescending (fun s -> Severity.toInt s.AggregatedSeverity)ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FSharpSignal Architecture β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββ β
β β IOC Input β (IP, Domain, Hash, URL, Email) β
β ββββββββββ¬ββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββ β
β β Type Inference β Discriminated Unions β
β β & Validation β Active Patterns β
β ββββββββββ¬ββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββ β
β β Enrichment β IP β GeoIP, ASN β
β β Pipeline β Hash β Malware DB β
β β (List.map) β Domain β Classification β
β ββββββββββ¬ββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Correlation Engine β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββ β β
β β β APT Rules β β C2 Rules β β Phish Rules β β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββ β β
β β Pattern Matching β β
β ββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β Result Type β β Report β β
β β SignalFound βββββΆβ Generation β β
β β NoMatch β β β β
β β InsufficientDataβ ββββββββββββββββββββ β
β ββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Requirement | F# Advantage |
|---|---|
| Correctness | Exhaustive pattern matching |
| Immutability | Default immutable data |
| Composition | Function pipelines |
| Type Safety | Discriminated unions |
| Conciseness | Type inference |
| .NET Ecosystem | Full interoperability |
MIT License - See LICENSE for details.
- nullsec-flowtrace - Flow analyzer (Haskell)
- nullsec-cppsentry - Packet sentinel (C++)
- nullsec-juliaprobe - Anomaly detector (Julia)