Anpassung Noise-Canceling new_source_ip_for_user
All checks were successful
release-tag / release-image (push) Successful in 2m38s
All checks were successful
release-tag / release-image (push) Successful in 2m38s
This commit is contained in:
@@ -1800,4 +1800,14 @@ VALUES
|
||||
('administrator', 'Built-in Administrator', 1),
|
||||
('admin', 'Generic admin account', 1)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
reason = VALUES(reason);
|
||||
reason = VALUES(reason);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_source_ip_seen (
|
||||
username VARCHAR(255) NOT NULL,
|
||||
src_ip VARCHAR(64) NOT NULL,
|
||||
hostname VARCHAR(255) NOT NULL,
|
||||
first_seen DATETIME(6) NOT NULL,
|
||||
last_seen DATETIME(6) NOT NULL,
|
||||
seen_count BIGINT NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (username, src_ip, hostname)
|
||||
);
|
||||
98
main.go
98
main.go
@@ -5278,29 +5278,31 @@ GROUP BY s.hostname, s.target_user, s.src_ip
|
||||
func (d *detector) runNewSourceIPForUserRule(ctx context.Context) error {
|
||||
windowEnd := time.Now().UTC()
|
||||
windowStart := windowEnd.Add(-d.cfg.NewSourceIPWindow)
|
||||
lookbackStart := windowStart.Add(-d.cfg.NewSourceIPLookback)
|
||||
|
||||
const q = `
|
||||
SELECT e.hostname, e.target_user, e.src_ip, COUNT(*) AS cnt
|
||||
SELECT e.hostname, e.target_user, e.src_ip, MIN(e.ts) AS first_seen, COUNT(*) AS cnt
|
||||
FROM event_logs e
|
||||
WHERE e.channel_name = 'Security'
|
||||
AND e.event_id = 4624
|
||||
AND e.ts >= ? AND e.ts < ?
|
||||
AND e.target_user <> '' AND e.target_user <> '-'
|
||||
AND e.src_ip <> '' AND e.src_ip <> '-' AND e.src_ip <> '::1' AND e.src_ip <> '127.0.0.1'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM event_logs old
|
||||
WHERE old.hostname = e.hostname
|
||||
AND old.channel_name = 'Security'
|
||||
AND old.event_id = 4624
|
||||
AND old.target_user = e.target_user
|
||||
AND old.src_ip = e.src_ip
|
||||
AND old.ts >= ? AND old.ts < ?
|
||||
AND e.target_user <> ''
|
||||
AND e.target_user <> '-'
|
||||
AND e.target_user NOT LIKE '%$'
|
||||
AND e.src_ip <> ''
|
||||
AND e.src_ip <> '-'
|
||||
AND e.src_ip <> '::1'
|
||||
AND e.src_ip <> '127.0.0.1'
|
||||
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
|
||||
`
|
||||
rows, err := d.db.QueryContext(ctx, q, windowStart, windowEnd, lookbackStart, windowStart)
|
||||
|
||||
rows, err := d.db.QueryContext(ctx, q, windowStart, windowEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -5308,17 +5310,33 @@ GROUP BY e.hostname, e.target_user, e.src_ip
|
||||
|
||||
for rows.Next() {
|
||||
var host, user, srcIP string
|
||||
var firstSeen time.Time
|
||||
var cnt int
|
||||
if err := rows.Scan(&host, &user, &srcIP, &cnt); err != nil {
|
||||
|
||||
if err := rows.Scan(&host, &user, &srcIP, &firstSeen, &cnt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user = normalizeUsername(user)
|
||||
if isNoiseAccount(user) {
|
||||
continue
|
||||
}
|
||||
|
||||
isNew, err := d.touchUserSourceIPSeen(ctx, user, srcIP, host, firstSeen, cnt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !isNew {
|
||||
continue
|
||||
}
|
||||
|
||||
score := 1.5 + math.Log10(float64(cnt)+1)
|
||||
|
||||
severity := "medium"
|
||||
if cnt >= 5 {
|
||||
severity = "high"
|
||||
}
|
||||
d.anomalyScoreGauge.WithLabelValues(host, "new_source_ip_for_user").Set(score)
|
||||
|
||||
created, err := d.insertDetection(ctx, Detection{
|
||||
RuleName: "new_source_ip_for_user",
|
||||
@@ -5329,23 +5347,27 @@ GROUP BY e.hostname, e.target_user, e.src_ip
|
||||
Score: score,
|
||||
WindowStart: windowStart,
|
||||
WindowEnd: windowEnd,
|
||||
Summary: fmt.Sprintf("Benutzer %s meldet sich auf %s von neuer Quell-IP %s an", user, host, srcIP),
|
||||
Summary: fmt.Sprintf("Benutzer %s meldet sich auf %s erstmals von Quell-IP %s an", user, host, srcIP),
|
||||
Details: mustJSON(map[string]any{
|
||||
"user": user,
|
||||
"src_ip": srcIP,
|
||||
"host": host,
|
||||
"count": cnt,
|
||||
"first_seen": firstSeen.UTC().Format(time.RFC3339Nano),
|
||||
"window_minutes": int(d.cfg.NewSourceIPWindow.Minutes()),
|
||||
"lookback_hours": int(d.cfg.NewSourceIPLookback.Hours()),
|
||||
"event_id": 4624,
|
||||
}),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if created {
|
||||
d.detectionHitsTotal.WithLabelValues("new_source_ip_for_user", severity).Inc()
|
||||
d.anomalyScoreGauge.WithLabelValues(host, "new_source_ip_for_user").Set(score)
|
||||
}
|
||||
}
|
||||
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
@@ -5859,6 +5881,46 @@ GROUP BY hostname, target_user
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func (d *detector) touchUserSourceIPSeen(ctx context.Context, username, srcIP, hostname string, firstSeen time.Time, count int) (bool, error) {
|
||||
username = normalizeUsername(username)
|
||||
hostname = strings.TrimSpace(hostname)
|
||||
srcIP = strings.TrimSpace(srcIP)
|
||||
|
||||
if username == "" || srcIP == "" || hostname == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
res, err := d.db.ExecContext(ctx, `
|
||||
INSERT INTO user_source_ip_seen
|
||||
(username, src_ip, hostname, first_seen, last_seen, seen_count)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
last_seen = VALUES(last_seen),
|
||||
seen_count = seen_count + VALUES(seen_count)
|
||||
`,
|
||||
username,
|
||||
srcIP,
|
||||
hostname,
|
||||
firstSeen.UTC(),
|
||||
firstSeen.UTC(),
|
||||
count,
|
||||
)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// MySQL:
|
||||
// 1 = Insert
|
||||
// 2 = Update durch ON DUPLICATE KEY UPDATE
|
||||
// 0 = kein effektives Update, je nach Client/Settings möglich
|
||||
return affected == 1, nil
|
||||
}
|
||||
|
||||
func (d *detector) runFirstTimePrivilegedRule(ctx context.Context) error {
|
||||
if !d.cfg.UEBAEnabled {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user