Italy - Silent Signals (network)
Inspect all DNS responses, and realise that there is a character from the flag encoded at offset 0x55 of each of the dns response packets. Let's look at the first two:


I then got GPT to generate me the solve script:
#!/usr/bin/env python3
"""
extract_flag.py
Usage:
python extract_flag.py capture.pcap
python extract_flag.py capture.pcap --base payload
python extract_flag.py capture.pcap --base packet # default
python extract_flag.py capture.pcap --base udp
python extract_flag.py capture.pcap --offset 0x55
Description:
Reads the pcap and extracts the byte at offset (default 0x55)
for each DNS/UDP packet. By default the offset is applied to the
entire raw packet (base='packet'). Use base='payload' to apply the
offset relative to the UDP payload start (useful for application-layer data).
"""
import sys
import argparse
from scapy.all import rdpcap, UDP, DNS, Raw
def is_dns_packet(pkt):
# Consider packets with DNS layer or UDP port 53
return (DNS in pkt) or (UDP in pkt and (pkt[UDP].sport == 53 or pkt[UDP].dport == 53))
def main():
p = argparse.ArgumentParser(description="Extract byte at offset 0x55 from DNS/UDP packets")
p.add_argument("pcap", help="pcap file to read")
p.add_argument("--offset", default="0x55", help="offset (hex like 0x55 or decimal like 85)")
p.add_argument("--base", choices=["packet", "udp", "payload"], default="packet",
help=("where to apply offset:\n"
" packet - offset from start of entire packet (default)\n"
" udp - offset from start of UDP header\n"
" payload - offset from start of UDP payload (application layer)"))
args = p.parse_args()
# parse offset
if isinstance(args.offset, str) and args.offset.startswith("0x"):
offset = int(args.offset, 16)
else:
offset = int(args.offset)
try:
packets = rdpcap(args.pcap)
except FileNotFoundError:
print(f"File not found: {args.pcap}", file=sys.stderr)
sys.exit(2)
except Exception as e:
print("Error reading pcap:", e, file=sys.stderr)
sys.exit(2)
extracted = bytearray()
for i, pkt in enumerate(packets, start=1):
if not is_dns_packet(pkt):
continue
raw = bytes(pkt) # full packet bytes
base_off = 0
if args.base == "udp":
if UDP in pkt:
# find start of UDP header in raw bytes:
# locate the UDP header by searching for the UDP source and dest ports in bytes
# fallback: try to compute via IP header length if present
try:
ip_layer = pkt.payload # could be IP, IPv6, etc.
# Scapy gives access to raw bytes for the UDP header via pkt[UDP].build() not safe here.
# Simpler and robust approach: locate pkt[UDP].sport and dport in the raw stream
sport = pkt[UDP].sport
dport = pkt[UDP].dport
# 2-byte numbers in network order
sport_bytes = sport.to_bytes(2, "big")
dport_bytes = dport.to_bytes(2, "big")
# search for sport+dport or dport+sport sequence near each other
candidate = raw.find(sport_bytes + dport_bytes)
if candidate != -1:
base_off = candidate
else:
# try dport+sport
candidate = raw.find(dport_bytes + sport_bytes)
base_off = candidate if candidate != -1 else 0
except Exception:
base_off = 0
else:
base_off = 0
elif args.base == "payload":
# find UDP payload start (Raw.load) if present
if Raw in pkt:
try:
payload = pkt[Raw].load
pos = raw.find(payload)
base_off = pos if pos != -1 else 0
except Exception:
base_off = 0
else:
base_off = 0
target_index = base_off + offset
if target_index < len(raw):
extracted.append(raw[target_index])
else:
# skip if packet too short
# optionally you could pad or raise a warning
# print(f"Packet #{i} too short for offset {hex(target_index)} (len {len(raw)})", file=sys.stderr)
pass
# Try to decode as ASCII printable
try:
s = extracted.decode("ascii")
# if it contains unprintable bytes, show hex as well
if all(32 <= b < 127 for b in extracted):
print("Flag (ASCII):", s)
else:
print("Extracted bytes (ASCII with non-printables present):")
print(s)
print("Hex:", extracted.hex())
except Exception:
print("Extracted bytes (hex):", extracted.hex())
# also try best-effort printable representation
printable = ''.join(chr(b) if 32 <= b < 127 else '.' for b in extracted)
print("Printable rep:", printable)
if __name__ == "__main__":
main()
# CSG_FLAG{Y0u_N33d_T0_Parse_DNS_TTL}Last updated