TheOneChasingSomething/Mitm_TLS_CTF_Lab
GitHub: TheOneChasingSomething/Mitm_TLS_CTF_Lab
以 11 个 CTF 挑战为核心、覆盖 TLS 安全全链路的 HTTPS 传输安全实验靶场,帮助学习者在可控环境中将理论保证与实现漏洞逐一对应。
Stars: 0 | Forks: 0
# "HTTPS Security" lab — TLS challenge laboratory
**Context**: a hands-on lab on HTTPS transport security, structured as eleven
*capture-the-flag* challenges. Two **warm-up** challenges (OpenSSL, Scapy) equip
the learner, one **cleartext interception** challenge (MITM HTTP) establishes the
network-attacker posture, then eight challenges defeat, in a controlled way, a
distinct property of TLS security — so the learner experimentally rebuilds the
link between *theoretical guarantee* and *implementation condition*.
## 1. Learning objectives
By the end of the lab, the learner should be able to:
1. **operate the basic tooling**: build, inspect and verify an X.509 certificate
by hand with OpenSSL (ASN.1 walk); sniff, dissect, craft and send packets with
Scapy [18];
2. distinguish the three guarantees of a TLS channel — **confidentiality**,
**integrity**, **peer authentication** — and show they are *separable* (a
channel may encrypt without authenticating; a channel may offer no guarantee
at all if there is no TLS) [5, 8];
3. tie each vulnerability to the faulty layer: identity (PKI), secret management,
**forward secrecy** (absent or *imperfect*), protocol negotiation, or
implementation;
4. take up a **man-in-the-middle** position (ARP poisoning, RFC 826 [15]) and
wield public tooling (bettercap, mitmproxy, `openssl s_client`,
Wireshark/tshark, `nmap --script ssl-*`, `testssl.sh`);
5. state, for each attack, the corresponding **normative countermeasure** (RFC
5280 validation, ECDHE/PFS ephemeral exchanges, DH groups ≥ 2048 bits, HSTS
RFC 6797, `TLS_FALLBACK_SCSV` RFC 7507, 1/n-1 splitting and explicit IV
RFC 4346, OpenSSL upgrade) [4, 6, 9, 17, 19].
## 2. Threat model and architecture
The chosen model is the **active network attacker** (Dolev–Yao) placed between a
victim-client and a server: it can read, rewrite, replay and inject packets, but
holds *a priori* no cryptographic secret. Challenges C6 and C7 enrich this model:
C6 adds **deferred compromise** (record now, obtain the key later); C7 (Logjam)
adds the **active downgrade** of an ephemeral exchange to a group so weak that
computing the discrete logarithm becomes feasible after an **amortized
precomputation** on the shared prime [8, 19].
Structuring design principle: **the application portal is never broken at the
application level**. The vulnerability always lies in the *transport* layer placed
in front of it (TLS termination by nginx/apache/openssl), or in its absence (MITM
HTTP). This separation isolates the variable under study and avoids conflating a
web flaw (out of scope) with a TLS flaw (the subject of the lab).
Isolated lab network (172.28.0.0/16)
┌───────────────┐ MITM ┌────────────────────────────┐
│ victim-client │◄────attacker──────►│ target Cx: TLS front-end │
│ (careless) │ │ VULNERABLE → portal │
└───────┬───────┘ └──────────────┬─────────────┘
│ armed with (dest IP) │ cleartext proxy
└─────────────── Flask portal ────────────┘
(encrypted flag feed · start · verify)
Components (see `docker-compose.yml`):
| Role | Container | Function |
|------|-----------|----------|
| Portal | `portal` | Serves the encrypted flag, arms the victim-client, verifies flags |
| Victim | `victim-client` | Emits the careless traffic to be intercepted |
| Targets | `c1`…`c11` | Vulnerable front-ends (or Scapy beacon), one per challenge |
The portal refuses any destination IP outside `LAB_CIDR`: it cannot be diverted
into a generic attack launcher (validation in `app/app.py`). The warm-ups (C1
OpenSSL, C2 Scapy) are *direct* interactions with the target and do not involve
the victim-client.
## 3. Challenge → defeated layer map
| # | Challenge | Layer / skill | Guarantee voided | Ref. |
|---|-----------|---------------|------------------|------|
| 1 | OpenSSL warm-up | X.509 tooling (ASN.1) | — (training) | [4] |
| 2 | Scapy warm-up | Network tooling (sniff/craft) | — (training) | [15, 18] |
| 3 | MITM against HTTP | No encrypted transport | Confidentiality (total) | [15] |
| 4 | Self-signed cert + MITM | PKI identity | Authentication | [4] |
| 5 | Private-key leak | Secret management (app-layer RSA-OAEP) | Persistent confidentiality | — |
| 6 | No forward secrecy | RSA key exchange (no ephemeral) | *Retroactive* confidentiality | [5, 8] |
| 7 | Logjam (export DHE) | 512-bit DH group + downgrade | Confidentiality (*imperfect* FS) | [19, 20] |
| 8 | SSL stripping | Transport policy | Confidentiality (via downgrade) | [6, 7] |
| 9 | POODLE (SSLv3/CBC) | Negotiation + CBC mode | Confidentiality | [9, 10] |
| 10 | BEAST (TLS 1.0/CBC) | Predictable IV (chained CBC) | Confidentiality (chosen-plaintext) | [13, 14, 16] |
| 11 | Heartbleed | Implementation (RFC 6520) | Confidentiality (memory) | [3, 11] |
## 4. Building the images (Packer)
Two routes, at the instructor's discretion:
**(a) Packer → Docker** — the portal image built by immutable *provisioning*
(`packer/portal.pkr.hcl`). This "immutable image" approach [1, 2] guarantees
bit-for-bit reproducibility independent of a local `docker build`:
cd packer && packer init . && packer build -only='docker.*' .
**(b) Packer → QEMU** — baking a **self-contained VM** carrying the whole lab
(`packer/lab-vm.pkr.hcl`). The ideal classroom deliverable: a single `qcow2`
handed to each student, with no runtime network dependency (guaranteed
isolation):
cd packer && packer init . && packer build -only='qemu.*' .
# → output-lab-vm/tls-lab.qcow2
## 5. Deploying the lab
The lab deploys in **three ways**, depending on context:
| Mode | Tool | Topology | Where |
|------|------|----------|-------|
| **Local** (single host) | Packer + Compose | everything on one machine (or a `qcow2` VM) | below + `packer/` |
| **Classroom** (fleet) | Ansible (+ Packer) | portal on the teacher, targets+victim on each workstation | `ansible/` (`site.yml`) |
| **Centralized anti-cheat** | Ansible (+ Packer) | everything on the teacher server, one isolated instance per student, confined SSH access | `ansible/` (`centralized.yml`) |
In **classroom** mode (mode 2), the portal — the site that receives and verifies
flags — is centralized on the teacher machine; each workstation hosts only the
targets and the victim-client, which proxy to that portal (`portal → TEACHER_IP`
via `extra_hosts`). The victim runs in *standalone* mode. Deploy:
`cd ansible && ansible-playbook site.yml`.
In **centralized anti-cheat** mode (mode 3), **everything** runs on the teacher
server, as **one isolated instance per student** (portal + targets + victim +
attacker, on a dedicated, hermetic `/24` network). The student has **no
Docker/host access**: they connect via **SSH** (`ForceCommand`) into their single
attacker container, and the **C2–C11 flags are unique per student** — impossible
to extract a flag from an image or share it. Deploy: `cd ansible && ansible-playbook
centralized.yml` (see `ansible/README.md`).
### Local mode
make up # docker compose build && up -d
# Targets: 8451(C1) · 8453(C3) · 8441(C4) · 8442(C5) · 8447(C6) · 8448(C7)
# 8006/8443(C8) · 8444(C9) · 8446(C10) · 8445(C11).
# C2 = internal Scapy beacon (UDP/8452).
### "Debug" option — observation proxy
A Compose override inserts an **inspection proxy** (mitmproxy/mitmweb) through
which **all victim-client traffic** flows. Since the victim already accepts any
certificate, mitmproxy **decrypts** the victim↔target TLS sessions and shows every
exchange in the clear (flag feed, RSA-OAEP blob, leaked key, POODLE/BEAST/Logjam
cookies, Heartbleed page…) — handy to check that a challenge really delivers its
flag, or for a demonstration.
make debug # = docker compose -f docker-compose.yml -f docker-compose.debug.yml up -d
# → inspection UI: http://localhost:8081
make debug-down
For total isolation, flip `internal: true` on the `lab` network in
`docker-compose.yml`. The attack host joins the `lab` network (or you
`docker compose exec` a tooled container): Scapy sees the C2 beacon there and can
ARP-poison there.
## 6. Detailed walkthrough per challenge
Each section follows the same template: *context → exploitation chain → normative
countermeasure*. The complete solutions (public tools **and** Scapy) are in
`SOLUTIONS.md`.
### C1 — OpenSSL warm-up (10 pts)
- **Goal**: retrieve the target's self-signed certificate (`openssl s_client`),
inspect it (`openssl x509 -text`), then **verify its signature by hand**
(`asn1parse` walk, BIT STRING extraction, `rsautl -verify`, comparison to the
TBSCertificate digest). The flag is embedded in the certificate's *OU* field.
- **Teaching**: manually unfold what `openssl verify` automates; understand the
ASN.1 structure and the signature ↔ body link (RFC 5280 [4]).
### C2 — Scapy warm-up (10 pts)
- **Goal**: sniff the UDP/8452 beacon (`sniff(filter="udp port 8452")`), read the
instruction, **craft** the magic datagram and **send** it (`sr1`); the target
then replies with the flag.
- **Teaching**: the three Scapy gestures — sniff, layer dissection,
craft/send — the foundation of the following MITM challenges [18].
### C3 — MITM against cleartext HTTP (20 pts)
- **Transport**: cleartext HTTP (port 8453), **no TLS**.
- **Exploitation**: ARP poisoning (`arp_spoof.py` or bettercap) between victim and
target, then sniffing (`sniff_http_flag.py` / tcpdump); the flag travels in the
clear.
- **Teaching**: without transport encryption, confidentiality is nil; active
interception (RFC 826 [15]) is enough.
- **Countermeasure**: mandatory HTTPS + permanent redirect + HSTS (see C8).
### C4 — Self-signed certificate & MITM (15 pts)
- **Transport**: TLS 1.2, self-signed certificate, *not validated by the client*.
- **Exploitation**: ARP-spoof the victim-client; transparent interception
(`bettercap`/`mitmproxy`); the attacker presents their own self-signed
certificate, which the victim accepts (validation disabled), and reads the flag.
- **Teaching**: encryption without **peer authentication** offers no protection
against a MITM; trust rests on validating the certificate chain [4].
- **Countermeasure**: strict RFC 5280 validation (chain, SAN, revocation);
pinning where appropriate.
### C5 — Private-key leak (20 pts)
- **Transport**: healthy TLS, but the portal's RSA private key is exposed under
`/.well-known/backup/server.key`. The flag is published **RSA-OAEP**-encrypted
by `/c/5/flag-feed`.
- **Exploitation**:
curl -k https://TARGET:8442/.well-known/backup/server.key -o server.key
curl -k https://TARGET:8442/c/5/flag-feed | jq -r .ciphertext_b64 | base64 -d > flag.bin
openssl pkeyutl -decrypt -inkey server.key \
-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -in flag.bin
- **Teaching**: compromising a long-term key voids the confidentiality of
everything it protects. Here the protection is *application-level* (a blob); C6
shows the same logic at the *transport* level.
- **Countermeasure**: compartmentalize secrets, restrictive permissions,
rotation, no secret under a served directory tree.
### C6 — No forward secrecy / RSA key exchange (25 pts)
- **Transport**: TLS 1.2 negotiating an **RSA key exchange** (`kRSA` suites like
`TLS_RSA_WITH_AES_128_CBC_SHA`; no ECDHE/DHE). The pre-master secret is
encrypted under the server's RSA public key and carried in the
ClientKeyExchange. The server's private key is exposed under
`/.well-known/backup/server.key`.
- **Exploitation** (*after-the-fact* decryption):
1. **record** the victim's TLS traffic: `tcpdump -i eth0 -w cap.pcap
'host TARGET and port 8447'` (from a MITM position if needed, cf.
`arp_spoof.py`);
2. **leak** the key: `curl -k
https://TARGET:8447/.well-known/backup/server.key -o server.key`;
3. **decrypt** offline: Wireshark → *Preferences ▸ Protocols ▸ TLS ▸ RSA keys
list* (add `server.key`), or
`tshark -r cap.pcap -o "tls.keys_list:TARGET,8447,http,server.key" -Y http`.
The flag appears in the clear in the decrypted HTTP response.
- **Teaching**: without an ephemeral, the long-term key is enough to recompute
*all* captured past sessions. **Forward secrecy** (ECDHE) breaks this link: each
session derives from an ephemeral secret destroyed after use, which no later
leak of the long-term key can reconstruct [5, 8].
- **Countermeasure**: enforce **ECDHE** suites (forward secrecy); in TLS 1.3
static RSA key exchange is simply removed.
### C7 — Logjam / export DHE (25 pts)
- **Transport**: TLS 1.2 accepting **EXPORT-grade DHE** suites — a **512-bit**
Diffie-Hellman group (`EXP-EDH-RSA-DES-CBC-SHA`). No protection against
*downgrade*. The flag is carried by the `SESSIONFLAG` cookie.
- **Exploitation**:
1. **detect**: `testssl.sh --logjam TARGET:8448`, `nmap --script
ssl-dh-params -p 8448 TARGET`, or `openssl s_client -connect TARGET:8448
-cipher EXP` (a 512-bit session establishes);
2. from a **MITM** position, force the ClientHello downgrade to the DHE_EXPORT
suite (the server answers with its 512-bit group);
3. **break** the 512-bit group's discrete logarithm — costly once, but
**amortized** because the same prime is shared by countless servers
(precomputation), yielding the ephemeral secret then decryption of the
session and reading of the cookie [19, 20].
- **Teaching**: an *ephemeral* exchange only ensures forward secrecy if the group
is **robust**. An export group (512 bits), or even a shared 1024-bit group, is
within reach of a precomputation (Logjam): FS becomes *imperfect*. This is the
"DH" counterpart of C6's "RSA".
- **Countermeasure**: disable all EXPORT suites; enforce DH groups
**≥ 2048 bits** (or unique per server); prefer ECDHE. On the client, reject DHE
groups < 1024 bits (the browsers' Logjam fix) [19].
### C8 — SSL stripping (20 pts)
- **Transport**: service reachable in the clear (port 80), **no HSTS**, hardcoded
`http://` link.
- **Exploitation**: MITM + HTTPS→HTTP downgrade (`bettercap` caplet `hstshijack`,
or `sslstrip2`); the flag then travels in the clear and is captured.
- **Teaching**: Marlinspike's attack [7] exploits the cleartext *bootstrap*. The
fix is to make HTTPS **mandatory and remembered** on the client side.
- **Countermeasure**: `Strict-Transport-Security` (HSTS, RFC 6797) with
`includeSubDomains` and listing on the *preload list* [6].
### C9 — POODLE / SSL 3.0 (25 pts)
- **Transport**: SSL 3.0 accepted, **CBC** suites, `TLS_FALLBACK_SCSV` absent →
forced fallback possible. The flag is carried by the `SESSIONFLAG` cookie.
- **Exploitation**: force the SSLv3 fallback (`openssl s_client -ssl3`); from a
MITM position, exploit SSL 3.0's **CBC padding oracle** to reconstruct the
cookie byte by byte [9, 10].
- **Teaching**: SSL 3.0 does not specify the CBC padding content, making its
verification exploitable as an oracle. An obsolete protocol stays dangerous as
long as a downgrade is possible.
- **Countermeasure**: disable SSL 3.0; enforce `TLS_FALLBACK_SCSV` (RFC 7507)
against downgrades [9].
### C10 — BEAST / TLS 1.0 CBC (25 pts)
- **Transport**: TLS 1.0 only, **CBC** suites. In TLS 1.0, a record's IV is the
previous record's last ciphertext block: it is **predictable**. The flag is
carried by the `SESSIONFLAG` cookie.
- **Exploitation**: confirm (`openssl s_client -tls1`, `testssl.sh`,
`nmap --script ssl-enum-ciphers`); from a MITM position (ARP poisoning,
`arp_spoof.py`), mount the **adaptive chosen-plaintext** attack (blockwise
chosen-boundary) that aligns the block boundary and guesses the cookie byte by
byte [13, 14, 16].
- **Teaching**: a predictable IV turns CBC encryption into a chosen-plaintext
oracle. This is a **protocol-design** weakness (TLS 1.0), distinct from POODLE's
*padding* oracle.
- **Countermeasure**: ban TLS 1.0; failing that, **1/n-1 record splitting** or
AEAD suites (AES-GCM). TLS 1.1+ structurally closes BEAST with an explicit
per-record IV (RFC 4346 [17]).
### C11 — Heartbleed / OpenSSL 1.0.1f (20 pts)
- **Transport**: OpenSSL 1.0.1f, **Heartbeat** extension (RFC 6520) with no check
of the announced length. The flag resides in the process memory.
- **Exploitation**:
nmap -p 8445 --script ssl-heartbleed TARGET # detection
# then RFC 6520 PoC: Heartbeat request with an oversized payload_length
# → out-of-bounds read up to 64 KB, where the flag sits.
- **Teaching**: a single unchecked length exposes arbitrary memory blocks (keys,
cookies, data) — the canonical illustration of an implementation vulnerability,
distinct from a protocol weakness [3, 11].
- **Countermeasure**: upgrade OpenSSL ≥ 1.0.1g; regenerate potentially exposed
secrets.
## 7. Scoring
| Challenge | Points | Skill assessed |
|-----------|:------:|----------------|
| C1 OpenSSL warm-up | 10 | X.509 / ASN.1 manipulation |
| C2 Scapy warm-up | 10 | Sniff / craft / send |
| C3 MITM HTTP | 20 | Active interception (ARP) |
| C4 Self-signed cert | 15 | PKI validation |
| C5 Key leak | 20 | Secret management (app-level) |
| C6 Forward secrecy (RSA exchange) | 25 | After-the-fact decryption / PFS |
| C7 Logjam (export DHE) | 25 | DH downgrade + precomputed discrete log |
| C8 SSL stripping | 20 | MITM defense / HSTS |
| C9 POODLE | 25 | CBC oracle / obsolescence |
| C10 BEAST | 25 | Predictable IV / chosen-plaintext |
| C11 Heartbleed | 20 | Memory disclosure |
| **Total** | **215** | |
## 8. Precautions, ethics and isolation
1. **Absolute isolation**: non-routable network; `internal: true` recommended.
2. **Scope**: the portal only arms the victim-client toward private IPs in
`LAB_CIDR` — no attack outside the lab is possible from the app.
3. **Network capabilities**: the Scapy target (C2) and the attack hosts require
`NET_RAW`/`NET_ADMIN`; grant them only within the isolated network.
4. **Legal framing**: controlled environment, documented pedagogical consent;
interception techniques are lawful only on infrastructure you control.
5. **Life cycle**: destroy the vulnerable instances after the lab (`make clean`);
keep "clean" snapshots.
6. **Debrief**: each challenge ends with the statement of its countermeasure.
### Reproducibility caveats (obsolete protocols)
Legacy protocols are progressively removed from recent stacks:
- **C6 (RSA exchange)**: `kRSA` suites are deprecated; re-enabled via
`@SECLEVEL=1` in `ssl_ciphers`. Wireshark decrypts traffic with the private key
**only** for the RSA exchange (impossible with ECDHE) — which is precisely the
teaching point.
- **C7 (Logjam)**: **EXPORT** suites were removed from OpenSSL ≥ 1.0.2g. The
target is therefore built on `ubuntu:14.04` (OpenSSL 1.0.1f, which still ships
them). The **512-bit discrete-log break** is not run in class: it relies on a
precomputation/PoC for the known group (that is the *whole* logic of Logjam —
the precomputation is amortized). The gradable exercise is **detection** and
**demonstrating the downgrade**; full decryption is provided turnkey by the
instructor.
- **C9 (SSLv3)**: pinned `httpd:2.4.29` image.
- **C10 (TLS 1.0)**: re-enabled via `targets/beast/openssl-lab.cnf` (`MinProtocol=
TLSv1`, `@SECLEVEL=0`). A legacy base otherwise.
- **C11 (Heartbleed)**: OpenSSL 1.0.1f compiled from the official archive.
These targets were **not** built/run in the preparation environment (network
disabled): validate the `docker build` on a tooled host before the session.
## 9. Reproducibility and anti-cheat
Flags are loaded from the environment (`FLAG_C1`…`FLAG_C11`), propagated
consistently to the portal **and** the corresponding target via `docker-compose`.
To generate a unique instance per cohort or per student, set a `.env` then
`docker compose up -d --build --force-recreate`. Verification is zero-disclosure
(constant-time comparison on a SHA-256 digest, cf. `challenges.py`).
## 10. References
[1] K. Morris, *Infrastructure as Code*, 2nd ed., O'Reilly, 2020.
[2] HashiCorp, *Packer Documentation — Immutable Machine Images*, docs.packer.io.
[3] R. Seggelmann, M. Tuexen, M. Williams, "Transport Layer Security (TLS) and
Datagram TLS (DTLS) Heartbeat Extension", **RFC 6520**, IETF, 2012.
[4] D. Cooper *et al.*, "Internet X.509 Public Key Infrastructure Certificate
and CRL Profile", **RFC 5280**, IETF, 2008.
[5] T. Dierks, E. Rescorla, "The TLS Protocol Version 1.2", **RFC 5246**, 2008.
[6] J. Hodges, C. Jackson, A. Barth, "HTTP Strict Transport Security (HSTS)",
**RFC 6797**, IETF, 2012.
[7] M. Marlinspike, "New Tricks for Defeating SSL in Practice", *Black Hat DC*,
2009.
[8] E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.3",
**RFC 8446**, IETF, 2018.
[9] B. Möller, A. Langley, "TLS Fallback Signaling Cipher Suite Value (SCSV) for
Preventing Protocol Downgrade Attacks", **RFC 7507**, IETF, 2015.
[10] B. Möller, T. Duong, K. Kotowicz, "This POODLE Bites: Exploiting the SSL
3.0 Fallback", Google, 2014. (CVE-2014-3566)
[11] MITRE, "CVE-2014-0160 (Heartbleed)", *Common Vulnerabilities and
Exposures*, 2014.
[12] A. Freier, P. Karlton, P. Kocher, "The Secure Sockets Layer (SSL) Protocol
Version 3.0", **RFC 6101** (Historic), IETF, 2011.
[13] T. Duong, J. Rizzo, "Here Come The ⊕ Ninjas" (BEAST), 2011.
[14] MITRE, "CVE-2011-3389" (SSL/TLS 1.0 CBC — BEAST), 2011.
[15] D. Plummer, "An Ethernet Address Resolution Protocol", **RFC 826**, IETF,
1982.
[16] G. Bard, "A Challenging but Feasible Blockwise-Adaptive Chosen-Plaintext
Attack on SSL", *SECRYPT*, 2006.
[17] T. Dierks, E. Rescorla, "The TLS Protocol Version 1.1", **RFC 4346**, 2006.
[18] P. Biondi *et al.*, *Scapy Documentation*, scapy.readthedocs.io.
[19] D. Adrian *et al.*, "Imperfect Forward Secrecy: How Diffie-Hellman Fails in
Practice" (Logjam), *ACM CCS*, 2015.
[20] MITRE, "CVE-2015-4000 (Logjam)", *Common Vulnerabilities and Exposures*,
2015.
## Appendix A — Flashcards (active recall)
1. **Q:** What does verifying a certificate signature *by hand* reveal compared to
`openssl verify`?
**A:** The concrete signature↔body link: ASN.1 walk, BIT STRING extraction,
public RSA decryption, comparison to the TBSCertificate digest (C1).
2. **Q:** What are the three fundamental Scapy gestures?
**A:** Sniff (`sniff`/BPF filter), dissect (`pkt[layer]`), craft & send
(`IP()/UDP()/Raw()`, `sr1`) (C2).
3. **Q:** Why does cleartext HTTP offer no confidentiality against a MITM?
**A:** Without transport encryption, ARP poisoning (RFC 826) is enough to read
all traffic (C3).
4. **Q:** What are the three guarantees of a TLS channel, and which one does an
unvalidated self-signed certificate void?
**A:** Confidentiality, integrity, peer authentication; authentication falls
(C4).
5. **Q:** What is the difference between the C5 key leak and the C6 one?
**A:** C5 decrypts an *application* blob (RSA-OAEP) directly; C6 decrypts a
**recorded** TLS session *after the fact* because RSA exchange offers no
forward secrecy.
6. **Q:** Why does RSA exchange (C6) allow retroactive decryption, and what
prevents it?
**A:** The pre-master secret is encrypted under the server's long-term key; a
later leak recomputes it. The **ECDHE** ephemeral destroys the secret after use
→ no leak reconstructs it (C6).
7. **Q:** How does Logjam (C7) differ from C6 even though DHE is *ephemeral*?
**A:** The ephemeral exists but the DH group is downgraded to 512 bits; its
discrete log is precomputable (amortized over the shared prime) → *imperfect*
forward secrecy. Fix: DH ≥ 2048 bits / ECDHE, and no EXPORT (C7).
8. **Q:** Why is precomputation central to Logjam?
**A:** The (high) discrete-log cost on a given prime is paid *once*, then
reused against every server sharing that prime (C7).
9. **Q:** Which header, and which complementary mechanism, neutralize SSL
stripping?
**A:** `Strict-Transport-Security` (HSTS, RFC 6797) + listing on the *preload
list* to cover the very first visit (C8).
10. **Q:** Which property of SSL 3.0's CBC padding does POODLE rely on, and what
prevents it?
**A:** The padding content is unspecified → an oracle exploitable byte by
byte; `TLS_FALLBACK_SCSV` (RFC 7507) blocks the downgrade (C9).
11. **Q:** What makes the IV predictable in TLS 1.0 (BEAST), and what closes the
flaw?
**A:** A record's IV is the previous record's last ciphertext block; TLS 1.1
mandates an explicit per-record IV, or apply 1/n-1 splitting (C10).
12. **Q:** Is Heartbleed a protocol or an implementation flaw?
**A:** Implementation (OpenSSL): the Heartbeat payload length (RFC 6520) is
unchecked → out-of-bounds read up to 64 KB (C11).
13. **Q:** Three distinct ways to lose the confidentiality of a key exchange —
name them via C6, C7 and the common remedy.
**A:** No ephemeral (RSA, C6); ephemeral too weak/downgraded (DH 512, Logjam
C7); common remedy: robust ephemerals (ECDHE or DH ≥ 2048 bits).
## Appendix B — Acronym glossary
| Acronym | Expansion | Explanation |
|---------|-----------|-------------|
| **TLS** | *Transport Layer Security* | Transport-securing protocol, successor to SSL [5, 8]. |
| **SSL** | *Secure Sockets Layer* | TLS's ancestor; SSL 3.0 is obsolete (Historic, RFC 6101) [12]. |
| **HTTPS** | *HTTP Secure* | HTTP wrapped in TLS. |
| **MITM** | *Man-In-The-Middle* | Attacker interposed on the channel, reading/rewriting traffic. |
| **PKI** | *Public Key Infrastructure* | Infrastructure managing certificates and trust (RFC 5280) [4]. |
| **PFS** | *Perfect Forward Secrecy* | Leaking a long-term key does not compromise past sessions (C6, C7). |
| **CA** | *Certificate Authority* | Authority that signs and attests certificates. |
| **SAN** | *Subject Alternative Name* | Certificate field listing the covered identities (domains). |
| **CRL** | *Certificate Revocation List* | List of revoked certificates. |
| **ASN.1** | *Abstract Syntax Notation One* | Structure notation of X.509 certificates (walked in C1). |
| **TBS** | *To Be Signed (Certificate)* | The actually-signed body of the certificate (compared in C1). |
| **HSTS** | *HTTP Strict Transport Security* | Header forcing HTTPS on the client side (RFC 6797) [6]. |
| **CBC** | *Cipher Block Chaining* | Block mode; its padding/IV flaws underlie POODLE and BEAST. |
| **IV** | *Initialization Vector* | CBC seeding block; its predictability in TLS 1.0 underlies BEAST [13]. |
| **AEAD** | *Authenticated Encryption with Associated Data* | Authenticated encryption (AES-GCM) with no CBC oracle. |
| **SCSV** | *Signaling Cipher Suite Value* | Dummy suite signaling a fallback, basis of `TLS_FALLBACK_SCSV` (RFC 7507) [9]. |
| **RSA** | *Rivest–Shamir–Adleman* | Asymmetric cryptosystem; in RSA *key exchange*, no forward secrecy (C6). |
| **kRSA** | *(key exchange) RSA* | TLS suites where the pre-master secret is encrypted under the server's RSA key (C6). |
| **DH** | *Diffie-Hellman* | Key exchange based on the discrete logarithm; too small a group (512 bits) is breakable (C7). |
| **DHE** | *Diffie-Hellman Ephemeral* | Ephemeral variant (carries PFS if the group is robust); downgraded to EXPORT in Logjam (C7). |
| **ECDHE** | *Elliptic Curve Diffie-Hellman Ephemeral* | Ephemeral exchange over an elliptic curve, the forward-secrecy standard. |
| **EXPORT** | *EXPORT (suites)* | Old weakened suites (keys/groups ≤ 512 bits) imposed by US regulation; basis of Logjam/FREAK [19]. |
| **OAEP** | *Optimal Asymmetric Encryption Padding* | Safe padding for RSA encryption (used in C5). |
| **BPF** | *Berkeley Packet Filter* | Capture filtering language (Scapy `sniff`, `tcpdump`). |
| **BEAST** | *Browser Exploit Against SSL/TLS* | Chosen-plaintext attack on TLS 1.0/CBC (CVE-2011-3389) [13, 14]. |
| **CVE** | *Common Vulnerabilities and Exposures* | Public vulnerability identification system (MITRE). |
| **RFC** | *Request For Comments* | IETF normative document. |
| **ARP** | *Address Resolution Protocol* | IP↔MAC protocol; its hijacking (*spoofing*) positions the MITM (RFC 826) [15]. |
| **IaC** | *Infrastructure as Code* | Declarative, versioned infrastructure management [1]. |
*Environment strictly for teaching purposes — ANSSI / CFSSI.*
# 🇫🇷 Version française # TP « Sécurité HTTPS » — Laboratoire de challenges TLS **Contexte** : travaux pratiques sur la sécurité du transport HTTPS, structurés en onze challenges de type *capture-the-flag*. Deux challenges de **prise en main** (OpenSSL, Scapy) outillent l'apprenant, un challenge d'**interception en clair** (MITM HTTP) installe la posture d'attaquant réseau, puis huit challenges mettent en défaut, de façon contrôlée, une propriété distincte de la sécurité TLS — afin que l'apprenant reconstruise expérimentalement le lien entre *garantie théorique* et *condition de mise en œuvre*. ## 1. Objectifs pédagogiques À l'issue du TP, l'apprenant doit être capable de : 1. **manipuler l'outillage de base** : fabriquer, inspecter et vérifier à la main un certificat X.509 avec OpenSSL (parcours ASN.1) ; renifler, disséquer, forger et émettre des paquets avec Scapy [18] ; 2. distinguer les trois garanties d'un canal TLS — **confidentialité**, **intégrité**, **authentification du pair** — et démontrer qu'elles sont *séparables* (un canal peut chiffrer sans authentifier ; un canal peut n'offrir aucune garantie s'il n'y a pas de TLS du tout) [5, 8] ; 3. relier chaque vulnérabilité à la couche fautive : identité (PKI), gestion des secrets, **forward secrecy** (absente ou *imparfaite*), négociation de protocole, ou implémentation ; 4. se placer en **homme-du-milieu** (empoisonnement ARP, RFC 826 [15]) et mobiliser l'outillage public (bettercap, mitmproxy, `openssl s_client`, Wireshark/tshark, `nmap --script ssl-*`, `testssl.sh`) ; 5. formuler pour chaque attaque la **contre-mesure normative** correspondante (validation RFC 5280, échanges éphémères ECDHE/PFS, groupes DH ≥ 2048 bits, HSTS RFC 6797, `TLS_FALLBACK_SCSV` RFC 7507, fractionnement 1/n-1 et IV explicite RFC 4346, mise à jour d'OpenSSL) [4, 6, 9, 17, 19]. ## 2. Modèle de menace et architecture Le modèle retenu est celui de l'**attaquant réseau actif** (Dolev–Yao) placé entre un client-victime et un serveur : il peut lire, réécrire, rejouer et injecter des paquets, mais ne dispose *a priori* d'aucun secret cryptographique. Les challenges C6 et C7 enrichissent ce modèle : C6 ajoute la **compromission différée** (enregistrer maintenant, obtenir la clé plus tard) ; C7 (Logjam) ajoute la **rétrogradation active** d'un échange éphémère vers un groupe si faible que le calcul du logarithme discret devient réalisable après un **précalcul amorti** sur le nombre premier partagé [8, 19]. Principe de conception structurant : **le portail applicatif n'est jamais troué au sens applicatif**. La vulnérabilité réside systématiquement dans la couche de *transport* placée devant lui (terminaison TLS par nginx/apache/openssl), ou dans son absence (MITM HTTP). Cette séparation isole la variable étudiée et évite de confondre faille web (hors périmètre) et faille TLS (objet du TP). Réseau de laboratoire isolé (172.28.0.0/16) ┌───────────────┐ MITM ┌────────────────────────────┐ │ client-victime│◄─────attaquant────►│ cible Cx : front-end TLS │ │ (imprudent) │ │ VULNÉRABLE → portail │ └───────┬───────┘ └──────────────┬─────────────┘ │ armé par (IP dest.) │ proxy clair └─────────────── Portail Flask ───────────┘ (flux flag chiffré · start · verify) Composants (cf. `docker-compose.yml`) : | Rôle | Conteneur | Fonction | |------|-----------|----------| | Portail | `portal` | Sert le flag chiffré, arme le client-victime, vérifie les flags | | Victime | `victim-client` | Émet le trafic imprudent à intercepter | | Cibles | `c1`…`c11` | Front-ends vulnérables (ou balise Scapy), un par challenge | Le portail refuse toute IP de destination hors de `LAB_CIDR` : il ne peut donc pas être détourné en lanceur d'attaque générique (validation dans `app/app.py`). Les warm-ups (C1 OpenSSL, C2 Scapy) sont des interactions *directes* avec la cible et ne mobilisent pas le client-victime. ## 3. Cartographie challenge → couche mise en défaut | # | Challenge | Couche / compétence | Garantie annulée | Réf. | |---|-----------|---------------------|------------------|------| | 1 | Prise en main OpenSSL | Outillage X.509 (ASN.1) | — (formation) | [4] | | 2 | Prise en main Scapy | Outillage réseau (sniff/forge) | — (formation) | [15, 18] | | 3 | MITM contre HTTP | Absence de transport chiffré | Confidentialité (totale) | [15] | | 4 | Certificat auto-signé + MITM | Identité PKI | Authentification | [4] | | 5 | Fuite de clé privée | Gestion des secrets (RSA-OAEP applicatif) | Confidentialité persistante | — | | 6 | Absence de forward secrecy | Échange de clés RSA (pas d'éphémère) | Confidentialité *rétroactive* | [5, 8] | | 7 | Logjam (DHE export) | Groupe DH 512 bits + downgrade | Confidentialité (*imperfect* FS) | [19, 20] | | 8 | SSL stripping | Politique de transport | Confidentialité (via downgrade) | [6, 7] | | 9 | POODLE (SSLv3/CBC) | Négociation + mode CBC | Confidentialité | [9, 10] | | 10 | BEAST (TLS 1.0/CBC) | IV prévisible (CBC chaîné) | Confidentialité (chosen-plaintext) | [13, 14, 16] | | 11 | Heartbleed | Implémentation (RFC 6520) | Confidentialité (mémoire) | [3, 11] | ## 4. Construction des images (Packer) Deux voies, au choix de l'enseignant : **(a) Packer → Docker** — image du portail construite par *provisioning* immuable (`packer/portal.pkr.hcl`). Cette approche « image immuable » [1, 2] garantit la reproductibilité bit-à-bit indépendamment d'un `docker build` local : cd packer && packer init . && packer build -only='docker.*' . **(b) Packer → QEMU** — cuisson d'une **VM autonome** embarquant tout le lab (`packer/lab-vm.pkr.hcl`). Livrable idéal en salle : un unique `qcow2` remis à chaque étudiant, sans dépendance réseau à l'exécution (isolement garanti) : cd packer && packer init . && packer build -only='qemu.*' . # → output-lab-vm/tls-lab.qcow2 ## 5. Déploiement du laboratoire Le TP se déploie de **trois façons**, selon le contexte : | Mode | Outil | Topologie | Où | |------|-------|-----------|-----| | **Local** (poste unique) | Packer + Compose | tout sur une machine (ou une VM `qcow2`) | ci-dessous + `packer/` | | **Salle de TP** (parc) | Ansible (+ Packer) | portail sur la prof, cibles+victime sur chaque poste | `ansible/` (`site.yml`) | | **Centralisé anti-triche** | Ansible (+ Packer) | tout sur le serveur prof, une instance isolée/étudiant, accès SSH confiné | `ansible/` (`centralized.yml`) | En **salle de TP** (mode 2), le portail — le site qui reçoit et vérifie les flags — est centralisé sur la machine prof ; chaque poste n'héberge que les cibles et le client-victime, qui proxifient vers ce portail (`portal → IP_prof` via `extra_hosts`). La victime tourne en mode *standalone*. Déploiement : `cd ansible && ansible-playbook site.yml`. En **centralisé anti-triche** (mode 3), **tout** tourne sur le serveur prof, en une **instance isolée par étudiant** (portail + cibles + victime + attaquant, sur un réseau `/24` dédié et hermétique). L'étudiant n'a **aucun accès Docker/hôte** : il se connecte par **SSH** (`ForceCommand`) dans son seul conteneur attaquant, et les **flags C2–C11 sont uniques par étudiant** — impossible d'extraire un flag d'une image ou de le partager. Déploiement : `cd ansible && ansible-playbook centralized.yml` (voir `ansible/README.md`). ### Mode local make up # docker compose build && up -d # Cibles : 8451(C1) · 8453(C3) · 8441(C4) · 8442(C5) · 8447(C6) · 8448(C7) # 8006/8443(C8) · 8444(C9) · 8446(C10) · 8445(C11). # C2 = balise Scapy interne (UDP/8452). ### Option « debug » — proxy d'observation Un override Compose insère un **proxy d'inspection** (mitmproxy/mitmweb) par lequel transite **tout le trafic du client-victime**. La victime acceptant déjà n'importe quel certificat, mitmproxy **déchiffre** les sessions TLS victime↔cible et affiche en clair chaque échange (flux du flag, blob RSA-OAEP, clé fuitée, cookies POODLE/BEAST/Logjam, page Heartbleed…) — pratique pour vérifier qu'un challenge délivre bien son flag ou pour une démonstration. make debug # = docker compose -f docker-compose.yml -f docker-compose.debug.yml up -d # → interface d'inspection : http://localhost:8081 make debug-down Pour un isolement total, basculer `internal: true` sur le réseau `lab` dans `docker-compose.yml`. Le poste d'attaque se joint au réseau `lab` (ou l'on `docker compose exec` un conteneur outillé) : Scapy y voit la balise C2 et peut y empoisonner l'ARP. ## 6. Déroulé détaillé par challenge Chaque section suit le même canevas : *contexte → chaîne d'exploitation → contre-mesure normative*. Les corrections complètes (outils publics **et** Scapy) sont dans `SOLUTIONS.md`. ### C1 — Prise en main d'OpenSSL (10 pts) - **But** : récupérer le certificat auto-signé de la cible (`openssl s_client`), l'inspecter (`openssl x509 -text`), puis **vérifier sa signature à la main** (parcours `asn1parse`, extraction du BIT STRING, `rsautl -verify`, comparaison au condensat du TBSCertificate). Le flag est embarqué dans le champ *OU* du certificat. - **Enseignement** : dérouler manuellement ce que `openssl verify` automatise ; comprendre la structure ASN.1 et le lien signature ↔ corps (RFC 5280 [4]). ### C2 — Prise en main de Scapy (10 pts) - **But** : renifler la balise UDP/8452 (`sniff(filter="udp port 8452")`), lire la consigne, **forger** le datagramme magique et l'**émettre** (`sr1`) ; la cible répond alors avec le flag. - **Enseignement** : les trois gestes de Scapy — sniff, dissection en couches, forge/émission — socle des challenges MITM suivants [18]. ### C3 — MITM contre HTTP en clair (20 pts) - **Transport** : HTTP clair (port 8453), **aucun TLS**. - **Exploitation** : empoisonnement ARP (`arp_spoof.py` ou bettercap) entre victime et cible, puis sniffing (`sniff_http_flag.py` / tcpdump) ; le flag transite en clair. - **Enseignement** : sans chiffrement de transport, la confidentialité est nulle ; l'interception active (RFC 826 [15]) suffit. - **Contre-mesure** : HTTPS obligatoire + redirection permanente + HSTS (cf. C8). ### C4 — Certificat auto-signé & MITM (15 pts) - **Transport** : TLS 1.2, certificat auto-signé, *non validé par le client*. - **Exploitation** : ARP-spoof du client-victime ; interception transparente (`bettercap`/`mitmproxy`) ; l'attaquant présente son propre certificat auto-signé, que la victime accepte (validation désactivée), et lit le flag. - **Enseignement** : le chiffrement sans **authentification du pair** n'offre aucune protection contre un MITM ; la confiance repose sur la validation de la chaîne de certification [4]. - **Contre-mesure** : validation stricte RFC 5280 (chaîne, SAN, révocation) ; épinglage le cas échéant. ### C5 — Fuite de clé privée (20 pts) - **Transport** : TLS sain, mais la clé privée RSA du portail est exposée sous `/.well-known/backup/server.key`. Le flag est publié chiffré **RSA-OAEP** par `/c/5/flag-feed`. - **Exploitation** : curl -k https://CIBLE:8442/.well-known/backup/server.key -o server.key curl -k https://CIBLE:8442/c/5/flag-feed | jq -r .ciphertext_b64 | base64 -d > flag.bin openssl pkeyutl -decrypt -inkey server.key \ -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -in flag.bin - **Enseignement** : la compromission d'une clé long-terme annule la confidentialité de tout ce qu'elle protège. Ici la protection est *applicative* (un blob) ; le C6 montre la même logique au niveau *transport*. - **Contre-mesure** : cloisonnement des secrets, permissions restrictives, rotation, absence de secret dans une arborescence servie. ### C6 — Absence de forward secrecy / échange RSA (25 pts) - **Transport** : TLS 1.2 négociant un **échange de clés RSA** (suites `kRSA` type `TLS_RSA_WITH_AES_128_CBC_SHA` ; aucun ECDHE/DHE). Le secret pré-maître est chiffré sous la clé publique RSA du serveur et transporté dans le ClientKeyExchange. La clé privée du serveur est exposée sous `/.well-known/backup/server.key`. - **Exploitation** (déchiffrement *a posteriori*) : 1. **enregistrer** le trafic TLS de la victime : `tcpdump -i eth0 -w cap.pcap 'host CIBLE and port 8447'` (au besoin en position MITM, cf. `arp_spoof.py`) ; 2. **faire fuiter** la clé : `curl -k https://CIBLE:8447/.well-known/backup/server.key -o server.key` ; 3. **déchiffrer** hors ligne : Wireshark → *Preferences ▸ Protocols ▸ TLS ▸ RSA keys list* (ajouter `server.key`), ou `tshark -r cap.pcap -o "tls.keys_list:CIBLE,8447,http,server.key" -Y http`. Le flag apparaît en clair dans la réponse HTTP déchiffrée. - **Enseignement** : sans éphémère, la clé long-terme suffit à recalculer *toutes* les sessions passées capturées. La **forward secrecy** (ECDHE) rompt ce lien : chaque session dérive d'un secret éphémère détruit après usage, qu'aucune fuite ultérieure de la clé long-terme ne peut reconstituer [5, 8]. - **Contre-mesure** : imposer des suites **ECDHE** (forward secrecy) ; en TLS 1.3 l'échange RSA statique est purement et simplement supprimé. ### C7 — Logjam / DHE export (25 pts) - **Transport** : TLS 1.2 acceptant des suites **DHE de qualité EXPORT** — groupe Diffie-Hellman de **512 bits** (`EXP-EDH-RSA-DES-CBC-SHA`). Aucune protection contre le *downgrade*. Le flag est porté par le cookie `SESSIONFLAG`. - **Exploitation** : 1. **détecter** : `testssl.sh --logjam CIBLE:8448`, `nmap --script ssl-dh-params -p 8448 CIBLE`, ou `openssl s_client -connect CIBLE:8448 -cipher EXP` (une session à 512 bits s'établit) ; 2. en position **MITM**, forcer la rétrogradation du ClientHello vers la suite DHE_EXPORT (le serveur répond avec son groupe de 512 bits) ; 3. **casser** le logarithme discret du groupe de 512 bits — coûteux une fois, mais **amorti** car le même nombre premier est partagé par d'innombrables serveurs (précalcul), d'où récupération du secret éphémère puis déchiffrement de la session et lecture du cookie [19, 20]. - **Enseignement** : un échange *éphémère* n'assure la forward secrecy que si le groupe est **robuste**. Un groupe export (512 bits), ou même un groupe de 1024 bits partagé, est à la portée d'un précalcul (Logjam) : la FS devient *imparfaite*. C'est le pendant « DH » du C6 « RSA ». - **Contre-mesure** : désactiver toutes les suites EXPORT ; imposer des groupes DH **≥ 2048 bits** (ou uniques par serveur) ; préférer ECDHE. Côté client, refuser les groupes DHE < 1024 bits (correctif Logjam des navigateurs) [19]. ### C8 — SSL stripping (20 pts) - **Transport** : service joignable en clair (port 80), **aucun HSTS**, lien `http://` en dur. - **Exploitation** : MITM + rétrogradation HTTPS→HTTP (`bettercap` caplet `hstshijack`, ou `sslstrip2`) ; le flag transite alors en clair et est capturé. - **Enseignement** : l'attaque de Marlinspike [7] exploite l'*amorçage* en clair. La parade est de rendre HTTPS **obligatoire et mémorisé** côté client. - **Contre-mesure** : `Strict-Transport-Security` (HSTS, RFC 6797) avec `includeSubDomains` et inscription sur la *preload list* [6]. ### C9 — POODLE / SSL 3.0 (25 pts) - **Transport** : SSL 3.0 accepté, suites **CBC**, `TLS_FALLBACK_SCSV` absent → repli forcé possible. Le flag est porté par le cookie `SESSIONFLAG`. - **Exploitation** : forcer le repli SSLv3 (`openssl s_client -ssl3`) ; en position MITM, exploiter l'**oracle de padding CBC** de SSL 3.0 pour reconstituer le cookie octet par octet [9, 10]. - **Enseignement** : SSL 3.0 ne spécifie pas le contenu du bourrage CBC, rendant sa vérification exploitable en oracle. Un protocole obsolète reste dangereux tant qu'un downgrade est possible. - **Contre-mesure** : désactiver SSL 3.0 ; imposer `TLS_FALLBACK_SCSV` (RFC 7507) contre les rétrogradations [9]. ### C10 — BEAST / TLS 1.0 CBC (25 pts) - **Transport** : TLS 1.0 exclusivement, suites **CBC**. En TLS 1.0, l'IV d'un enregistrement est le dernier bloc chiffré du précédent : il est **prévisible**. Le flag est porté par le cookie `SESSIONFLAG`. - **Exploitation** : confirmer (`openssl s_client -tls1`, `testssl.sh`, `nmap --script ssl-enum-ciphers`) ; en position MITM (empoisonnement ARP, `arp_spoof.py`), monter l'attaque à **texte clair choisi adaptatif** (blockwise chosen-boundary) qui aligne la frontière de bloc et devine le cookie octet par octet [13, 14, 16]. - **Enseignement** : un IV prévisible transforme le chiffrement CBC en oracle de texte clair choisi. C'est une faiblesse de **conception protocolaire** (TLS 1.0), distincte de l'oracle de *padding* de POODLE. - **Contre-mesure** : bannir TLS 1.0 ; à défaut, **fractionnement 1/n-1** ou suites AEAD (AES-GCM). TLS 1.1+ referme structurellement BEAST par un IV explicite par enregistrement (RFC 4346 [17]). ### C11 — Heartbleed / OpenSSL 1.0.1f (20 pts) - **Transport** : OpenSSL 1.0.1f, extension **Heartbeat** (RFC 6520) sans contrôle de la longueur annoncée. Le flag réside en mémoire du processus. - **Exploitation** : nmap -p 8445 --script ssl-heartbleed CIBLE # détection # puis PoC RFC 6520 : requête Heartbeat avec payload_length surdimensionné # → lecture hors-limites jusqu'à 64 Ko, où figure le flag. - **Enseignement** : une seule longueur non vérifiée expose des blocs mémoire arbitraires (clés, cookies, données) — illustration canonique d'une vulnérabilité d'implémentation, distincte d'une faiblesse de protocole [3, 11]. - **Contre-mesure** : mise à jour OpenSSL ≥ 1.0.1g ; régénération des secrets potentiellement exposés. ## 7. Barème | Challenge | Points | Compétence évaluée | |-----------|:------:|--------------------| | C1 Prise en main OpenSSL | 10 | Manipulation X.509 / ASN.1 | | C2 Prise en main Scapy | 10 | Sniff / forge / envoi | | C3 MITM HTTP | 20 | Interception active (ARP) | | C4 Cert. auto-signé | 15 | Validation PKI | | C5 Fuite de clé | 20 | Gestion des secrets (applicatif) | | C6 Forward secrecy (échange RSA) | 25 | Déchiffrement a posteriori / PFS | | C7 Logjam (DHE export) | 25 | Downgrade DH + log discret précalculé | | C8 SSL stripping | 20 | Défense MITM / HSTS | | C9 POODLE | 25 | Oracle CBC / obsolescence | | C10 BEAST | 25 | IV prévisible / chosen-plaintext | | C11 Heartbleed | 20 | Divulgation mémoire | | **Total** | **215** | | ## 8. Précautions, éthique et isolement 1. **Isolement absolu** : réseau non routable ; `internal: true` recommandé. 2. **Périmètre** : le portail n'arme le client-victime que vers des IP privées du `LAB_CIDR` — aucune attaque hors laboratoire n'est possible depuis l'appli. 3. **Capacités réseau** : la cible Scapy (C2) et les postes d'attaque requièrent `NET_RAW`/`NET_ADMIN` ; ne les accorder qu'au sein du réseau isolé. 4. **Cadre légal** : environnement contrôlé, consentement pédagogique documenté ; les techniques d'interception ne sont licites que sur une infrastructure dont on a la maîtrise. 5. **Cycle de vie** : détruire les instances vulnérables après le TP (`make clean`) ; conserver des instantanés « propres ». 6. **Débriefing** : chaque challenge se conclut par l'énoncé de sa contre-mesure. ### Caveats de reproductibilité (protocoles obsolètes) Les protocoles hérités sont progressivement retirés des piles récentes : - **C6 (échange RSA)** : les suites `kRSA` sont dépréciées ; réautorisées via `@SECLEVEL=1` dans `ssl_ciphers`. Wireshark ne déchiffre le trafic avec la clé privée **que** pour l'échange RSA (impossible avec ECDHE) — c'est précisément le point pédagogique. - **C7 (Logjam)** : les suites **EXPORT** ont été retirées d'OpenSSL ≥ 1.0.2g. La cible est donc bâtie sur `ubuntu:14.04` (OpenSSL 1.0.1f, qui les embarque encore). Le **cassage du log discret 512 bits** n'est pas exécuté en séance : on s'appuie sur un précalcul/PoC pour le groupe connu (c'est *toute* la logique de Logjam — le précalcul est amorti). L'exercice évaluable est la **détection** et la **démonstration du downgrade** ; le déchiffrement complet est fourni « clé en main » par l'encadrant. - **C9 (SSLv3)** : image `httpd:2.4.29` épinglée. - **C10 (TLS 1.0)** : réactivé via `targets/beast/openssl-lab.cnf` (`MinProtocol= TLSv1`, `@SECLEVEL=0`). Base héritée sinon. - **C11 (Heartbleed)** : OpenSSL 1.0.1f compilé depuis l'archive officielle. Ces cibles n'ont **pas** été construites/exécutées dans l'environnement de préparation (réseau désactivé) : valider le `docker build` sur un hôte outillé avant la séance. ## 9. Reproductibilité et anti-triche Les flags sont chargés depuis l'environnement (`FLAG_C1`…`FLAG_C11`), propagés de façon cohérente au portail **et** à la cible correspondante via `docker-compose`. Pour générer une instance unique par promotion ou par étudiant, définir un `.env` puis `docker compose up -d --build --force-recreate`. La vérification se fait à divulgation nulle (comparaison à temps constant sur empreinte SHA-256, cf. `challenges.py`). ## 10. Références [1] K. Morris, *Infrastructure as Code*, 2ᵉ éd., O'Reilly, 2020. [2] HashiCorp, *Packer Documentation — Immutable Machine Images*, docs.packer.io. [3] R. Seggelmann, M. Tuexen, M. Williams, « Transport Layer Security (TLS) and Datagram TLS (DTLS) Heartbeat Extension », **RFC 6520**, IETF, 2012. [4] D. Cooper *et al.*, « Internet X.509 Public Key Infrastructure Certificate and CRL Profile », **RFC 5280**, IETF, 2008. [5] T. Dierks, E. Rescorla, « The TLS Protocol Version 1.2 », **RFC 5246**, 2008. [6] J. Hodges, C. Jackson, A. Barth, « HTTP Strict Transport Security (HSTS) », **RFC 6797**, IETF, 2012. [7] M. Marlinspike, « New Tricks for Defeating SSL in Practice », *Black Hat DC*, 2009. [8] E. Rescorla, « The Transport Layer Security (TLS) Protocol Version 1.3 », **RFC 8446**, IETF, 2018. [9] B. Möller, A. Langley, « TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks », **RFC 7507**, IETF, 2015. [10] B. Möller, T. Duong, K. Kotowicz, « This POODLE Bites: Exploiting the SSL 3.0 Fallback », Google, 2014. (CVE-2014-3566) [11] MITRE, « CVE-2014-0160 (Heartbleed) », *Common Vulnerabilities and Exposures*, 2014. [12] A. Freier, P. Karlton, P. Kocher, « The Secure Sockets Layer (SSL) Protocol Version 3.0 », **RFC 6101** (Historic), IETF, 2011. [13] T. Duong, J. Rizzo, « Here Come The ⊕ Ninjas » (BEAST), 2011. [14] MITRE, « CVE-2011-3389 » (SSL/TLS 1.0 CBC — BEAST), 2011. [15] D. Plummer, « An Ethernet Address Resolution Protocol », **RFC 826**, IETF, 1982. [16] G. Bard, « A Challenging but Feasible Blockwise-Adaptive Chosen-Plaintext Attack on SSL », *SECRYPT*, 2006. [17] T. Dierks, E. Rescorla, « The TLS Protocol Version 1.1 », **RFC 4346**, 2006. [18] P. Biondi *et al.*, *Scapy Documentation*, scapy.readthedocs.io. [19] D. Adrian *et al.*, « Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice » (Logjam), *ACM CCS*, 2015. [20] MITRE, « CVE-2015-4000 (Logjam) », *Common Vulnerabilities and Exposures*, 2015. ## Annexe A — Flashcards (révision active) 1. **Q :** Que révèle la vérification *manuelle* d'une signature de certificat par rapport à `openssl verify` ? **R :** Le lien concret signature↔corps : parcours ASN.1, extraction du BIT STRING, déchiffrement RSA public, comparaison au condensat du TBSCertificate (C1). 2. **Q :** Quels sont les trois gestes fondamentaux de Scapy ? **R :** Renifler (`sniff`/filtre BPF), disséquer (`pkt[couche]`), forger & émettre (`IP()/UDP()/Raw()`, `sr1`) (C2). 3. **Q :** Pourquoi un flux HTTP en clair n'offre-t-il aucune confidentialité en présence d'un MITM ? **R :** Sans chiffrement de transport, l'empoisonnement ARP (RFC 826) suffit à lire l'intégralité du trafic (C3). 4. **Q :** Quelles sont les trois garanties d'un canal TLS, et laquelle un certificat auto-signé non validé annule-t-il ? **R :** Confidentialité, intégrité, authentification du pair ; c'est l'authentification qui tombe (C4). 5. **Q :** Quelle est la différence entre la fuite de clé du C5 et celle du C6 ? **R :** C5 déchiffre un blob *applicatif* (RSA-OAEP) directement ; C6 déchiffre *a posteriori* une session TLS **enregistrée** parce que l'échange RSA n'offre pas de forward secrecy. 6. **Q :** Pourquoi l'échange RSA (C6) permet-il un déchiffrement rétroactif, et qu'est-ce qui l'empêche ? **R :** Le secret pré-maître est chiffré sous la clé long-terme du serveur ; sa fuite ultérieure le recalcule. L'éphémère **ECDHE** détruit le secret après usage → aucune fuite ne le reconstitue (C6). 7. **Q :** En quoi Logjam (C7) diffère-t-il du C6 alors que DHE est *éphémère* ? **R :** L'éphémère existe mais le groupe DH est rétrogradé à 512 bits ; son log discret est précalculable (amorti sur le premier partagé) → forward secrecy *imparfaite*. Parade : DH ≥ 2048 bits / ECDHE, et pas d'EXPORT (C7). 8. **Q :** Pourquoi le précalcul est-il central dans Logjam ? **R :** Le coût (élevé) du logarithme discret sur un premier donné est payé *une fois*, puis réutilisé contre tous les serveurs partageant ce premier (C7). 9. **Q :** Quel en-tête, et quel mécanisme complémentaire, neutralisent le SSL stripping ? **R :** `Strict-Transport-Security` (HSTS, RFC 6797) + inscription sur la *preload list* pour couvrir la toute première visite (C8). 10. **Q :** Sur quelle propriété du bourrage CBC de SSL 3.0 repose POODLE, et qu'est-ce qui l'empêche ? **R :** Le contenu du padding n'est pas spécifié → oracle exploitable octet par octet ; `TLS_FALLBACK_SCSV` (RFC 7507) bloque le downgrade (C9). 11. **Q :** Qu'est-ce qui rend l'IV prévisible en TLS 1.0 (BEAST), et qu'est-ce qui referme la faille ? **R :** L'IV d'un enregistrement est le dernier bloc chiffré du précédent ; TLS 1.1 impose un IV explicite par enregistrement, ou fractionnement 1/n-1 (C10). 12. **Q :** Heartbleed est-elle une faille de protocole ou d'implémentation ? **R :** D'implémentation (OpenSSL) : la longueur du payload Heartbeat (RFC 6520) n'est pas contrôlée → lecture hors-limites jusqu'à 64 Ko (C11). 13. **Q :** Trois façons distinctes de perdre la confidentialité d'un échange de clés — nommez-les via C6, C7 et le remède commun. **R :** Pas d'éphémère (RSA, C6) ; éphémère trop faible/rétrogradé (DH 512, Logjam C7) ; remède commun : éphémères robustes (ECDHE ou DH ≥ 2048 bits). ## Annexe B — Glossaire des acronymes | Acronyme | Développé | Explication | |----------|-----------|-------------| | **TLS** | *Transport Layer Security* | Protocole de sécurisation du transport, successeur de SSL [5, 8]. | | **SSL** | *Secure Sockets Layer* | Ancêtre de TLS ; SSL 3.0 est obsolète (Historic, RFC 6101) [12]. | | **HTTPS** | *HTTP Secure* | HTTP encapsulé dans TLS. | | **MITM** | *Man-In-The-Middle* | Attaquant interposé sur le canal, lisant/réécrivant le trafic. | | **PKI** | *Public Key Infrastructure* | Infrastructure de gestion des certificats et de la confiance (RFC 5280) [4]. | | **PFS** | *Perfect Forward Secrecy* | La fuite d'une clé long-terme ne compromet pas les sessions passées (C6, C7). | | **CA** | *Certificate Authority* | Autorité qui signe et atteste les certificats. | | **SAN** | *Subject Alternative Name* | Champ du certificat listant les identités (domaines) couvertes. | | **CRL** | *Certificate Revocation List* | Liste des certificats révoqués. | | **ASN.1** | *Abstract Syntax Notation One* | Notation de structure des certificats X.509 (parcourue au C1). | | **TBS** | *To Be Signed (Certificate)* | Corps du certificat effectivement signé (comparé au C1). | | **HSTS** | *HTTP Strict Transport Security* | En-tête forçant l'usage de HTTPS côté client (RFC 6797) [6]. | | **CBC** | *Cipher Block Chaining* | Mode par blocs ; ses défauts de padding/IV fondent POODLE et BEAST. | | **IV** | *Initialization Vector* | Bloc d'amorçage CBC ; sa prévisibilité en TLS 1.0 fonde BEAST [13]. | | **AEAD** | *Authenticated Encryption with Associated Data* | Chiffrement authentifié (AES-GCM) sans oracle CBC. | | **SCSV** | *Signaling Cipher Suite Value* | Suite factice signalant un repli, base de `TLS_FALLBACK_SCSV` (RFC 7507) [9]. | | **RSA** | *Rivest–Shamir–Adleman* | Cryptosystème asymétrique ; en *échange de clés* RSA, pas de forward secrecy (C6). | | **kRSA** | *(key exchange) RSA* | Suites TLS où le secret pré-maître est chiffré sous la clé RSA du serveur (C6). | | **DH** | *Diffie-Hellman* | Échange de clés fondé sur le logarithme discret ; un groupe trop petit (512 bits) est cassable (C7). | | **DHE** | *Diffie-Hellman Ephemeral* | Variante éphémère (porteuse de PFS si le groupe est robuste) ; rétrogradée en EXPORT dans Logjam (C7). | | **ECDHE** | *Elliptic Curve Diffie-Hellman Ephemeral* | Échange éphémère sur courbe elliptique, standard de forward secrecy. | | **EXPORT** | *(suites) EXPORT* | Anciennes suites bridées (clés/groupes ≤ 512 bits) imposées par la réglementation US ; base de Logjam/FREAK [19]. | | **OAEP** | *Optimal Asymmetric Encryption Padding* | Bourrage sûr pour le chiffrement RSA (utilisé au C5). | | **BPF** | *Berkeley Packet Filter* | Langage de filtrage de capture (Scapy `sniff`, `tcpdump`). | | **BEAST** | *Browser Exploit Against SSL/TLS* | Attaque chosen-plaintext sur TLS 1.0/CBC (CVE-2011-3389) [13, 14]. | | **CVE** | *Common Vulnerabilities and Exposures* | Système d'identification public des vulnérabilités (MITRE). | | **RFC** | *Request For Comments* | Document normatif de l'IETF. | | **ARP** | *Address Resolution Protocol* | Protocole IP↔MAC ; son détournement (*spoofing*) positionne le MITM (RFC 826) [15]. | | **IaC** | *Infrastructure as Code* | Gestion déclarative et versionnée de l'infrastructure [1]. | *Environnement à visée strictement pédagogique — ANSSI / CFSSI.*
# 🇫🇷 Version française # TP « Sécurité HTTPS » — Laboratoire de challenges TLS **Contexte** : travaux pratiques sur la sécurité du transport HTTPS, structurés en onze challenges de type *capture-the-flag*. Deux challenges de **prise en main** (OpenSSL, Scapy) outillent l'apprenant, un challenge d'**interception en clair** (MITM HTTP) installe la posture d'attaquant réseau, puis huit challenges mettent en défaut, de façon contrôlée, une propriété distincte de la sécurité TLS — afin que l'apprenant reconstruise expérimentalement le lien entre *garantie théorique* et *condition de mise en œuvre*. ## 1. Objectifs pédagogiques À l'issue du TP, l'apprenant doit être capable de : 1. **manipuler l'outillage de base** : fabriquer, inspecter et vérifier à la main un certificat X.509 avec OpenSSL (parcours ASN.1) ; renifler, disséquer, forger et émettre des paquets avec Scapy [18] ; 2. distinguer les trois garanties d'un canal TLS — **confidentialité**, **intégrité**, **authentification du pair** — et démontrer qu'elles sont *séparables* (un canal peut chiffrer sans authentifier ; un canal peut n'offrir aucune garantie s'il n'y a pas de TLS du tout) [5, 8] ; 3. relier chaque vulnérabilité à la couche fautive : identité (PKI), gestion des secrets, **forward secrecy** (absente ou *imparfaite*), négociation de protocole, ou implémentation ; 4. se placer en **homme-du-milieu** (empoisonnement ARP, RFC 826 [15]) et mobiliser l'outillage public (bettercap, mitmproxy, `openssl s_client`, Wireshark/tshark, `nmap --script ssl-*`, `testssl.sh`) ; 5. formuler pour chaque attaque la **contre-mesure normative** correspondante (validation RFC 5280, échanges éphémères ECDHE/PFS, groupes DH ≥ 2048 bits, HSTS RFC 6797, `TLS_FALLBACK_SCSV` RFC 7507, fractionnement 1/n-1 et IV explicite RFC 4346, mise à jour d'OpenSSL) [4, 6, 9, 17, 19]. ## 2. Modèle de menace et architecture Le modèle retenu est celui de l'**attaquant réseau actif** (Dolev–Yao) placé entre un client-victime et un serveur : il peut lire, réécrire, rejouer et injecter des paquets, mais ne dispose *a priori* d'aucun secret cryptographique. Les challenges C6 et C7 enrichissent ce modèle : C6 ajoute la **compromission différée** (enregistrer maintenant, obtenir la clé plus tard) ; C7 (Logjam) ajoute la **rétrogradation active** d'un échange éphémère vers un groupe si faible que le calcul du logarithme discret devient réalisable après un **précalcul amorti** sur le nombre premier partagé [8, 19]. Principe de conception structurant : **le portail applicatif n'est jamais troué au sens applicatif**. La vulnérabilité réside systématiquement dans la couche de *transport* placée devant lui (terminaison TLS par nginx/apache/openssl), ou dans son absence (MITM HTTP). Cette séparation isole la variable étudiée et évite de confondre faille web (hors périmètre) et faille TLS (objet du TP). Réseau de laboratoire isolé (172.28.0.0/16) ┌───────────────┐ MITM ┌────────────────────────────┐ │ client-victime│◄─────attaquant────►│ cible Cx : front-end TLS │ │ (imprudent) │ │ VULNÉRABLE → portail │ └───────┬───────┘ └──────────────┬─────────────┘ │ armé par (IP dest.) │ proxy clair └─────────────── Portail Flask ───────────┘ (flux flag chiffré · start · verify) Composants (cf. `docker-compose.yml`) : | Rôle | Conteneur | Fonction | |------|-----------|----------| | Portail | `portal` | Sert le flag chiffré, arme le client-victime, vérifie les flags | | Victime | `victim-client` | Émet le trafic imprudent à intercepter | | Cibles | `c1`…`c11` | Front-ends vulnérables (ou balise Scapy), un par challenge | Le portail refuse toute IP de destination hors de `LAB_CIDR` : il ne peut donc pas être détourné en lanceur d'attaque générique (validation dans `app/app.py`). Les warm-ups (C1 OpenSSL, C2 Scapy) sont des interactions *directes* avec la cible et ne mobilisent pas le client-victime. ## 3. Cartographie challenge → couche mise en défaut | # | Challenge | Couche / compétence | Garantie annulée | Réf. | |---|-----------|---------------------|------------------|------| | 1 | Prise en main OpenSSL | Outillage X.509 (ASN.1) | — (formation) | [4] | | 2 | Prise en main Scapy | Outillage réseau (sniff/forge) | — (formation) | [15, 18] | | 3 | MITM contre HTTP | Absence de transport chiffré | Confidentialité (totale) | [15] | | 4 | Certificat auto-signé + MITM | Identité PKI | Authentification | [4] | | 5 | Fuite de clé privée | Gestion des secrets (RSA-OAEP applicatif) | Confidentialité persistante | — | | 6 | Absence de forward secrecy | Échange de clés RSA (pas d'éphémère) | Confidentialité *rétroactive* | [5, 8] | | 7 | Logjam (DHE export) | Groupe DH 512 bits + downgrade | Confidentialité (*imperfect* FS) | [19, 20] | | 8 | SSL stripping | Politique de transport | Confidentialité (via downgrade) | [6, 7] | | 9 | POODLE (SSLv3/CBC) | Négociation + mode CBC | Confidentialité | [9, 10] | | 10 | BEAST (TLS 1.0/CBC) | IV prévisible (CBC chaîné) | Confidentialité (chosen-plaintext) | [13, 14, 16] | | 11 | Heartbleed | Implémentation (RFC 6520) | Confidentialité (mémoire) | [3, 11] | ## 4. Construction des images (Packer) Deux voies, au choix de l'enseignant : **(a) Packer → Docker** — image du portail construite par *provisioning* immuable (`packer/portal.pkr.hcl`). Cette approche « image immuable » [1, 2] garantit la reproductibilité bit-à-bit indépendamment d'un `docker build` local : cd packer && packer init . && packer build -only='docker.*' . **(b) Packer → QEMU** — cuisson d'une **VM autonome** embarquant tout le lab (`packer/lab-vm.pkr.hcl`). Livrable idéal en salle : un unique `qcow2` remis à chaque étudiant, sans dépendance réseau à l'exécution (isolement garanti) : cd packer && packer init . && packer build -only='qemu.*' . # → output-lab-vm/tls-lab.qcow2 ## 5. Déploiement du laboratoire Le TP se déploie de **trois façons**, selon le contexte : | Mode | Outil | Topologie | Où | |------|-------|-----------|-----| | **Local** (poste unique) | Packer + Compose | tout sur une machine (ou une VM `qcow2`) | ci-dessous + `packer/` | | **Salle de TP** (parc) | Ansible (+ Packer) | portail sur la prof, cibles+victime sur chaque poste | `ansible/` (`site.yml`) | | **Centralisé anti-triche** | Ansible (+ Packer) | tout sur le serveur prof, une instance isolée/étudiant, accès SSH confiné | `ansible/` (`centralized.yml`) | En **salle de TP** (mode 2), le portail — le site qui reçoit et vérifie les flags — est centralisé sur la machine prof ; chaque poste n'héberge que les cibles et le client-victime, qui proxifient vers ce portail (`portal → IP_prof` via `extra_hosts`). La victime tourne en mode *standalone*. Déploiement : `cd ansible && ansible-playbook site.yml`. En **centralisé anti-triche** (mode 3), **tout** tourne sur le serveur prof, en une **instance isolée par étudiant** (portail + cibles + victime + attaquant, sur un réseau `/24` dédié et hermétique). L'étudiant n'a **aucun accès Docker/hôte** : il se connecte par **SSH** (`ForceCommand`) dans son seul conteneur attaquant, et les **flags C2–C11 sont uniques par étudiant** — impossible d'extraire un flag d'une image ou de le partager. Déploiement : `cd ansible && ansible-playbook centralized.yml` (voir `ansible/README.md`). ### Mode local make up # docker compose build && up -d # Cibles : 8451(C1) · 8453(C3) · 8441(C4) · 8442(C5) · 8447(C6) · 8448(C7) # 8006/8443(C8) · 8444(C9) · 8446(C10) · 8445(C11). # C2 = balise Scapy interne (UDP/8452). ### Option « debug » — proxy d'observation Un override Compose insère un **proxy d'inspection** (mitmproxy/mitmweb) par lequel transite **tout le trafic du client-victime**. La victime acceptant déjà n'importe quel certificat, mitmproxy **déchiffre** les sessions TLS victime↔cible et affiche en clair chaque échange (flux du flag, blob RSA-OAEP, clé fuitée, cookies POODLE/BEAST/Logjam, page Heartbleed…) — pratique pour vérifier qu'un challenge délivre bien son flag ou pour une démonstration. make debug # = docker compose -f docker-compose.yml -f docker-compose.debug.yml up -d # → interface d'inspection : http://localhost:8081 make debug-down Pour un isolement total, basculer `internal: true` sur le réseau `lab` dans `docker-compose.yml`. Le poste d'attaque se joint au réseau `lab` (ou l'on `docker compose exec` un conteneur outillé) : Scapy y voit la balise C2 et peut y empoisonner l'ARP. ## 6. Déroulé détaillé par challenge Chaque section suit le même canevas : *contexte → chaîne d'exploitation → contre-mesure normative*. Les corrections complètes (outils publics **et** Scapy) sont dans `SOLUTIONS.md`. ### C1 — Prise en main d'OpenSSL (10 pts) - **But** : récupérer le certificat auto-signé de la cible (`openssl s_client`), l'inspecter (`openssl x509 -text`), puis **vérifier sa signature à la main** (parcours `asn1parse`, extraction du BIT STRING, `rsautl -verify`, comparaison au condensat du TBSCertificate). Le flag est embarqué dans le champ *OU* du certificat. - **Enseignement** : dérouler manuellement ce que `openssl verify` automatise ; comprendre la structure ASN.1 et le lien signature ↔ corps (RFC 5280 [4]). ### C2 — Prise en main de Scapy (10 pts) - **But** : renifler la balise UDP/8452 (`sniff(filter="udp port 8452")`), lire la consigne, **forger** le datagramme magique et l'**émettre** (`sr1`) ; la cible répond alors avec le flag. - **Enseignement** : les trois gestes de Scapy — sniff, dissection en couches, forge/émission — socle des challenges MITM suivants [18]. ### C3 — MITM contre HTTP en clair (20 pts) - **Transport** : HTTP clair (port 8453), **aucun TLS**. - **Exploitation** : empoisonnement ARP (`arp_spoof.py` ou bettercap) entre victime et cible, puis sniffing (`sniff_http_flag.py` / tcpdump) ; le flag transite en clair. - **Enseignement** : sans chiffrement de transport, la confidentialité est nulle ; l'interception active (RFC 826 [15]) suffit. - **Contre-mesure** : HTTPS obligatoire + redirection permanente + HSTS (cf. C8). ### C4 — Certificat auto-signé & MITM (15 pts) - **Transport** : TLS 1.2, certificat auto-signé, *non validé par le client*. - **Exploitation** : ARP-spoof du client-victime ; interception transparente (`bettercap`/`mitmproxy`) ; l'attaquant présente son propre certificat auto-signé, que la victime accepte (validation désactivée), et lit le flag. - **Enseignement** : le chiffrement sans **authentification du pair** n'offre aucune protection contre un MITM ; la confiance repose sur la validation de la chaîne de certification [4]. - **Contre-mesure** : validation stricte RFC 5280 (chaîne, SAN, révocation) ; épinglage le cas échéant. ### C5 — Fuite de clé privée (20 pts) - **Transport** : TLS sain, mais la clé privée RSA du portail est exposée sous `/.well-known/backup/server.key`. Le flag est publié chiffré **RSA-OAEP** par `/c/5/flag-feed`. - **Exploitation** : curl -k https://CIBLE:8442/.well-known/backup/server.key -o server.key curl -k https://CIBLE:8442/c/5/flag-feed | jq -r .ciphertext_b64 | base64 -d > flag.bin openssl pkeyutl -decrypt -inkey server.key \ -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -in flag.bin - **Enseignement** : la compromission d'une clé long-terme annule la confidentialité de tout ce qu'elle protège. Ici la protection est *applicative* (un blob) ; le C6 montre la même logique au niveau *transport*. - **Contre-mesure** : cloisonnement des secrets, permissions restrictives, rotation, absence de secret dans une arborescence servie. ### C6 — Absence de forward secrecy / échange RSA (25 pts) - **Transport** : TLS 1.2 négociant un **échange de clés RSA** (suites `kRSA` type `TLS_RSA_WITH_AES_128_CBC_SHA` ; aucun ECDHE/DHE). Le secret pré-maître est chiffré sous la clé publique RSA du serveur et transporté dans le ClientKeyExchange. La clé privée du serveur est exposée sous `/.well-known/backup/server.key`. - **Exploitation** (déchiffrement *a posteriori*) : 1. **enregistrer** le trafic TLS de la victime : `tcpdump -i eth0 -w cap.pcap 'host CIBLE and port 8447'` (au besoin en position MITM, cf. `arp_spoof.py`) ; 2. **faire fuiter** la clé : `curl -k https://CIBLE:8447/.well-known/backup/server.key -o server.key` ; 3. **déchiffrer** hors ligne : Wireshark → *Preferences ▸ Protocols ▸ TLS ▸ RSA keys list* (ajouter `server.key`), ou `tshark -r cap.pcap -o "tls.keys_list:CIBLE,8447,http,server.key" -Y http`. Le flag apparaît en clair dans la réponse HTTP déchiffrée. - **Enseignement** : sans éphémère, la clé long-terme suffit à recalculer *toutes* les sessions passées capturées. La **forward secrecy** (ECDHE) rompt ce lien : chaque session dérive d'un secret éphémère détruit après usage, qu'aucune fuite ultérieure de la clé long-terme ne peut reconstituer [5, 8]. - **Contre-mesure** : imposer des suites **ECDHE** (forward secrecy) ; en TLS 1.3 l'échange RSA statique est purement et simplement supprimé. ### C7 — Logjam / DHE export (25 pts) - **Transport** : TLS 1.2 acceptant des suites **DHE de qualité EXPORT** — groupe Diffie-Hellman de **512 bits** (`EXP-EDH-RSA-DES-CBC-SHA`). Aucune protection contre le *downgrade*. Le flag est porté par le cookie `SESSIONFLAG`. - **Exploitation** : 1. **détecter** : `testssl.sh --logjam CIBLE:8448`, `nmap --script ssl-dh-params -p 8448 CIBLE`, ou `openssl s_client -connect CIBLE:8448 -cipher EXP` (une session à 512 bits s'établit) ; 2. en position **MITM**, forcer la rétrogradation du ClientHello vers la suite DHE_EXPORT (le serveur répond avec son groupe de 512 bits) ; 3. **casser** le logarithme discret du groupe de 512 bits — coûteux une fois, mais **amorti** car le même nombre premier est partagé par d'innombrables serveurs (précalcul), d'où récupération du secret éphémère puis déchiffrement de la session et lecture du cookie [19, 20]. - **Enseignement** : un échange *éphémère* n'assure la forward secrecy que si le groupe est **robuste**. Un groupe export (512 bits), ou même un groupe de 1024 bits partagé, est à la portée d'un précalcul (Logjam) : la FS devient *imparfaite*. C'est le pendant « DH » du C6 « RSA ». - **Contre-mesure** : désactiver toutes les suites EXPORT ; imposer des groupes DH **≥ 2048 bits** (ou uniques par serveur) ; préférer ECDHE. Côté client, refuser les groupes DHE < 1024 bits (correctif Logjam des navigateurs) [19]. ### C8 — SSL stripping (20 pts) - **Transport** : service joignable en clair (port 80), **aucun HSTS**, lien `http://` en dur. - **Exploitation** : MITM + rétrogradation HTTPS→HTTP (`bettercap` caplet `hstshijack`, ou `sslstrip2`) ; le flag transite alors en clair et est capturé. - **Enseignement** : l'attaque de Marlinspike [7] exploite l'*amorçage* en clair. La parade est de rendre HTTPS **obligatoire et mémorisé** côté client. - **Contre-mesure** : `Strict-Transport-Security` (HSTS, RFC 6797) avec `includeSubDomains` et inscription sur la *preload list* [6]. ### C9 — POODLE / SSL 3.0 (25 pts) - **Transport** : SSL 3.0 accepté, suites **CBC**, `TLS_FALLBACK_SCSV` absent → repli forcé possible. Le flag est porté par le cookie `SESSIONFLAG`. - **Exploitation** : forcer le repli SSLv3 (`openssl s_client -ssl3`) ; en position MITM, exploiter l'**oracle de padding CBC** de SSL 3.0 pour reconstituer le cookie octet par octet [9, 10]. - **Enseignement** : SSL 3.0 ne spécifie pas le contenu du bourrage CBC, rendant sa vérification exploitable en oracle. Un protocole obsolète reste dangereux tant qu'un downgrade est possible. - **Contre-mesure** : désactiver SSL 3.0 ; imposer `TLS_FALLBACK_SCSV` (RFC 7507) contre les rétrogradations [9]. ### C10 — BEAST / TLS 1.0 CBC (25 pts) - **Transport** : TLS 1.0 exclusivement, suites **CBC**. En TLS 1.0, l'IV d'un enregistrement est le dernier bloc chiffré du précédent : il est **prévisible**. Le flag est porté par le cookie `SESSIONFLAG`. - **Exploitation** : confirmer (`openssl s_client -tls1`, `testssl.sh`, `nmap --script ssl-enum-ciphers`) ; en position MITM (empoisonnement ARP, `arp_spoof.py`), monter l'attaque à **texte clair choisi adaptatif** (blockwise chosen-boundary) qui aligne la frontière de bloc et devine le cookie octet par octet [13, 14, 16]. - **Enseignement** : un IV prévisible transforme le chiffrement CBC en oracle de texte clair choisi. C'est une faiblesse de **conception protocolaire** (TLS 1.0), distincte de l'oracle de *padding* de POODLE. - **Contre-mesure** : bannir TLS 1.0 ; à défaut, **fractionnement 1/n-1** ou suites AEAD (AES-GCM). TLS 1.1+ referme structurellement BEAST par un IV explicite par enregistrement (RFC 4346 [17]). ### C11 — Heartbleed / OpenSSL 1.0.1f (20 pts) - **Transport** : OpenSSL 1.0.1f, extension **Heartbeat** (RFC 6520) sans contrôle de la longueur annoncée. Le flag réside en mémoire du processus. - **Exploitation** : nmap -p 8445 --script ssl-heartbleed CIBLE # détection # puis PoC RFC 6520 : requête Heartbeat avec payload_length surdimensionné # → lecture hors-limites jusqu'à 64 Ko, où figure le flag. - **Enseignement** : une seule longueur non vérifiée expose des blocs mémoire arbitraires (clés, cookies, données) — illustration canonique d'une vulnérabilité d'implémentation, distincte d'une faiblesse de protocole [3, 11]. - **Contre-mesure** : mise à jour OpenSSL ≥ 1.0.1g ; régénération des secrets potentiellement exposés. ## 7. Barème | Challenge | Points | Compétence évaluée | |-----------|:------:|--------------------| | C1 Prise en main OpenSSL | 10 | Manipulation X.509 / ASN.1 | | C2 Prise en main Scapy | 10 | Sniff / forge / envoi | | C3 MITM HTTP | 20 | Interception active (ARP) | | C4 Cert. auto-signé | 15 | Validation PKI | | C5 Fuite de clé | 20 | Gestion des secrets (applicatif) | | C6 Forward secrecy (échange RSA) | 25 | Déchiffrement a posteriori / PFS | | C7 Logjam (DHE export) | 25 | Downgrade DH + log discret précalculé | | C8 SSL stripping | 20 | Défense MITM / HSTS | | C9 POODLE | 25 | Oracle CBC / obsolescence | | C10 BEAST | 25 | IV prévisible / chosen-plaintext | | C11 Heartbleed | 20 | Divulgation mémoire | | **Total** | **215** | | ## 8. Précautions, éthique et isolement 1. **Isolement absolu** : réseau non routable ; `internal: true` recommandé. 2. **Périmètre** : le portail n'arme le client-victime que vers des IP privées du `LAB_CIDR` — aucune attaque hors laboratoire n'est possible depuis l'appli. 3. **Capacités réseau** : la cible Scapy (C2) et les postes d'attaque requièrent `NET_RAW`/`NET_ADMIN` ; ne les accorder qu'au sein du réseau isolé. 4. **Cadre légal** : environnement contrôlé, consentement pédagogique documenté ; les techniques d'interception ne sont licites que sur une infrastructure dont on a la maîtrise. 5. **Cycle de vie** : détruire les instances vulnérables après le TP (`make clean`) ; conserver des instantanés « propres ». 6. **Débriefing** : chaque challenge se conclut par l'énoncé de sa contre-mesure. ### Caveats de reproductibilité (protocoles obsolètes) Les protocoles hérités sont progressivement retirés des piles récentes : - **C6 (échange RSA)** : les suites `kRSA` sont dépréciées ; réautorisées via `@SECLEVEL=1` dans `ssl_ciphers`. Wireshark ne déchiffre le trafic avec la clé privée **que** pour l'échange RSA (impossible avec ECDHE) — c'est précisément le point pédagogique. - **C7 (Logjam)** : les suites **EXPORT** ont été retirées d'OpenSSL ≥ 1.0.2g. La cible est donc bâtie sur `ubuntu:14.04` (OpenSSL 1.0.1f, qui les embarque encore). Le **cassage du log discret 512 bits** n'est pas exécuté en séance : on s'appuie sur un précalcul/PoC pour le groupe connu (c'est *toute* la logique de Logjam — le précalcul est amorti). L'exercice évaluable est la **détection** et la **démonstration du downgrade** ; le déchiffrement complet est fourni « clé en main » par l'encadrant. - **C9 (SSLv3)** : image `httpd:2.4.29` épinglée. - **C10 (TLS 1.0)** : réactivé via `targets/beast/openssl-lab.cnf` (`MinProtocol= TLSv1`, `@SECLEVEL=0`). Base héritée sinon. - **C11 (Heartbleed)** : OpenSSL 1.0.1f compilé depuis l'archive officielle. Ces cibles n'ont **pas** été construites/exécutées dans l'environnement de préparation (réseau désactivé) : valider le `docker build` sur un hôte outillé avant la séance. ## 9. Reproductibilité et anti-triche Les flags sont chargés depuis l'environnement (`FLAG_C1`…`FLAG_C11`), propagés de façon cohérente au portail **et** à la cible correspondante via `docker-compose`. Pour générer une instance unique par promotion ou par étudiant, définir un `.env` puis `docker compose up -d --build --force-recreate`. La vérification se fait à divulgation nulle (comparaison à temps constant sur empreinte SHA-256, cf. `challenges.py`). ## 10. Références [1] K. Morris, *Infrastructure as Code*, 2ᵉ éd., O'Reilly, 2020. [2] HashiCorp, *Packer Documentation — Immutable Machine Images*, docs.packer.io. [3] R. Seggelmann, M. Tuexen, M. Williams, « Transport Layer Security (TLS) and Datagram TLS (DTLS) Heartbeat Extension », **RFC 6520**, IETF, 2012. [4] D. Cooper *et al.*, « Internet X.509 Public Key Infrastructure Certificate and CRL Profile », **RFC 5280**, IETF, 2008. [5] T. Dierks, E. Rescorla, « The TLS Protocol Version 1.2 », **RFC 5246**, 2008. [6] J. Hodges, C. Jackson, A. Barth, « HTTP Strict Transport Security (HSTS) », **RFC 6797**, IETF, 2012. [7] M. Marlinspike, « New Tricks for Defeating SSL in Practice », *Black Hat DC*, 2009. [8] E. Rescorla, « The Transport Layer Security (TLS) Protocol Version 1.3 », **RFC 8446**, IETF, 2018. [9] B. Möller, A. Langley, « TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks », **RFC 7507**, IETF, 2015. [10] B. Möller, T. Duong, K. Kotowicz, « This POODLE Bites: Exploiting the SSL 3.0 Fallback », Google, 2014. (CVE-2014-3566) [11] MITRE, « CVE-2014-0160 (Heartbleed) », *Common Vulnerabilities and Exposures*, 2014. [12] A. Freier, P. Karlton, P. Kocher, « The Secure Sockets Layer (SSL) Protocol Version 3.0 », **RFC 6101** (Historic), IETF, 2011. [13] T. Duong, J. Rizzo, « Here Come The ⊕ Ninjas » (BEAST), 2011. [14] MITRE, « CVE-2011-3389 » (SSL/TLS 1.0 CBC — BEAST), 2011. [15] D. Plummer, « An Ethernet Address Resolution Protocol », **RFC 826**, IETF, 1982. [16] G. Bard, « A Challenging but Feasible Blockwise-Adaptive Chosen-Plaintext Attack on SSL », *SECRYPT*, 2006. [17] T. Dierks, E. Rescorla, « The TLS Protocol Version 1.1 », **RFC 4346**, 2006. [18] P. Biondi *et al.*, *Scapy Documentation*, scapy.readthedocs.io. [19] D. Adrian *et al.*, « Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice » (Logjam), *ACM CCS*, 2015. [20] MITRE, « CVE-2015-4000 (Logjam) », *Common Vulnerabilities and Exposures*, 2015. ## Annexe A — Flashcards (révision active) 1. **Q :** Que révèle la vérification *manuelle* d'une signature de certificat par rapport à `openssl verify` ? **R :** Le lien concret signature↔corps : parcours ASN.1, extraction du BIT STRING, déchiffrement RSA public, comparaison au condensat du TBSCertificate (C1). 2. **Q :** Quels sont les trois gestes fondamentaux de Scapy ? **R :** Renifler (`sniff`/filtre BPF), disséquer (`pkt[couche]`), forger & émettre (`IP()/UDP()/Raw()`, `sr1`) (C2). 3. **Q :** Pourquoi un flux HTTP en clair n'offre-t-il aucune confidentialité en présence d'un MITM ? **R :** Sans chiffrement de transport, l'empoisonnement ARP (RFC 826) suffit à lire l'intégralité du trafic (C3). 4. **Q :** Quelles sont les trois garanties d'un canal TLS, et laquelle un certificat auto-signé non validé annule-t-il ? **R :** Confidentialité, intégrité, authentification du pair ; c'est l'authentification qui tombe (C4). 5. **Q :** Quelle est la différence entre la fuite de clé du C5 et celle du C6 ? **R :** C5 déchiffre un blob *applicatif* (RSA-OAEP) directement ; C6 déchiffre *a posteriori* une session TLS **enregistrée** parce que l'échange RSA n'offre pas de forward secrecy. 6. **Q :** Pourquoi l'échange RSA (C6) permet-il un déchiffrement rétroactif, et qu'est-ce qui l'empêche ? **R :** Le secret pré-maître est chiffré sous la clé long-terme du serveur ; sa fuite ultérieure le recalcule. L'éphémère **ECDHE** détruit le secret après usage → aucune fuite ne le reconstitue (C6). 7. **Q :** En quoi Logjam (C7) diffère-t-il du C6 alors que DHE est *éphémère* ? **R :** L'éphémère existe mais le groupe DH est rétrogradé à 512 bits ; son log discret est précalculable (amorti sur le premier partagé) → forward secrecy *imparfaite*. Parade : DH ≥ 2048 bits / ECDHE, et pas d'EXPORT (C7). 8. **Q :** Pourquoi le précalcul est-il central dans Logjam ? **R :** Le coût (élevé) du logarithme discret sur un premier donné est payé *une fois*, puis réutilisé contre tous les serveurs partageant ce premier (C7). 9. **Q :** Quel en-tête, et quel mécanisme complémentaire, neutralisent le SSL stripping ? **R :** `Strict-Transport-Security` (HSTS, RFC 6797) + inscription sur la *preload list* pour couvrir la toute première visite (C8). 10. **Q :** Sur quelle propriété du bourrage CBC de SSL 3.0 repose POODLE, et qu'est-ce qui l'empêche ? **R :** Le contenu du padding n'est pas spécifié → oracle exploitable octet par octet ; `TLS_FALLBACK_SCSV` (RFC 7507) bloque le downgrade (C9). 11. **Q :** Qu'est-ce qui rend l'IV prévisible en TLS 1.0 (BEAST), et qu'est-ce qui referme la faille ? **R :** L'IV d'un enregistrement est le dernier bloc chiffré du précédent ; TLS 1.1 impose un IV explicite par enregistrement, ou fractionnement 1/n-1 (C10). 12. **Q :** Heartbleed est-elle une faille de protocole ou d'implémentation ? **R :** D'implémentation (OpenSSL) : la longueur du payload Heartbeat (RFC 6520) n'est pas contrôlée → lecture hors-limites jusqu'à 64 Ko (C11). 13. **Q :** Trois façons distinctes de perdre la confidentialité d'un échange de clés — nommez-les via C6, C7 et le remède commun. **R :** Pas d'éphémère (RSA, C6) ; éphémère trop faible/rétrogradé (DH 512, Logjam C7) ; remède commun : éphémères robustes (ECDHE ou DH ≥ 2048 bits). ## Annexe B — Glossaire des acronymes | Acronyme | Développé | Explication | |----------|-----------|-------------| | **TLS** | *Transport Layer Security* | Protocole de sécurisation du transport, successeur de SSL [5, 8]. | | **SSL** | *Secure Sockets Layer* | Ancêtre de TLS ; SSL 3.0 est obsolète (Historic, RFC 6101) [12]. | | **HTTPS** | *HTTP Secure* | HTTP encapsulé dans TLS. | | **MITM** | *Man-In-The-Middle* | Attaquant interposé sur le canal, lisant/réécrivant le trafic. | | **PKI** | *Public Key Infrastructure* | Infrastructure de gestion des certificats et de la confiance (RFC 5280) [4]. | | **PFS** | *Perfect Forward Secrecy* | La fuite d'une clé long-terme ne compromet pas les sessions passées (C6, C7). | | **CA** | *Certificate Authority* | Autorité qui signe et atteste les certificats. | | **SAN** | *Subject Alternative Name* | Champ du certificat listant les identités (domaines) couvertes. | | **CRL** | *Certificate Revocation List* | Liste des certificats révoqués. | | **ASN.1** | *Abstract Syntax Notation One* | Notation de structure des certificats X.509 (parcourue au C1). | | **TBS** | *To Be Signed (Certificate)* | Corps du certificat effectivement signé (comparé au C1). | | **HSTS** | *HTTP Strict Transport Security* | En-tête forçant l'usage de HTTPS côté client (RFC 6797) [6]. | | **CBC** | *Cipher Block Chaining* | Mode par blocs ; ses défauts de padding/IV fondent POODLE et BEAST. | | **IV** | *Initialization Vector* | Bloc d'amorçage CBC ; sa prévisibilité en TLS 1.0 fonde BEAST [13]. | | **AEAD** | *Authenticated Encryption with Associated Data* | Chiffrement authentifié (AES-GCM) sans oracle CBC. | | **SCSV** | *Signaling Cipher Suite Value* | Suite factice signalant un repli, base de `TLS_FALLBACK_SCSV` (RFC 7507) [9]. | | **RSA** | *Rivest–Shamir–Adleman* | Cryptosystème asymétrique ; en *échange de clés* RSA, pas de forward secrecy (C6). | | **kRSA** | *(key exchange) RSA* | Suites TLS où le secret pré-maître est chiffré sous la clé RSA du serveur (C6). | | **DH** | *Diffie-Hellman* | Échange de clés fondé sur le logarithme discret ; un groupe trop petit (512 bits) est cassable (C7). | | **DHE** | *Diffie-Hellman Ephemeral* | Variante éphémère (porteuse de PFS si le groupe est robuste) ; rétrogradée en EXPORT dans Logjam (C7). | | **ECDHE** | *Elliptic Curve Diffie-Hellman Ephemeral* | Échange éphémère sur courbe elliptique, standard de forward secrecy. | | **EXPORT** | *(suites) EXPORT* | Anciennes suites bridées (clés/groupes ≤ 512 bits) imposées par la réglementation US ; base de Logjam/FREAK [19]. | | **OAEP** | *Optimal Asymmetric Encryption Padding* | Bourrage sûr pour le chiffrement RSA (utilisé au C5). | | **BPF** | *Berkeley Packet Filter* | Langage de filtrage de capture (Scapy `sniff`, `tcpdump`). | | **BEAST** | *Browser Exploit Against SSL/TLS* | Attaque chosen-plaintext sur TLS 1.0/CBC (CVE-2011-3389) [13, 14]. | | **CVE** | *Common Vulnerabilities and Exposures* | Système d'identification public des vulnérabilités (MITRE). | | **RFC** | *Request For Comments* | Document normatif de l'IETF. | | **ARP** | *Address Resolution Protocol* | Protocole IP↔MAC ; son détournement (*spoofing*) positionne le MITM (RFC 826) [15]. | | **IaC** | *Infrastructure as Code* | Gestion déclarative et versionnée de l'infrastructure [1]. | *Environnement à visée strictement pédagogique — ANSSI / CFSSI.*
标签:中间人攻击, 传输层安全(TLS), 安全培训, 安全实验靶场, 安全测试工具, 密码学, 手动系统调用, 版权保护, 系统提示词, 网络安全, 请求拦截, 身份验证强制, 隐私保护