courses

Background Concepts Reference

This page collects concise explanations of concepts that appear across the course but that are not the primary focus of any single lecture. Use it as a quick reference when a term comes up in class or in a reading that you are not familiar with.


Network Fundamentals

Promiscuous Mode

A network interface normally discards any frame whose destination MAC address does not match its own. Promiscuous mode disables that filter: the interface passes every frame it receives to the OS, regardless of destination. This is required for packet capture tools like Wireshark, tcpdump, and scapy — without it you only see traffic addressed to your own machine.

# tcpdump and Wireshark enable promiscuous mode automatically.
# You can set it manually:
ip link set eth0 promisc on

Monitor mode (wireless) is the equivalent for Wi-Fi — see the WiFi modes section in the cracking lecture.

MAC Address Tables and Why You Cannot Sniff a Switched Network

A managed switch maintains a MAC address table (also called the CAM table) that maps each MAC address to the port it was learned on. When a frame arrives, the switch looks up the destination MAC and forwards the frame only to that port — all other ports see nothing. This is why promiscuous mode alone is not enough to capture traffic between two other hosts on the same switch. Options for capturing third-party traffic on a switched network include:

ARP Spoofing / Poisoning

ARP (Address Resolution Protocol) maps IPv4 addresses to MAC addresses. Hosts cache these mappings in an ARP table. ARP has no authentication: any host can send an ARP reply claiming to be any IP address.

ARP spoofing exploits this by broadcasting forged ARP replies:

"IP 192.168.1.1 is at MAC AA:BB:CC:DD:EE:FF"  ← your MAC, not the router's

Once both the victim and the gateway have poisoned ARP tables, traffic flows through your machine — a classic Layer 2 man-in-the-middle (MITM). Tools: arpspoof (dsniff suite), bettercap’s arp.spoof module.

Defenses: Dynamic ARP Inspection (DAI), static ARP entries, 802.1X port authentication.

Dynamic ARP Inspection (DAI)

DAI is a switch security feature that validates ARP replies before forwarding them. The switch maintains a DHCP snooping binding table (IP → MAC → port) and drops any ARP reply that contradicts it. This blocks ARP spoofing on managed enterprise switches. Home switches and most lab environments do not run DAI.

TCP Sequence Numbers and Acknowledgment Numbers

TCP guarantees in-order, reliable delivery using two counters in every packet:

Together these allow receivers to reorder out-of-order segments, detect lost packets, and confirm delivery. In a packet dump you will see seq=1234 ack=5678 — the sender is saying “I am sending bytes starting at 1234, and I have received everything up to 5677.”

MAC Vendor Prefixes (OUI)

The first three bytes (24 bits) of any MAC address are an Organizationally Unique Identifier (OUI) assigned by the IEEE to the hardware manufacturer. For example, F8:FF:C2 → Apple, 00:50:56 → VMware. Nmap, Wireshark, and arp-scan resolve OUIs automatically. In reconnaissance this lets you quickly identify device types and narrow scope (e.g., “all Raspberry Pi boards use B8:27:EB”).

# Look up an OUI manually
curl "https://api.macvendors.com/F8:FF:C2"
# or use the local Wireshark database:
grep -i "F8:FF:C2" /usr/share/wireshark/manuf

BPF Filter Syntax

Berkeley Packet Filter (BPF) is a filter language used by tcpdump, tshark, Wireshark, and scapy to specify which packets to capture or analyze. Basic primitives:

Expression Meaning
host 10.0.0.1 traffic to or from this IP
net 10.0.0.0/24 traffic within this subnet
port 80 traffic on port 80 (either direction)
tcp / udp / icmp protocol filter
tcp[13] & 2 != 0 TCP SYN flag set (byte 13 of TCP header, bit 1)

Combine with and, or, not:

tcpdump -i eth0 'host 10.0.0.1 and not port 22'

BPF filters run in the kernel before data is copied to userspace, so they are very efficient. Wireshark’s display filters are a different, richer syntax applied after capture.


Wireless Networking

BSSID, ESSID, Channel

Term Meaning
ESSID The human-readable network name (the SSID you see in your Wi-Fi list)
BSSID The MAC address of the access point (AP). Used to uniquely identify one AP when multiple APs share the same ESSID (e.g., enterprise Wi-Fi)
Channel The radio frequency band divided into numbered slices. 2.4 GHz uses channels 1–14 (only 1, 6, 11 are non-overlapping); 5 GHz uses channels 36–165

