Hands-on security exercise / source reading
Capture traffic you generated
Read the supplied instructions here, then download the complete project to use the Python utilities and training materials. The tool workflow requires the separate software and controlled environment described below. These are guided practice materials; reference checks do not assess independent understanding.
Archive folder: jeremy-bryant-pages/labs/traffic-capture/
Lab instructions
labs/traffic-capture/README.md
# Capture traffic you generated Run a small HTTP service on your own computer, capture its requests in Wireshark, and explain the difference between a successful response, HTTP 404 and a failed connection. This is an operational exercise: the script makes real loopback traffic, and you operate Wireshark. It does not generate a capture file or claim that you captured anything. Allow 35-50 minutes. You need Python 3.10+, a terminal and an existing Wireshark installation with permission to capture loopback traffic. On Windows, loopback capture requires Npcap. On Linux, capture permissions must already be configured. If the interface is missing or access is denied, record that limitation and ask the owner of the computer to arrange setup. No installation, firewall changes or VM changes are part of this lab. No programming is required. The service binds only to `127.0.0.1`. It serves fixed text, never local files. The client has no destination option and uses no proxy. A second socket reserves a local port without listening, giving the failed connection its own target. Both sockets close at completion or interruption. This is a temporary teaching service, not a service to leave running. ## Maintained entry point Open a terminal in this folder. On Windows use `python`; on Linux use `python3` if that is your Python 3 command. Substitute it consistently below. ```text python lab.py --help python lab.py cases python lab.py run --scenario guided --out run/guided-01 ``` Each run needs a fresh direct child of this folder's `run/`. Existing folders, linked paths and path traversal are refused. Names use lowercase letters, digits, hyphens or underscores. Outputs include `setup.json`, a blank `worksheet.txt`, and, after traffic runs, `client-results.json` and `server-log.json`. The setup records the generator's SHA-256 for traceability. These files stay ignored by version control. Ports and packet timing vary; request labels, order and content are fixed for each scenario. Exit codes are `0` for completed traffic generation, `2` for an input/runtime error and `130` for interruption. No exit code awards learner completion. `--no-wait` skips the capture pause for maintenance checks; it does not capture. ## Guided capture: Windows or Linux 1. Run the command above. Leave the terminal at its prompt. Record the **HTTP port** and **non-listening port**; the example letters `P` and `Q` below mean these printed numbers, not literal filter text. 2. Open Wireshark and choose **Capture > Options**. On Windows select only **Adapter for loopback traffic capture**. On Linux select only **lo**. Do not select Wi-Fi, Ethernet or an all-interface capture. Wireshark's [loopback guide](https://wiki.wireshark.org/captureSetup/loopback) explains why traffic sent to the local machine uses a different capture interface. 3. Copy the complete printed capture filter into that interface's capture filter box. It has this form: `host 127.0.0.1 and tcp and (port P or port Q)`. Click **Start**. Capture filters select what is recorded; packets excluded now cannot be recovered by changing a display filter later. See the [capture filter guide](https://www.wireshark.org/docs/wsug_html_chunked/ChCapCaptureFilterSection.html). 4. Return to the terminal and press Enter. Wait for its summary, then stop the Wireshark capture with the red square. Use **File > Save As** to save all captured packets as `capture.pcapng` inside this run folder. This is your actual capture, separate from the script's application logs. 5. In the display filter bar, paste `display_filter` from `setup.json`. It uses different syntax: `ip.addr == 127.0.0.1 && (tcp.port == P || tcp.port == Q)`. If HTTP is not recognised on the changing port, select a packet to port P, use **Analyze > Decode As**, set that TCP port's current protocol to **HTTP** and apply. This is a decoding choice for this session, described in the [protocol dissection guide](https://www.wireshark.org/docs/wsug_html_chunked/ChCustProtocolDissectionSection.html). 6. Try `http.request`, `http.response.code == 200`, and `http.response.code == 404` separately. Select a request and use **Follow > TCP Stream**. Find its `X-Lab-Id` label, request path and response. Record actual frame numbers and stream numbers; these are not predetermined. 7. Clear the HTTP filter. Use `tcp.port == Q` with your Q value, then `tcp.flags.reset == 1` to examine resets. Compare this evidence with L4's client result. A refusal normally produces a reset; a local policy may instead cause a timeout. Record what you observed. An HTTP-only display filter would hide this failed connection. The [display filter guide](https://www.wireshark.org/docs/wsug_html_chunked/ChWorkBuildDisplayFilterSection.html) describes field and value matching. ## Interpret the evidence | Label | Guided request | Question | | --- | --- | --- | | L1 | `GET /hello` | Did TCP connect, and what HTTP response followed? | | L2 | `GET /missing` | What proves the server was reachable despite HTTP 404? | | L3 | `GET /marker`, harmless `ORCHARD-CANARY-42` header | Where can you see the marker in clear text? | | L4 | connection to the owned non-listening port | Was any HTTP response possible? | **Vocabulary:** loopback means this machine; a port identifies a local endpoint; TCP provides a connection; HTTP provides application requests and responses; a reset rejects or terminates a TCP connection; a capture filter limits recorded packets; a display filter limits visible packets. Finish the worksheet with your capture, filter, request/response frame pairs, the L4 result and a short explanation. Keep the worked example closed until you have made a prediction. Continue with [drills](DRILLS.md). Troubleshoot an empty capture by checking the selected interface, the printed ports and whether capture started before Enter. Use a new run for a retry. Do not infer firewall blocking from silence alone. Packet counts, source ports, retries, checksums reported by capture tools and timestamps can differ between systems. There is no TLS, routing, DNS lookup or external network here. A 200 response is a response from this toy service, not proof that a real business operation succeeded. A 404 is an application result, not a network outage. The fixtures and text are original fictional practice materials. No university questions or live incident evidence are included. Maintainer tests validate the toy service and boundaries; packet capture operation and learner understanding still require actual evidence. Handover prompt: **Show one successful exchange, one HTTP error and one failed connection. What did each layer establish, and what would you check next?**
Worked example
labs/traffic-capture/WORKED-EXAMPLE.md
# Worked reasoning: guided traffic This is an explanation of the intended exercise. It is not a saved capture or a claim that Wireshark was operated. Supply frame numbers from your own run. L1 requests `/hello`. The toy service returns HTTP 200 and fixed text. In a capture started in time, look for the TCP handshake, the request containing `X-Lab-Id: L1`, and the response in the same TCP stream. The request and response provide application evidence beyond a completed TCP handshake. L2 requests `/missing`. It receives HTTP 404 because the toy service does not implement that path. The HTTP response itself shows that the client reached an HTTP server. Calling this a connection failure would confuse two different layers. Pair the actual request and response before attributing the 404 to L2. L3 requests `/marker` and includes `X-Lab-Marker: ORCHARD-CANARY-42`. This is a harmless label, not an exploit or secret. It is visible because this lab uses clear-text HTTP. A marker can identify test traffic without making that traffic malicious. L4 attempts to connect to another socket owned by the script, bound but never put into a listening state. The normal outcome is connection refused. The application creates no HTTP request on this connection, because it cannot finish connecting. Inspect the SYN/reset exchange if captured. If your result is a timeout, state that and investigate capture and local policy; do not invent a reset. Application logs alone do not prove which packets Wireshark saved. An example finding, completed with your evidence, is: "L2 reached the HTTP service: request frame ___ and response frame ___ share TCP stream ___. The server returned 404 for `/missing`. L4 had no HTTP response; client output says ___ and frames ___ show ___. These are different failure types." For the changed run, `/hello?note=missing` is still a supported path and returns 200. `/missing?note=hello` is still absent and returns 404. The query's wording does not determine the route. L3's marker changes letter case; that matters for a later case-sensitive rule, even though the HTTP service still returns 200. Do not copy fixed frame numbers, claim that a file was captured from synthetic logs, or infer compromise from the marker. A useful next check depends on the layer that failed: application routing for the 404, endpoint listening state for the failed connection, and capture setup when packet evidence is absent.
Practice drills
labs/traffic-capture/DRILLS.md
# Practice stages 1. **Guided.** Follow the README and fill in actual frame references. Explain L2 before opening the worked example. Save your capture and worksheet. 2. **Prompts only.** Use a new run, `run/prompts-01`. Keep only this checklist: loopback interface; current ports; capture before Enter; decode HTTP if needed; match requests to responses; inspect L4 without an HTTP filter. 3. **Independent.** Run `python lab.py run --scenario independent --out run/independent-01` on one line. Keep the full guide closed. Produce the three outcome explanations with frame references and identify help you used. 4. **Changed input.** Run `python lab.py run --scenario changed --out run/changed-01` on one line. Predict whether the query words change the HTTP outcomes. Compare L3's exact header bytes with the guided capture. 5. **Teach-back.** Explain to a beginner why "404 means the server is down" is unsupported. Demonstrate how `http` hides L4. Explain why you chose loopback rather than a physical network interface. 6. **Later recall.** After two days, write the difference between capture and display filters from memory, then check it. After a week, repeat a fresh capture and explain one unexpected observation without copying old frames. Success means you can operate the tool, trace evidence to a claim and explain the limits on an unfamiliar run. Finishing a command is not automatic mastery. If capture is unavailable, label your work "traffic generation only; capture pending" and keep that distinction in any portfolio description.