This commit is contained in:
92
main.go
92
main.go
@@ -4963,42 +4963,51 @@ func buildSQLMatchCondition(r DynamicRule) (string, []any) {
|
||||
}
|
||||
|
||||
func (s *server) runDetectionsOnce() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), s.cfg.DetectionInterval)
|
||||
defer cancel()
|
||||
|
||||
if err := s.detector.updateAgentMetrics(ctx); err != nil {
|
||||
s.logger.Printf("update agent metrics: %v", err)
|
||||
type ruleSpec struct {
|
||||
name string
|
||||
timeout time.Duration
|
||||
fn func(context.Context) error
|
||||
}
|
||||
|
||||
rules := []struct {
|
||||
name string
|
||||
fn func(context.Context) error
|
||||
}{
|
||||
{"agent_offline", s.detector.runAgentOfflineRule},
|
||||
{"failed_logon_spike", s.detector.runFailedLogonSpikeRule},
|
||||
{"reboot_spike", s.detector.runRebootSpikeRule},
|
||||
{"new_event_id", s.detector.runNewEventIDRule},
|
||||
{"password_spray", s.detector.runPasswordSprayRule},
|
||||
{"success_after_failures", s.detector.runSuccessAfterFailuresRule},
|
||||
{"new_source_ip_for_user", s.detector.runNewSourceIPForUserRule},
|
||||
{"dynamic_rules", s.detector.runDynamicRules},
|
||||
rules := []ruleSpec{
|
||||
{"agent_offline", 15 * time.Second, s.detector.runAgentOfflineRule},
|
||||
{"failed_logon_spike", 45 * time.Second, s.detector.runFailedLogonSpikeRule},
|
||||
{"reboot_spike", 30 * time.Second, s.detector.runRebootSpikeRule},
|
||||
{"new_event_id", 60 * time.Second, s.detector.runNewEventIDRule},
|
||||
{"password_spray", 60 * time.Second, s.detector.runPasswordSprayRule},
|
||||
{"success_after_failures", 90 * time.Second, s.detector.runSuccessAfterFailuresRule},
|
||||
{"new_source_ip_for_user", 90 * time.Second, s.detector.runNewSourceIPForUserRule},
|
||||
{"dynamic_rules", 60 * time.Second, s.detector.runDynamicRules},
|
||||
|
||||
{"ueba_admin_new_host", s.detector.runAdminNewHostRule},
|
||||
{"ueba_offhours_login", s.detector.runOffHoursLoginRule},
|
||||
{"ueba_first_privileged_use", s.detector.runFirstTimePrivilegedRule},
|
||||
{"ueba_new_user_context", s.detector.runUEBANewUserContextRule},
|
||||
{"ueba_update", s.detector.runUEBABaselineUpdate},
|
||||
{"ueba_admin_new_host", 90 * time.Second, s.detector.runAdminNewHostRule},
|
||||
{"ueba_offhours_login", 60 * time.Second, s.detector.runOffHoursLoginRule},
|
||||
{"ueba_first_privileged_use", 60 * time.Second, s.detector.runFirstTimePrivilegedRule},
|
||||
|
||||
// Diese Regel ist bei dir aktuell der Problemfall.
|
||||
{"ueba_new_user_context", 180 * time.Second, s.detector.runUEBANewUserContextRule},
|
||||
|
||||
{"ueba_update", 120 * time.Second, s.detector.runUEBABaselineUpdate},
|
||||
}
|
||||
|
||||
for _, rule := range rules {
|
||||
start := time.Now()
|
||||
if err := rule.fn(ctx); err != nil {
|
||||
s.logger.Printf("rule %s error: %v", rule.name, err)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rule.timeout)
|
||||
err := rule.fn(ctx)
|
||||
cancel()
|
||||
|
||||
dur := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Printf("rule %s error after %s: %v", rule.name, dur, err)
|
||||
s.detector.ruleErrorsTotal.WithLabelValues(rule.name).Inc()
|
||||
continue
|
||||
}
|
||||
|
||||
s.logger.Printf("rule %s completed in %s", rule.name, dur)
|
||||
|
||||
s.detector.ruleLastRunGauge.WithLabelValues(rule.name).Set(float64(time.Now().Unix()))
|
||||
s.detector.ruleRuntimeHist.WithLabelValues(rule.name).Observe(time.Since(start).Seconds())
|
||||
s.detector.ruleRuntimeHist.WithLabelValues(rule.name).Observe(dur.Seconds())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5061,6 +5070,8 @@ func (d *detector) runUEBANewUserContextRule(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
windowEnd := time.Now().UTC()
|
||||
windowStart := windowEnd.Add(-d.cfg.UEBANewContextWindow)
|
||||
|
||||
@@ -5079,23 +5090,21 @@ WHERE e.channel_name = 'Security'
|
||||
AND e.target_user <> ''
|
||||
AND e.target_user <> '-'
|
||||
AND e.target_user NOT LIKE '%$'
|
||||
AND LOWER(e.target_user) NOT IN (
|
||||
'system',
|
||||
'localsystem',
|
||||
'local service',
|
||||
'network service',
|
||||
'anonymous logon'
|
||||
)
|
||||
GROUP BY e.hostname, e.target_user, e.src_ip, e.workstation
|
||||
`
|
||||
|
||||
rows, err := d.db.QueryContext(ctx, q, windowStart, windowEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("query ueba_new_user_context after %s: %w", time.Since(start), err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
rowCount := 0
|
||||
newCount := 0
|
||||
|
||||
for rows.Next() {
|
||||
rowCount++
|
||||
|
||||
var host, user, srcIP, workstation string
|
||||
var firstSeen time.Time
|
||||
var count int
|
||||
@@ -5118,6 +5127,8 @@ GROUP BY e.hostname, e.target_user, e.src_ip, e.workstation
|
||||
continue
|
||||
}
|
||||
|
||||
newCount++
|
||||
|
||||
score := 2.0
|
||||
severity := "medium"
|
||||
|
||||
@@ -5162,9 +5173,20 @@ GROUP BY e.hostname, e.target_user, e.src_ip, e.workstation
|
||||
}
|
||||
}
|
||||
|
||||
return rows.Err()
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.logger.Printf(
|
||||
"ueba_new_user_context processed rows=%d new_contexts=%d window=%s duration=%s",
|
||||
rowCount,
|
||||
newCount,
|
||||
d.cfg.UEBANewContextWindow,
|
||||
time.Since(start),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
func riskWeight(severity string) float64 {
|
||||
switch severity {
|
||||
case "critical":
|
||||
|
||||
Reference in New Issue
Block a user