When doing passive reconnaissance with airodump-ng, each row represents one BSSID. Set --bssid and --channel to focus capture on a single AP and reduce noise.

Deauthentication Attack

IEEE 802.11 management frames (including deauthentication frames) are not authenticated in WPA2. An attacker can send a forged deauth frame on behalf of the AP to any client, causing it to disconnect. The client then automatically reconnects — performing a fresh 4-way handshake. Capturing this handshake is the first step in offline WPA2 cracking.

# Send 5 deauth frames to client AA:BB:CC:DD:EE:FF on AP 11:22:33:44:55:66
aireplay-ng --deauth 5 -a 11:22:33:44:55:66 -c AA:BB:CC:DD:EE:FF wlan0mon

The deauth attack does not weaken WPA2 cryptography and does not reveal the passphrase by itself — it only forces a handshake you can then crack offline. Sending deauth frames without authorization is illegal under the CFAA and equivalent statutes.


Cryptography Basics

Encoding vs Encryption

These terms are frequently confused:

Property Encoding (e.g., Base64) Encryption (e.g., AES)
Goal Represent binary as printable text Conceal plaintext from observers
Key required? No Yes
Reversible? Yes, by anyone Yes, only with the key
Security? None Depends on algorithm + key

Base64 encodes every 3 bytes of binary as 4 printable ASCII characters using the alphabet A-Za-z0-9+/ with = padding. It expands data by ~33% and is used in MIME email, HTTP Basic auth, data URIs, and JWT tokens. It is not a form of security.

import base64
base64.b64encode(b"Hello!")   # b'SGVsbG8h'
base64.b64decode(b"SGVsbG8h")  # b'Hello!'

Dictionary Attack vs Brute Force

Hybrid attacks combine both: take wordlist entries and apply rules (capitalize first letter, append digits) to generate variations. Hashcat’s rule engine makes this practical.

PBKDF2 — Slowing Down Brute Force

PBKDF2 (Password-Based Key Derivation Function 2) is a standard (RFC 2898) for turning a passphrase into a cryptographic key. It runs the passphrase through HMAC-SHA1 (or similar) 4096 times by default, deliberately consuming CPU. WPA2 uses it to derive the PMK:

PMK = PBKDF2(HMAC-SHA1, passphrase, SSID, 4096 iterations, 256 bits)

This means testing one WPA2 candidate requires 4096 hash operations. A GPU can still test millions of candidates per second, but PBKDF2 limits the speed of brute-force relative to simple MD5 (billions per second). See Cracking WiFi for the full offline-cracking mechanism.


Vulnerability Classification

CVE — Common Vulnerabilities and Exposures

A CVE identifier (e.g., CVE-2021-44228) uniquely names a publicly disclosed vulnerability. Format: CVE-YEAR-NNNNN. Assigned by CVE Numbering Authorities (CNAs), including major vendors, CERT/CC, and MITRE. The NVD (National Vulnerability Database, nvd.nist.gov) is the canonical reference and includes analysis, references, and CVSS scores.

CVSS — Common Vulnerability Scoring System

CVSS is a 0–10 numerical severity rating published alongside each CVE. CVSS v3.1 scores are computed from:

Metric group Examples
Attack Vector Network, Adjacent, Local, Physical
Attack Complexity Low, High
Privileges Required None, Low, High
User Interaction None, Required
Impact Confidentiality, Integrity, Availability (none/low/high each)

General interpretation:

Score Severity
9.0–10.0 Critical
7.0–8.9 High
4.0–6.9 Medium
0.1–3.9 Low

A score of 10.0 means unauthenticated remote exploitation with full system impact. Log4Shell (CVE-2021-44228) scored 10.0.


Binary and Firmware Analysis

Hexadecimal Offsets

In binary analysis, offset means the number of bytes from the beginning of a file or structure. Offsets are almost always expressed in hexadecimal. For example, offset 0x34 = 52 bytes from the start.

# Read 4 bytes starting at offset 0x34 in a binary file
with open("file.bin", "rb") as f:
    f.seek(0x34)
    data = f.read(4)
print(data.hex())

binwalk output shows offsets (Decimal Hexadecimal) because firmware headers at known offsets signal the start of embedded filesystems or compressed images.

ELF Binary Format

ELF (Executable and Linkable Format) is the standard binary format for Linux executables, shared libraries (.so), and object files (.o). Key tools:

Command What it shows
file binary Confirms ELF, architecture (x86-64, ARM, MIPS), endianness
readelf -h binary ELF header: entry point, section count
readelf -S binary Section table: .text (code), .data, .bss, .rodata
objdump -d binary Disassembly of all code sections
strings binary Printable strings embedded in the binary

