danielostrow commited on
Commit
ab9baba
·
verified ·
1 Parent(s): 2b5ad85

Fix websocket pattern + improve beacon override logic to prevent false positives/negatives

Browse files
Files changed (1) hide show
  1. c2sentinel.py +26 -11
c2sentinel.py CHANGED
@@ -278,15 +278,15 @@ LEGITIMATE_PATTERNS = [
278
  description="Database connection with variable query responses"
279
  ),
280
  LegitimatePattern(
281
- name="websocket_ping",
282
  service_type=ServiceType.API,
283
  ports=[80, 443, 8080],
284
- min_packet_size=10,
285
  max_packet_size=100000,
286
- symmetric_ratio=(0.001, 100.0), # Can receive large data pushes
287
- max_interval_cv=0.5,
288
- max_size_cv=5.0, # Large variance in push data
289
- description="WebSocket connection with ping/pong and data pushes"
290
  ),
291
  ]
292
 
@@ -1712,14 +1712,29 @@ class C2Sentinel:
1712
 
1713
  # ================================================================
1714
  # PHASE 5: Apply legitimate pattern discount
1715
- # High-confidence legitimate patterns should NOT be overridden by beacon indicators
1716
  # ================================================================
1717
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1718
  if matched_pattern and pattern_confidence > 0.5:
1719
- # High-confidence legitimate patterns (> 0.75) always get full discount
1720
- # This prevents false positives on known good traffic
1721
- if pattern_confidence >= 0.75:
1722
- # Strong legitimate pattern match - apply full discount regardless of beacon indicators
 
1723
  discount = 1.0 - (pattern_confidence * 0.8) # Up to 80% reduction
1724
  c2_prob *= discount
1725
  result.mitigating_factors.append(f"Strong {matched_pattern.name} pattern match (conf: {pattern_confidence:.0%})")
 
278
  description="Database connection with variable query responses"
279
  ),
280
  LegitimatePattern(
281
+ name="websocket_stream",
282
  service_type=ServiceType.API,
283
  ports=[80, 443, 8080],
284
+ min_packet_size=100, # WebSocket frames are typically larger
285
  max_packet_size=100000,
286
+ symmetric_ratio=(0.001, 0.3), # Receives much more than sends (streaming)
287
+ max_interval_cv=1.5, # Irregular timing (event-driven)
288
+ max_size_cv=2.0, # High variance in response sizes (required)
289
+ description="WebSocket streaming connection with variable push data"
290
  ),
291
  ]
292
 
 
1712
 
1713
  # ================================================================
1714
  # PHASE 5: Apply legitimate pattern discount
1715
+ # Balance between legitimate patterns and beacon indicators
1716
  # ================================================================
1717
 
1718
+ # Check if we have a very strong beacon signal that should override patterns
1719
+ very_strong_beacon = False
1720
+ if beacon_indicators >= 5:
1721
+ very_strong_beacon = True
1722
+ elif beacon_indicators >= 4:
1723
+ # Check if timing and size CVs are extremely low (strong C2 signature)
1724
+ if len(connections) >= 5:
1725
+ timestamps = sorted([c.get('timestamp', 0) for c in connections])
1726
+ if len(timestamps) > 1:
1727
+ intervals = np.diff(timestamps)
1728
+ interval_cv = np.std(intervals) / (np.mean(intervals) + 1e-6)
1729
+ if interval_cv < 0.1 and recv_cv < 0.1:
1730
+ very_strong_beacon = True
1731
+
1732
  if matched_pattern and pattern_confidence > 0.5:
1733
+ # Very strong beacon signals override legitimate patterns (except SSH on port 22)
1734
+ if very_strong_beacon and matched_pattern.name != 'ssh_keepalive':
1735
+ result.mitigating_factors.append(f"{matched_pattern.name} pattern overridden by very strong beacon signal")
1736
+ elif pattern_confidence >= 0.75 and not very_strong_beacon:
1737
+ # Strong legitimate pattern without strong beacon - apply full discount
1738
  discount = 1.0 - (pattern_confidence * 0.8) # Up to 80% reduction
1739
  c2_prob *= discount
1740
  result.mitigating_factors.append(f"Strong {matched_pattern.name} pattern match (conf: {pattern_confidence:.0%})")