mirror of
https://github.com/andreicscs/HoneyWire
synced 2026-06-26 12:39:53 +00:00
updated event details from map to raw json data so that field order is kept.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package models
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// HubVersion defines the backend protocol version for resolving compatible sensors and authenticating Agents.
|
||||
const HubVersion = "2.0.0"
|
||||
|
||||
@@ -34,7 +36,7 @@ type Event struct {
|
||||
Severity string `json:"severity"`
|
||||
Source string `json:"source"`
|
||||
Target string `json:"target"`
|
||||
Details map[string]interface{} `json:"details"`
|
||||
Details json.RawMessage `json:"details"`
|
||||
IsRead bool `json:"isRead"`
|
||||
IsArchived bool `json:"isArchived"`
|
||||
Count int `json:"count"`
|
||||
|
||||
@@ -2,7 +2,6 @@ package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
@@ -79,10 +78,13 @@ func (s *Service) ProcessEvent(e *models.Event, nodeID string) error {
|
||||
}
|
||||
}
|
||||
|
||||
detailsJSON, _ := json.Marshal(e.Details)
|
||||
detailsStr := "{}"
|
||||
if len(e.Details) > 0 {
|
||||
detailsStr = string(e.Details)
|
||||
}
|
||||
e.NodeID = nodeID
|
||||
|
||||
lastInsertID, err := s.store.InsertEvent(e, nowStr, string(detailsJSON))
|
||||
lastInsertID, err := s.store.InsertEvent(e, nowStr, detailsStr)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "FOREIGN KEY") {
|
||||
return fmt.Errorf("sensor_not_registered")
|
||||
|
||||
@@ -2,7 +2,6 @@ package siem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
@@ -317,8 +316,8 @@ func (s *Service) formatSyslog(event models.Event) string {
|
||||
|
||||
timestamp := t.UTC().Format(time.RFC3339Nano)
|
||||
|
||||
detailsJSON, err := json.Marshal(event.Details)
|
||||
if err != nil {
|
||||
detailsJSON := event.Details
|
||||
if len(detailsJSON) == 0 {
|
||||
detailsJSON = []byte("{}")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package siem
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"regexp"
|
||||
"testing"
|
||||
@@ -41,7 +42,7 @@ func TestSyslogForwardingRFC5424(t *testing.T) {
|
||||
Source: "192.168.1.100",
|
||||
Target: "10.0.0.5",
|
||||
SensorID: "sensor-01",
|
||||
Details: map[string]interface{}{"file": "/etc/shadow"},
|
||||
Details: json.RawMessage(`{"file": "/etc/shadow"}`),
|
||||
}
|
||||
|
||||
// Send the event
|
||||
|
||||
@@ -77,7 +77,11 @@ func (s *SQLiteStore) GetEvents(isArchived int, nodeID string, sensorID string)
|
||||
|
||||
e.IsRead = isReadInt == 1
|
||||
e.IsArchived = isArchivedInt == 1
|
||||
json.Unmarshal([]byte(detailsStr), &e.Details)
|
||||
if detailsStr != "" {
|
||||
e.Details = json.RawMessage(detailsStr)
|
||||
} else {
|
||||
e.Details = json.RawMessage("{}")
|
||||
}
|
||||
events = append(events, e)
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ type Sensor struct {
|
||||
testTrigger string
|
||||
testSource string
|
||||
testTarget string
|
||||
testDetails map[string]any
|
||||
testDetails EventDetails
|
||||
}
|
||||
|
||||
func NewSensor() (*Sensor, error) {
|
||||
@@ -176,7 +176,7 @@ func NewSensor() (*Sensor, error) {
|
||||
}
|
||||
|
||||
// SetTestPayload allows community sensors to define a realistic, protocol-specific mock payload
|
||||
func (s *Sensor) SetTestPayload(trigger, source, target string, details map[string]any) {
|
||||
func (s *Sensor) SetTestPayload(trigger, source, target string, details EventDetails) {
|
||||
s.testPayload = map[string]any{
|
||||
"eventTrigger": trigger,
|
||||
"source": source,
|
||||
@@ -214,7 +214,7 @@ func (s *Sensor) listenForSignals() {
|
||||
trigger := "test_mode_synthetic_alert"
|
||||
source := "Wizard Live Test"
|
||||
target := "Mock Hub"
|
||||
details := map[string]any{"test_message": "Wizard triggered a live test event firedrill."}
|
||||
details := EventDetails{{"test_message", "Wizard triggered a live test event firedrill."}}
|
||||
|
||||
if s.testTrigger != "" {
|
||||
trigger = s.testTrigger
|
||||
@@ -241,7 +241,7 @@ func (s *Sensor) RunTestMode() bool {
|
||||
trigger := "test_mode_synthetic_alert"
|
||||
source := "CI/CD Runner"
|
||||
target := "Mock Hub"
|
||||
details := map[string]any{"test_message": "Automated CI/CD check."}
|
||||
details := EventDetails{{"test_message", "Automated CI/CD check."}}
|
||||
|
||||
if s.testTrigger != "" {
|
||||
trigger = s.testTrigger
|
||||
@@ -275,7 +275,33 @@ func (s *Sensor) RunTestMode() bool {
|
||||
// PIPELINE A: EVENT WORKER
|
||||
// ==========================================
|
||||
|
||||
func (s *Sensor) ReportEvent(trigger, source, target string, details map[string]any) bool {
|
||||
// EventDetail represents an ordered key-value pair for event details
|
||||
type EventDetail struct {
|
||||
Key string
|
||||
Value any
|
||||
}
|
||||
|
||||
// EventDetails is an ordered slice of event details that marshals to a JSON object
|
||||
type EventDetails []EventDetail
|
||||
|
||||
func (ed EventDetails) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("{")
|
||||
for i, d := range ed {
|
||||
if i > 0 {
|
||||
buf.WriteString(",")
|
||||
}
|
||||
key, _ := json.Marshal(d.Key)
|
||||
val, _ := json.Marshal(d.Value)
|
||||
buf.Write(key)
|
||||
buf.WriteString(":")
|
||||
buf.Write(val)
|
||||
}
|
||||
buf.WriteString("}")
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (s *Sensor) ReportEvent(trigger, source, target string, details EventDetails) bool {
|
||||
payload := map[string]any{
|
||||
"contractVersion": s.hubContractVersion,
|
||||
"sensorId": s.SensorID,
|
||||
|
||||
@@ -264,7 +264,7 @@ func TestReportEvent_Serialization(t *testing.T) {
|
||||
trigger := "test_serialization"
|
||||
source := "192.168.1.10"
|
||||
target := "8.8.8.8:53"
|
||||
details := map[string]any{"protocol": "dns"}
|
||||
details := EventDetails{{"protocol", "dns"}}
|
||||
|
||||
// Report the event, which places it on the channel
|
||||
if !s.ReportEvent(trigger, source, target, details) {
|
||||
@@ -287,8 +287,9 @@ func TestReportEvent_Serialization(t *testing.T) {
|
||||
if got, want := receivedPayload["target"], target; got != want {
|
||||
t.Errorf("target mismatch: got %v, want %v", got, want)
|
||||
}
|
||||
if !reflect.DeepEqual(receivedPayload["details"], details) {
|
||||
t.Errorf("details mismatch: got %v, want %v", receivedPayload["details"], details)
|
||||
expectedDetails := map[string]any{"protocol": "dns"}
|
||||
if !reflect.DeepEqual(receivedPayload["details"], expectedDetails) {
|
||||
t.Errorf("details mismatch: got %v, want %v", receivedPayload["details"], expectedDetails)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("Timed out waiting for server to receive event payload")
|
||||
|
||||
@@ -167,10 +167,10 @@ func reportFileEvent(
|
||||
trigger,
|
||||
"Local OS",
|
||||
filepath.Base(path),
|
||||
map[string]any{
|
||||
"category": category,
|
||||
"action": action,
|
||||
"path": path,
|
||||
sdk.EventDetails{
|
||||
{"category", category},
|
||||
{"action", action},
|
||||
{"path", path},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -195,11 +195,11 @@ func main() {
|
||||
"decoy_file_tampered",
|
||||
"Wizard Firedrill",
|
||||
"Mock Canary File",
|
||||
map[string]any{
|
||||
"test_message": "Wizard triggered a synthetic event firedrill.",
|
||||
"category": "tamper",
|
||||
"action": "Decoy file modified",
|
||||
"path": "/canaries/mock_passwords.txt",
|
||||
sdk.EventDetails{
|
||||
{"test_message", "Wizard triggered a synthetic event firedrill."},
|
||||
{"category", "tamper"},
|
||||
{"action", "Decoy file modified"},
|
||||
{"path", "/canaries/mock_passwords.txt"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@ func main() {
|
||||
"icmp_ping_received",
|
||||
"Wizard Firedrill",
|
||||
"ICMP Listener",
|
||||
map[string]any{
|
||||
"test_message": "Wizard triggered a synthetic event firedrill.",
|
||||
"packet_size": 64,
|
||||
"icmp_id": 1337,
|
||||
"icmp_seq": 1,
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{
|
||||
{"test_message", "Wizard triggered a synthetic event firedrill."},
|
||||
{"packet_size", 64},
|
||||
{"icmp_id", 1337},
|
||||
{"icmp_seq", 1},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -99,11 +99,11 @@ func listenICMP(conn *icmp.PacketConn, hw *sdk.Sensor) {
|
||||
"icmp_ping_received",
|
||||
sourceIP,
|
||||
"ICMP Listener",
|
||||
map[string]any{
|
||||
"packet_size": n,
|
||||
"icmp_id": echo.ID,
|
||||
"icmp_seq": echo.Seq,
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{
|
||||
{"packet_size", n},
|
||||
{"icmp_id", echo.ID},
|
||||
{"icmp_seq", echo.Seq},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -42,12 +42,12 @@ func main() {
|
||||
"network_scan_detected",
|
||||
"Wizard Firedrill",
|
||||
"Multiple Ports",
|
||||
map[string]any{
|
||||
"test_message": "Wizard triggered a synthetic event firedrill.",
|
||||
"ports_hit": []uint16{22, 80, 443, 3306, 8080},
|
||||
"count": 5,
|
||||
"window_sec": 5.0,
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{
|
||||
{"test_message", "Wizard triggered a synthetic event firedrill."},
|
||||
{"ports_hit", []uint16{22, 80, 443, 3306, 8080}},
|
||||
{"count", 5},
|
||||
{"window_sec", 5.0},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -149,11 +149,11 @@ func processHit(hw *sdk.Sensor, srcIP string, dstPort uint16) {
|
||||
"network_scan_detected",
|
||||
srcIP,
|
||||
"Multiple Ports",
|
||||
map[string]any{
|
||||
"ports_hit": uniquePortsList,
|
||||
"count": len(uniquePortsList),
|
||||
"window_sec": window.Seconds(),
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{
|
||||
{"ports_hit", uniquePortsList},
|
||||
{"count", len(uniquePortsList)},
|
||||
{"window_sec", window.Seconds()},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
state.history = nil
|
||||
|
||||
@@ -35,11 +35,11 @@ func main() {
|
||||
"tcp_connection",
|
||||
"Wizard Firedrill",
|
||||
"Mock Tarpit Port",
|
||||
map[string]any{
|
||||
"test_message": "Wizard triggered a synthetic event firedrill.",
|
||||
"payload": []string{"SSH-2.0-Firedrill-Test\r\n"},
|
||||
"duration_sec": 5.2,
|
||||
"action_taken": "hold",
|
||||
sdk.EventDetails{
|
||||
{"test_message", "Wizard triggered a synthetic event firedrill."},
|
||||
{"payload", []string{"SSH-2.0-Firedrill-Test\r\n"}},
|
||||
{"duration_sec", 5.2},
|
||||
{"action_taken", "hold"},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -165,10 +165,10 @@ func handleConnection(hw *sdk.Sensor, conn net.Conn, port int) {
|
||||
"tcp_connection",
|
||||
srcIP,
|
||||
fmt.Sprintf("Port %d", port),
|
||||
map[string]any{
|
||||
"duration_sec": duration,
|
||||
"payload": payload,
|
||||
"action_taken": tarpitMode,
|
||||
sdk.EventDetails{
|
||||
{"duration_sec", duration},
|
||||
{"payload", payload},
|
||||
{"action_taken", tarpitMode},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -251,12 +251,12 @@ func main() {
|
||||
"web_login_attempt",
|
||||
"Wizard Firedrill",
|
||||
"Web Interface",
|
||||
map[string]any{
|
||||
"test_message": "Wizard triggered a synthetic event firedrill.",
|
||||
"user_agent": "HoneyWire-Firedrill/1.0",
|
||||
"attempted_username": "admin",
|
||||
"attempted_password": "password123",
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{
|
||||
{"test_message", "Wizard triggered a synthetic event firedrill."},
|
||||
{"user_agent", "HoneyWire-Firedrill/1.0"},
|
||||
{"attempted_username", "admin"},
|
||||
{"attempted_password", "password123"},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -350,11 +350,11 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
"web_login_attempt",
|
||||
srcIP,
|
||||
"Web Interface",
|
||||
map[string]any{
|
||||
"user_agent": userAgent,
|
||||
"attempted_username": username,
|
||||
"attempted_password": password,
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{
|
||||
{"user_agent", userAgent},
|
||||
{"attempted_username", username},
|
||||
{"attempted_password", password},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ func main() {
|
||||
"custom_anomaly_detected",
|
||||
"Wizard Firedrill",
|
||||
"Mock Custom Target",
|
||||
map[string]any{
|
||||
"test_message": "Wizard triggered a synthetic event firedrill.",
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{
|
||||
{"test_message", "Wizard triggered a synthetic event firedrill."},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -84,10 +84,10 @@ func runSensor(ctx context.Context, hw *sdk.Sensor) {
|
||||
"custom_anomaly_detected", // 1. Event Trigger
|
||||
sourceIP, // 2. Source
|
||||
target, // 3. Target
|
||||
map[string]any{ // 4. Details
|
||||
"attack_type": "example_probe",
|
||||
"raw_payload": "GET /etc/passwd HTTP/1.1",
|
||||
"action_taken": "logged",
|
||||
sdk.EventDetails{ // 4. Details
|
||||
{"attack_type", "example_probe"},
|
||||
{"raw_payload", "GET /etc/passwd HTTP/1.1"},
|
||||
{"action_taken", "logged"},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user