For firmware analysis, file on an extracted binary quickly tells you the CPU architecture of the embedded device.

Firmware Formats: Squashfs and LZMA

Embedded Linux firmware images are typically packed as layers:

  1. A bootloader (U-Boot) at offset 0
  2. A compressed Linux kernel (often LZMA-compressed)
  3. A read-only root filesystem (often Squashfs)

Squashfs is a compressed, read-only filesystem format designed for embedded devices. It stores the entire filesystem tree in a single file. binwalk -e extracts it; unsquashfs can also unpack it manually.

LZMA is a compression algorithm optimized for high compression ratio at the cost of slower decompression. It is commonly used to compress the Linux kernel image inside firmware.

binwalk recognizes these signatures and reports their offsets. -e extracts; -M recurses into archives found inside other archives.

Linux System Files for Firmware Analysis

When you extract firmware and have the root filesystem, check these files:

File Contains
/etc/passwd User accounts (username, UID, GID, home, shell). The password field is x if hashing is in shadow
/etc/shadow Hashed passwords for each user (requires root; absent on some embedded systems)
/etc/os-release OS name and version string
/etc/hostname Device hostname
/etc/httpd.conf or /etc/nginx/ Web server config — ports, auth, file paths
/usr/bin/, /bin/ Executables; file bin/busybox reveals architecture

Embedded devices often have hardcoded credentials in /etc/passwd or /etc/shadow with simple hashes (MD5 crypt, DES) that crack quickly.


Exploit Development Background

Stack Buffer Overflow

When a C function stores local variables on the call stack, those variables sit adjacent to the return address — the address the CPU will jump to when the function returns. If a function copies user input into a fixed-size local buffer without checking length (e.g., strcpy, gets), writing more bytes than the buffer holds overwrites adjacent memory, including the return address.

 Low address
 ┌─────────────┐
 │  buffer[64] │  ← user input goes here
 ├─────────────┤
 │  saved rbp  │  ← base pointer
 ├─────────────┤
 │ return addr │  ← overwriting this controls execution
 └─────────────┘
 High address (stack grows down)

By placing an attacker-controlled address in the return address slot, code execution is redirected. The cyclic tool (from pwndbg/pwntools) generates a De Bruijn pattern to find the exact offset of the return address.

x86-64 CPU Registers

The x86-64 architecture has 16 general-purpose 64-bit registers. In exploit development, the most relevant:

Register Role
$rip Instruction pointer — address of the next instruction to execute. Controlling $rip = controlling execution
$rsp Stack pointer — address of the top of the stack (grows toward lower addresses)
$rbp Base pointer — used by functions to reference local variables as fixed offsets from a stable point
$rax Return value of function calls; first argument in some calling conventions
$rdi, $rsi, $rdx First three arguments to a function (System V AMD64 ABI)

In pwndbg: info registers or i r shows all register values. $rip is shown after every stop.

De Bruijn Sequences / Cyclic Patterns

A De Bruijn sequence of order n over an alphabet has the property that every possible substring of length n appears exactly once. For exploit development with a binary alphabet (or character set), this means: if you write a De Bruijn pattern into a buffer and then read back whatever value ended up in a register (e.g., $rip after a crash), you can determine the exact byte offset at which the overflow overwrote that register.

# pwntools / pwndbg workflow:
from pwn import cyclic, cyclic_find

pattern = cyclic(200)          # generate 200-byte De Bruijn pattern
# ... trigger the crash, note value in $rip
offset = cyclic_find(0x6161616b)   # 'kaaa' in little-endian → offset 40

In pwndbg: cyclic 200 then cyclic --find $rip after crash.


Protocol Internals

CRLF (Carriage Return + Line Feed)

Network protocols derived from early teletype conventions use a two-byte end-of-line sequence: \r\n (0x0D 0x0A). This includes HTTP, SMTP, FTP, POP3, and IMAP. A single \n (Unix line ending) is technically wrong for these protocols; many servers accept it anyway, but some do not.

In Python:

# Correct HTTP request line ending
request = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"

A blank \r\n alone signals the end of HTTP headers. Forgetting the final \r\n\r\n is a common bug when hand-crafting HTTP requests in socket code.

Format String Vulnerabilities

C’s printf family of functions takes a format string with conversion specifiers (%d, %s, %x, %n). If user input is passed directly as the format string, an attacker can:

