Real-time traffic analyzer for Ragnar server mode. Uses tcpdump for packet capture and provides: - Live connection tracking - Per-host bandwidth statistics - Protocol distribution analysis - Suspicious pattern detection
| 153 | 'bytes_in': self.bytes_in, |
| 154 | 'bytes_out': self.bytes_out, |
| 155 | 'protocols': self.protocols, |
| 156 | 'ports_contacted': list(self.ports_contacted)[:100], # Limit for API |
| 157 | 'ports_targeted': list(self.ports_targeted)[:100], |
| 158 | 'connections_active': self.connections_active, |
| 159 | 'first_seen': self.first_seen.isoformat(), |
| 160 | 'last_seen': self.last_seen.isoformat(), |
| 161 | 'dns_queries': self.dns_queries[-50:], # Last 50 queries |
| 162 | } |
| 163 | |
| 164 | |
| 165 | class TrafficAnalyzer: |
| 166 | """ |
| 167 | Real-time traffic analyzer. |
| 168 | |
| 169 | Uses tcpdump for packet capture and provides: |
| 170 | - Live connection tracking |
| 171 | - Per-host bandwidth statistics |
| 172 | - Protocol distribution analysis |
| 173 | - Suspicious pattern detection |
| 174 | """ |
| 175 | |
| 176 | # Suspicious ports with descriptions for analyst context |
| 177 | SUSPICIOUS_PORTS = { |
| 178 | 4444: "Metasploit default listener", |
| 179 | 5555: "Android ADB / common backdoor", |
| 180 | 6666: "IRC backdoor / DarkComet", |
| 181 | 1234: "Generic backdoor", |
| 182 | 31337: "Back Orifice / 'elite' port", |
| 183 | 12345: "NetBus trojan", |
| 184 | 65535: "Uncommon max port (evasion)", |
| 185 | 6667: "IRC (C2 channel)", |
| 186 | 6697: "IRC over TLS", |
| 187 | 8080: "HTTP proxy (if unexpected)", |
| 188 | 9001: "Tor default", |
| 189 | 9050: "Tor SOCKS proxy", |
| 190 | 1337: "Common hacker port", |
| 191 | 5900: "VNC (if unauthorized)", |
| 192 | 2222: "SSH alternate (dropbear)", |
| 193 | } |
| 194 | |
| 195 | # Ports whose "suspicious" classification only makes sense over TCP + |
| 196 | # unicast. UDP broadcasts on these are almost always a custom IoT / |
| 197 | # discovery protocol that happened to pick the port — not C2. |
| 198 | TCP_UNICAST_ONLY_PORTS = frozenset({ |
| 199 | 4444, 5555, 6666, 6667, 6697, 9001, 9050, 5900, 2222, |
| 200 | }) |
| 201 | |
| 202 | # DNS tunneling detection threshold |
| 203 | DNS_TUNNEL_THRESHOLD = 100 # Queries per minute from single host |
| 204 | DNS_QUERY_TRACKING_WINDOW = 60 # Seconds to track DNS query rate |
| 205 | |
| 206 | # C2 beacon detection |
| 207 | # A flow is considered a beacon candidate when a local host repeatedly |
| 208 | # contacts the same external (ip, port) at low-jitter intervals with |
| 209 | # similar payload sizes. See _sweep_beacons() for the scoring. |
| 210 | BEACON_MIN_SAMPLES = 6 # Need this many hits before scoring |
| 211 | BEACON_HISTORY_MAX = 64 # Ring buffer length per flow |
| 212 | BEACON_MIN_INTERVAL = 5.0 # Ignore sub-5s noise (HTTP keepalive) |
no outgoing calls