Universal 2026 — Carrier Lock Çözüm Yazısı

Otomatik olarak çerçevelenmeyi reddeden ham bir uydu aşağı bağlantısı. CCSDS telemetri yapısını tanıyın, PN9 sözde-rastgeleleştiricisini geri alın, uzay paketi akışını yeniden birleştirin; bayrak, parçalanmış bir mesaj taşıyan tek bir sanal kanaldan çıkıyor.

4 dk okuma
ibrahimsql
748 kelime

Universal 2026 — Carrier Lock

Bir uzay adli bilişim sorusu. Bize bir yer istasyonunun zayıf, tekrarlayan bir yayından çektiği "ham bitler" veriliyor — çerçeveleme yok, üst veri yok, sadece bir blob. Görev, taşıyıcıya kilitlenip ne taşıdığını okumak.

  • Etkinlik: Universal 2026
  • Kategori: Adli Bilişim (Forensics)
  • Dosya: downlink.bin
  • Bayrak formatı: uctf{...}

1. Blob

Text
$ file downlink.bin
downlink.bin: data
$ ls -l downlink.bin
-rw-r--r--  1 user  staff  22616 downlink.bin

Tanınabilir hiçbir kapsayıcısı olmayan, yüksek entropili 22.616 bayt "veri". İpucu, otomatik olarak çerçevelenemediğini söylüyordu ki bu uzay telemetrisi için normaldir: bir kod çözücü, analistin önce bulması gereken bir işaretçiye senkronize olur.

2. Çerçeve işaretçisini bulma

CCSDS telemetri transfer çerçeveleri 4 baytlık bir Attached Sync Marker ile sınırlandırılır. Bunu aradığımızda eşit aralıklı isabetler dönüyor:

Python
data = open("downlink.bin", "rb").read()
i, offsets = 0, []
while True:
    j = data.find(b"\x1a\xcf\xfc\x1d", i)
    if j == -1:
        break
    offsets.append(j)
    i = j + 4
print(len(offsets))                 # 22
print([b - a for a, b in zip(offsets, offsets[1:])])   # [1028, 1028, ...]

1A CF FC 1D CCSDS Attached Sync Marker'dır. Toplam 22 tane var, her biri 1028 bayt arayla: 4 baytlık işaretçi artı 1024 baytlık transfer çerçevesi. Bu da 22 × 1028 = 22.616 bayt eder — dosyanın tamamı, tam olarak.

Yani yakalama, 22 sabit uzunlukta transfer çerçevesidir. Ama çerçeve gövdeleri hâlâ gürültü, çünkü CCSDS çerçeveleri iletilmeden önce sözde-rastgeleleştirilir.

3. PN9 sözde-rastgeleleştiricisini geri alma

CCSDS, uzun özdeş bit dizilerinden kaçınmak için bir PN9 rastgeleleştiricisi (polinom x⁸ + x⁷ + x⁵ + x³ + 1) uygular. Bu, sabit bir diziyle bayt bazında XOR'dur ve her transfer çerçevesinin başında sıfırlanır. LFSR'yi yeniden uygulayıp her 1024 baytlık gövdeyi XOR'lamak bunu geri alır:

Python
def pn9(n):
    reg, out = 0xFF, bytearray()
    for _ in range(n):
        b = 0
        for _ in range(8):
            b = (b << 1) | (reg & 1)
            fb = ((reg >> 7) ^ (reg >> 5) ^ (reg >> 3) ^ (reg >> 0)) & 1
            reg = ((reg >> 1) | (fb << 7)) & 0xFF
        out.append(b)
    return bytes(out)
 
ks = pn9(1024)
frames = [bytes(a ^ b for a, b in zip(data[o+4:o+1028], ks)) for o in offsets]

Artık her çerçevenin ilk altı baytı temiz biçimde çözülüyor — bunlar CCSDS birincil başlığıdır:

frame 0  header: 0a b0 00 00 18 00
frame 1  header: 0a b0 01 01 18 0e
frame 2  header: 0a b0 02 02 18 ...

Sürüm bitleri, uzay aracı kimliği (171) ve çerçeve sayaçları olması gerektiği gibi artıyor. Rastgeleleştirici gitti ve çerçeveler gerçek.

4. Paket akışını yeniden birleştirme

Her çerçevenin 1018 baytlık veri alanı (1024 eksi 6 baytlık birincil başlık) kendi içinde tamamlanmış değildir. Çerçeve çerçeve ayrıştırmak frame 1'de anında taşır — paket akışı çerçeve sınırları boyunca süreklidir. Veri alanlarını tek bir akışta birleştirip CCSDS Space Packet yapısıyla (6 baytlık başlık) yürümek bunu düzeltir:

Python
stream = b"".join(f[6:] for f in frames)
o, counts = 0, {}
while o + 6 <= len(stream):
    b0, b1, b2, b3, b4, b5 = stream[o:o+6]
    apid = ((b0 & 0x07) << 8) | b1
    dl = ((b4 << 8) | b5) + 1          # uzunluk alanı (boyut - 1)
    payload = stream[o+6:o+6+dl]
    counts[apid] = counts.get(apid, 0) + 1
    o += 6 + dl
 
print(counts)
# {200: 424, 300: 424, 400: 424, 250: 9, 2047: 1}

Üç uygulama kimliği baskın (200, 300, 400 ve her biri 424 paket) — bu ev idaresi telemetrisi, tekrarlayan ve sıkıcı bir desen. APID 2047 tek bir 0x90 baytı paketi, saf dolgu. Ve APID 250 tam dokuz kez görünüyor. İşte ilginç olan bu.

5. APID 250 üzerindeki mesaj

Sadece APID-250 yüklerini çıkarıp paket sıra sayısına (başlığın üçüncü baytı) göre sıralamak mesajı yeniden birleştirir:

msg = [(pkt_seq, payload) for ... if apid == 250]
flag = "".join(p for _, p in sorted(msg))
print(flag)
Text
# dosya sırası (ev idaresiyle iç içe, sırasız):
# 'uctf'  '1g'  '{s1g'  'n4l_'  '1n}'  '0wn_'  '0r'  'unkn'  '0f_'
# sıra sayısına göre 0..8 sıralandıktan sonra:
uctf{s1gn4l_0f_unkn0wn_0r1g1n}

Bayrak metni dokuz küçük pakete bölünmüş ve telemetri akışı boyunca dağıtılmıştı. 0'dan 8'e kadar sıra sayıları onları tekrar sıraya koyuyor.

6. Bayrak

uctf{s1gn4l_0f_unkn0wn_0r1g1n}

Bilinmeyen kaynaklı sinyal. Zincir — senkron işaretçisi, PN9 geri rastgeleleştirmesi, sürekli paket yeniden birleştirme, sıra düzeni — herhangi bir CCSDS yakalaması için standart iş akışıdır. Üç aşamalı tuzak şudur: çerçeveler işaretçiyi bulana kadar gürültü gibi görünür, geri rastgeleleştirene kadar çöp gibi görünür ve veri alanlarını çerçeve başına değil de tek bir sürekli akış olarak ele alana kadar bozuk görünür.

---
Bu yazıyı paylaş:
TwitterLinkedInFacebook

Ne düşünüyorsun?

Tepki bırakarak geri bildirim ver

İlgili Yazılar