// Vulnerable:
printf(user_input);          // if input is "%x %x %x", reads stack values

// Safe:
printf("%s", user_input);    // format string is fixed; user input is data

Boofuzz includes format string sequences in its default fuzz library because many embedded device implementations of printf-like functions are still vulnerable.

DHCP / BOOTP Fields

DHCP (Dynamic Host Configuration Protocol) is built on top of the older BOOTP protocol. BOOTP/DHCP uses a fixed header followed by options. Key fields in a DHCP packet:

Field Size Purpose
op 1 byte 1 = Request (client→server), 2 = Reply (server→client)
htype 1 byte Hardware type (1 = Ethernet)
hlen 1 byte Hardware address length (6 for MAC)
xid 4 bytes Transaction ID — random, matches request to reply
ciaddr 4 bytes Client IP (if already has one)
yiaddr 4 bytes “Your” IP — the address the server is offering
siaddr 4 bytes Server IP
chaddr 16 bytes Client hardware (MAC) address
Options variable Type-length-value: option 53 = DHCP message type, option 51 = lease time

When fuzzing DHCP with scapy or boofuzz, xid must match the request to get a reply. op=1 + htype=1 + hlen=6 + valid chaddr is the minimum to look like a legitimate client.


Fuzzing Concepts

Boofuzz Primitive Functions

Boofuzz uses a domain-specific API to define protocol message fields. Each primitive generates a set of mutated values automatically during fuzzing:

Function Purpose Default mutations
s_string("value") Text field Empty string, long strings, format specifiers, null bytes
s_int(value, format="ascii") Integer field Boundary values (0, -1, MAX_INT, etc.)
s_size("block_name") Auto-computed length of a named block Various size overflows, zero, negative
s_block_start("name") / s_block_end("name") Groups fields into a named block (used with s_size)
s_static(b"\r\n") Fixed bytes, never mutated None
s_bytes(b"\x00", fuzzable=True) Raw bytes field  

s_size is essential for protocols with length-prefixed fields (TLV formats, HTTP Content-Length): it keeps the length field consistent with the actual payload, so the target parses the fuzzed content rather than rejecting it at the length check.


Python Idioms

List Comprehensions

A list comprehension builds a new list in one expression, replacing a for loop:

# Equivalent forms:
squares = []
for x in range(10):
    squares.append(x ** 2)

squares = [x ** 2 for x in range(10)]         # with transform
evens   = [x for x in range(10) if x % 2 == 0]  # with filter

In scapy and dpkt scripts, list comprehensions are common for filtering packets:

syn_packets = [p for p in packets if p.haslayer(TCP) and p[TCP].flags == "S"]

Lambda Functions

A lambda is an anonymous function defined inline. Equivalent to a named def for simple single-expression functions:

double = lambda x: x * 2
double(5)   # 10

# Common use: sort or filter with a key
packets.sort(key=lambda p: p.time)

Generator Expressions

Like list comprehensions but lazy — they compute values one at a time without building the full list in memory. Useful for large pcap files:

# This reads the entire file into memory:
payloads = [bytes(p[TCP].payload) for p in PcapReader("big.pcap")]

# This processes one packet at a time:
payloads = (bytes(p[TCP].payload) for p in PcapReader("big.pcap"))
for payload in payloads:
    ...

Protocol Vulnerability Context

IPv6 Routing Header Type 0 (RH0)

IPv6 Routing Headers allow a source to specify a list of intermediate nodes a packet should visit. Type 0 (RH0) listed up to 127 intermediate addresses and was designed for source routing. It was deprecated by RFC 5095 (2007) because it could be abused to:

Modern OS kernels and routers drop RH0 packets by default. Embedded TCP/IP stacks (like the Treck stack involved in Ripple20) sometimes still process them, or mishandle the header parsing — leading to heap overflows (CVE-2020-11897, CVSS 10.0).

Ripple20

Ripple20 is a set of 19 vulnerabilities (2020) in the Treck TCP/IP stack, a lightweight stack used in medical devices, industrial controllers, printers, and power grid equipment. The name comes from the cascading supply-chain effect: Treck is embedded in components from multiple vendors, which are in turn embedded in products from hundreds of manufacturers — the “ripple” of one vulnerable library across an entire industry.

The critical vulnerabilities (CVSS 10.0) include an out-of-bounds write via malformed IPv4 tunneling options and the RH0 heap overflow mentioned above. Both allow unauthenticated remote code execution. The lesson: embedded TCP/IP stacks are a long-lived, hard-to-patch supply-chain risk.