Cybersecurity-Projects/PROJECTS/beginner/network-traffic-analyzer/cpp/learn/04-CHALLENGES.md

8.1 KiB
Raw Permalink Blame History

Challenges and Extensions

These are concrete things you can build on top of the existing codebase. Each one has a clear starting point in the code and a reason why it's worth doing.

Beginner

1. Add ICMP Type Breakdown

Right now ICMP packets count as a single protocol entry. ICMP carries many message types: echo request/reply (ping), port unreachable, time exceeded (traceroute hops), etc.

What to do: In IPv4::handle_icmp() (src/packet/IP.cpp:73), cast the payload to icmphdr and read type and code. Extend ApplicationProtocol in packet.hpp to include ICMP_ECHO, ICMP_UNREACHABLE, etc., or add a separate icmp_type field to Packet.

Why it matters: ICMP is frequently used for recon (ping sweeps) and for covert channels (ICMP tunneling tools like icmptunnel encode data in the payload). Being able to distinguish echo requests from unreachable messages tells you whether you're being scanned or whether routes are broken.

2. Color-Code Protocols in the TUI

Add color to the transport and application protocol tables — TCP in blue, UDP in green, ICMP in yellow, unknown in red.

What to do: In view.cpp:render_transport(), access individual cells with table.SelectCell(row, col).Decorate(color(Color::Blue)). FTXUI's Table::SelectCell() takes row and column indices.

Why it matters: Security operators scan dashboards under time pressure. Color coding lets the eye jump to anomalies (unexpected UDP traffic, unknown protocols) without reading every row.

3. Add a Packet Rate Counter

Display packets/sec alongside the bandwidth graph. The bandwidth graph shows bytes/sec, but packet rate is separately useful — a flood of tiny packets at low bandwidth is a different pattern than a few large transfers.

What to do: Add uint32_t last_p = 0 to Stats (alongside last_b). In update_bandwidth() (protocolStats.cpp:230), compute delta_packets / elapsed alongside the existing byte calculation. Add it to StatsSnapshot and display it in render_header() or render_stats().


Intermediate

4. TCP Stream Reassembly

Right now each TCP packet is analyzed independently. Application-level protocols that span multiple packets (HTTP responses, FTP transfers) aren't reconstructed. Reassembly combines TCP segments in sequence number order into a stream.

What to do: Add a StreamTable class that maps (src_ip, dst_ip, src_port, dst_port) to an ordered buffer of segments (keyed by sequence number). In got_packet() (pcapCapture.cpp:152), after constructing a TCP Packet, insert it into the stream table. When segments arrive in order, append to the stream buffer. When a gap fills, run application-layer identification on the complete buffer.

Why it matters: HTTP detection by verb matching (memcmp(payload_ptr, "GET ", 4) in packet.cpp:9) only works if the HTTP request fits in the first packet. For large PUT/POST bodies or slow connections, the verb might be in an earlier segment that's already been processed. Reassembly is how Snort, Suricata, and commercial DPI engines handle this.

5. DNS Query Logging

Extract DNS query names from UDP packets on port 53 and log them with timestamps.

What to do: In Packet::get_application_protocol() (packet.cpp:14), when DNS is identified, parse the DNS question section from payload_ptr. DNS is binary: bytes 011 are the header (ID, flags, counts), bytes 12+ are the question section as a length-prefixed label sequence (e.g., \x03www\x07example\x03com\x00). Walk the labels to extract the FQDN. Add a dns_query string field to Packet and display it in the packets table.

Why it matters: DNS is the phone book attackers always use. C2 beacons check in via DNS. Data exfiltration encodes data in DNS queries (DNS tunneling). A simple query log catches malware like dnscat2 which uses DNS TXT records for a command shell — the queries show absurdly long subdomain names.

6. Alert Rules Engine

Add a rule evaluation engine that fires alerts when traffic matches configurable conditions: "alert if any single IP sends > 1000 packets in 10 seconds" (port scan), "alert if DNS queries/sec > 100" (tunneling), "alert if a new IP appears that wasn't in baseline" (lateral movement).

What to do: Create an AlertRule struct with a condition function and threshold. Create an AlertEngine that the UI update thread calls after update_ip_stats(). Rules inspect the Stats snapshot for threshold violations. Store triggered alerts in a deque<Alert> and add a panel to view.cpp to display them.

Why it matters: This is the core of what a SIEM does. SIEMs (Splunk, Elastic SIEM, IBM QRadar) correlate events from multiple sources, but the underlying idea — evaluate rule conditions against observed metrics, fire alert when exceeded — is what you're building here.


Advanced

7. Packet Payload Hex Dump

Add a detail view that shows the raw hex bytes and ASCII representation of a selected packet's payload — like Wireshark's bottom pane.

What to do: The payload_ptr is currently nulled after get_application_protocol() runs (packet.hpp:53). To support hex dump, copy the payload bytes into a vector<uint8_t> before nulling. Add a selected-packet index to View state, a way to navigate it (arrow keys via CatchEvent), and a render_hex_dump() method that formats bytes as XX XX XX ... | .text.. rows.

FTXUI doesn't have a built-in hex dump widget. You'd build it with a series of hbox({text(hex_col) | fixed(50), text(ascii_col)}) elements.

Why it matters: Payload inspection is how you verify that an alert is real. "DNS traffic" is easy to detect. Knowing whether that DNS traffic contains normal queries or base64-encoded exfiltration requires looking at the bytes.

8. Anomaly Baseline and Deviation Detection

Record a traffic baseline over a configurable window (e.g., first 60 seconds), then flag deviations. A new protocol appearing, a normally-quiet IP becoming a top talker, or TCP traffic on a UDP-only port all warrant investigation.

What to do: Add a Baseline class that snapshots transport_map and ip_map after the baseline window. Add a compare(current_snapshot, baseline) function that computes Z-scores or percentage deltas for each metric. Store deviations in a vector<Deviation> and render them in a new TUI panel.

Why it matters: The 2020 SolarWinds attack persisted undetected for 9 months partly because the malicious traffic mimicked normal Orion product telemetry — it looked like expected traffic to anyone checking manually. Automated baseline comparison would have flagged the new beacon pattern against the pre-compromise baseline.

9. PCAP Export During Live Capture

Let the user write a .pcap file of captured traffic in real time, not just export stats at the end. This enables offline analysis in Wireshark after the fact.

What to do: Use pcap_dump_open() to create a dump file handle, and pcap_dump() inside got_packet() (pcapCapture.cpp:152) to write each raw packet with its pcap_pkthdr. Add a --write flag to argsParser (argsParse.cpp). The dump handle is another C resource that benefits from RAII wrapping.

Why it matters: Live capture tools in incident response always write pcap files. You want to capture first, analyze later — especially if the attack is still in progress. Tools like tcpdump -w and dumpcap do exactly this.

10. Protocol-Aware Port Scanning Detection

Detect SYN-only streams (where TCP connections are initiated but never completed) and flag them as potential port scans.

What to do: In the TCP stream table (from challenge 4), track TCP flags on each packet. A SYN with no SYN-ACK reply within a timeout is a half-open scan. Count the number of distinct destination ports from a single source IP within a time window — more than N unique ports in M seconds = probable scan. This is the algorithm portsentry, snort, and modern firewalls use.

The 2016 Mirai botnet scanned the entire IPv4 internet for open Telnet/SSH ports in under an hour by running SYN scans from 100,000+ infected devices simultaneously. Detecting scan patterns at the packet level — not just counting connection attempts — is how network IDS systems catch this.