Hoppa yfir í efnið

Samsett lokaverkefni

Nú tengjum við saman vinnulagið úr allri Ýmislegt-leiðinni. Verkefnið hefur sex lög:

villandi skráarending
    ↓
safnskrá
    ↓
mynd og lýsigögn
    ↓
faldar PNG-upplýsingar
    ↓
QR-kóði
    ↓
hávaðasamur texti og Base64
    ↓
fáni

Við fáum tilbúna skrá sem heitir:

gjof.jpg

Öll úttök sem þarf eru sýnd í kaflanum, svo hægt er að leysa verkefnið sem skriflega æfingu þótt einstök verkfæri séu ekki uppsett. Best er þó að skrifa skipanirnar í lausnadagbók eins og um raunverulega CTF-skrá væri að ræða.

Verkefnisgögnin eru ótraust inntak

Við keyrum engar útdregnar skrár, opnum engar afkóðaðar vefslóðir og drögum safnskrár aðeins út í tóma möppu. Dæmið er tilbúið og inniheldur engar persónuupplýsingar.

Reglur verkefnisins

  • Fáninn er á sniðinu gg{...}.
  • Við megum nota staðbundin verkfæri og Python.
  • Við eigum að geta endurtekið hvert skref.
  • Við eigum að útskýra af hverju næsta próf var valið.
  • Handahófskennt „keyrði öll tól“ fær ekki fulla lausn.

Búum til vinnumöppu og varðveitum afrit:

mkdir -p lokaverkefni/{inntak,vinnu,nidurstodur}
cp gjof.jpg lokaverkefni/inntak/
cp gjof.jpg lokaverkefni/vinnu/gjof.jpg
cd lokaverkefni

Skráum kássu svo við getum athugað vinnuafritið síðar:

sha256sum inntak/gjof.jpg vinnu/gjof.jpg

Kássurnar eiga að vera eins áður en greining hefst.

Lag 1: skráin er ekki það sem nafnið segir

Fyrsta próf:

file vinnu/gjof.jpg

Úttak:

vinnu/gjof.jpg: Zip archive data, at least v2.0 to extract

Hex-skoðun staðfestir hausinn:

xxd -l 16 vinnu/gjof.jpg
00000000: 504b 0304 1400 0000 0800 2a51 2a5b  .........*Q*[

50 4b 03 04 er algengt ZIP-auðkenni.

Æfing: næsta skref

Æfing 1

Hvað vitum við, hvað vitum við ekki og hvaða skipun er skynsamleg næst?

Lausn við æfingu 1

Við vitum:

  • innihaldið lítur út eins og ZIP,
  • .jpg-endingin er villandi,
  • file og hausinn styðja sömu niðurstöðu.

Við vitum ekki:

  • hvort safnið sé heilt,
  • hvaða skrár eru inni,
  • hvort slóðir eða stærðir séu öruggar,
  • hvort safnið sé lykilorðsvarið.

Við skoðum skráalistann án útdráttar:

unzip -l vinnu/gjof.jpg
unzip -t vinnu/gjof.jpg

Við endurnefnum ekki endilega strax. Flest ZIP-tól lesa innihaldið þrátt fyrir endinguna, og núverandi heiti minnir okkur á blekkinguna.

Lag 2: skoðum safnið

unzip -l sýnir:

Archive:  vinnu/gjof.jpg
  Length      Date    Time    Name
---------  ---------- -----   ----
      118  2026-07-10 10:00   leidbeining.txt
    18432  2026-07-10 10:00   mynd.png
---------                     -------
    18550                     2 files

Listinn hefur:

  • aðeins tvær litlar skrár,
  • engar algildar slóðir,
  • ekkert ..,
  • engin augljós stærðarmerki þjöppunarsprengju.

Við drögum út í nýja möppu:

mkdir -p vinnu/lag-02
unzip vinnu/gjof.jpg -d vinnu/lag-02
file vinnu/lag-02/*

leidbeining.txt segir:

Augun sjá myndina, en bláa rásin geymir síðasta orðið.
Lestu lýsinguna áður en þú leitar í bitum.

Æfing: þrjár tilgátur

Æfing 2

Skrifaðu þrjár afmarkaðar tilgátur sem textinn styður og raðaðu ódýrum prófum á þær.

Lausn við æfingu 2

Mögulegar tilgátur:

  1. „Lýsinguna“ vísar á lýsigagnareit, til dæmis Description eða Comment.
  2. „Bláa rásin“ vísar á B-rás RGB-myndarinnar.
  3. „Síðasta orðið“ vísar á gildislægsta bita, LSB, frekar en síðasta sýnilega orð textaskrárinnar.

Ódýr röð prófa:

exiftool vinnu/lag-02/mynd.png
magick vinnu/lag-02/mynd.png -channel B -separate nidurstodur/bla.png
zsteg vinnu/lag-02/mynd.png

Lýsigögn eru ódýrasta prófið og textinn segir beinlínis að lesa lýsinguna áður en bitaleit hefst.

Lag 3: lýsigögnin velja nákvæma leið

exiftool sýnir:

File Type                       : PNG
Image Width                     : 512
Image Height                    : 512
Color Type                      : RGB
Description                     : b1,b,lsb,xy — úttakið er önnur PNG-mynd
Software                        : Synthetic CTF Builder

Við túlkum:

b1    eitt bitaplan
a?    engin alfa-rás samkvæmt Color Type
b     bláa rásin
lsb   gildislægsti biti
xy    lestrarröð eftir x og síðan y samkvæmt verkfærinu

Vísbendingin passar við zsteg-heiti. Við prófum markvisst:

zsteg vinnu/lag-02/mynd.png

Stytt úttak:

b1,b,lsb,xy  .. file: PNG image data, 290 x 290, 8-bit grayscale
b2,r,msb,yx  .. text: "q!A"

Æfing: veldu niðurstöðu

Æfing 3

Hvora zsteg-niðurstöðuna skoðum við fyrst og hvernig staðfestum við hana?

Lausn við æfingu 3

Við veljum:

b1,b,lsb,xy .. file: PNG image data

Hún passar nákvæmlega við:

  • Description-reitinn,
  • bláu rásina úr leiðbeiningunni,
  • LSB-vísbendinguna,
  • loforðið um að úttakið sé PNG.

Við drögum hana út:

zsteg -E 'b1,b,lsb,xy' vinnu/lag-02/mynd.png \
  > nidurstodur/falin.png
file nidurstodur/falin.png
pngcheck -v nidurstodur/falin.png

Stutta textabrotið q!A hefur hvorki stuðning úr vísbendingum né sterkt skráarsnið og gæti verið tilviljun.

Lag 4: myndin er QR-kóði

file staðfestir gilda PNG-mynd. Þegar hún er opnuð sést QR-kóði, en við þurfum ekki að nota síma eða láta forrit opna innihaldið sjálfkrafa.

zbarimg --raw nidurstodur/falin.png \
  > nidurstodur/qr.txt

qr.txt inniheldur:

# parts are shuffled
part=3/4 data=X2xvZ3
note=sort numerically; join only data
part=1/4 data=Z2d7Z2
part=4/4 data=VtfQ==
part=2/4 data=9nbl9p

Þetta er ekki vefslóð. Það er lítið sérsnið með fjórum hlutum og einni athugasemd.

Æfing: af hverju ekki einföld skeljaröð?

Æfing 4

Af hverju er sort qr.txt | cut -d= -f3 brothætt lausn? Hvaða atriði þarf þáttari að staðfesta?

Lausn við æfingu 4

Skipunin er brothætt vegna þess að:

  • athugasemda- og note-línur fylgja ekki gagnasniðinu,
  • venjuleg textaröðun bilar þegar hlutanúmer verða 10, 11 og svo framvegis,
  • Base64-gildi getur sjálft endað á =,
  • cut -f3 gerir ráð fyrir nákvæmum fjölda =-tákna,
  • ekkert staðfestir að hlutar 1–4 séu allir til staðar eða aðeins einu sinni.

Þáttari ætti að staðfesta:

  • alla gagnalínuna,
  • númer hluta og heildarfjölda,
  • að númer séu einkvæm,
  • að nákvæmlega hlutar 1, 2, 3 og 4 séu til,
  • leyfilegt stafasett gagnanna,
  • að aðrar línur séu annaðhvort skilgreindar athugasemdir eða skráðar sem ógildar.

Lag 5: hreinsum og röðum með Python

Skrifum lítið forrit, leysa.py:

import base64
import re
from pathlib import Path

mynstur = re.compile(
    r"^part=(?P<numer>[0-9]+)/(?P<heild>[0-9]+) "
    r"data=(?P<data>[A-Za-z0-9+/=]+)$"
)

hlutar = {}
heild = None
hunsadar = []

for linunumer, lina in enumerate(
    Path("nidurstodur/qr.txt").read_text(encoding="utf-8").splitlines(),
    start=1,
):
    if not lina or lina.startswith("#") or lina.startswith("note="):
        hunsadar.append((linunumer, lina))
        continue

    m = mynstur.fullmatch(lina)
    if not m:
        raise ValueError(f"Ógild lína {linunumer}: {lina!r}")

    numer = int(m.group("numer"))
    ny_heild = int(m.group("heild"))

    if heild is None:
        heild = ny_heild
    elif ny_heild != heild:
        raise ValueError("Ósamræmdur heildarfjöldi")

    if numer in hlutar:
        raise ValueError(f"Tvítekinn hluti: {numer}")

    hlutar[numer] = m.group("data")

if heild is None or heild < 1:
    raise ValueError("Engir gagnahlutar fundust")

vaentanleg = set(range(1, heild + 1))
if set(hlutar) != vaentanleg:
    raise ValueError(
        f"Vantar eða fékk óvænta hluta: {set(hlutar) ^ vaentanleg}"
    )

samsett = "".join(hlutar[numer] for numer in range(1, heild + 1))

try:
    afkodad = base64.b64decode(samsett, validate=True)
except ValueError as villa:
    raise ValueError("Ógilt Base64 eftir samsetningu") from villa

try:
    texti = afkodad.decode("ascii")
except UnicodeDecodeError as villa:
    raise ValueError("Afkóðuð gögn eru ekki ASCII") from villa

print("Raðað Base64:", samsett)
print("Hunsaðar línur:", hunsadar)
print("Niðurstaða:", texti)

Keyrum úr lokaverkefni/:

python3 leysa.py

Úttak:

Raðað Base64: Z2d7Z29nbl9pX2xvZ3VtfQ==
Hunsaðar línur: [(1, '# parts are shuffled'), (3, 'note=sort numerically; join only data')]
Niðurstaða: gg{gogn_i_logum}

Æfing: staðfestu fánann

Æfing 5

Hvaða athuganir styðja að gg{gogn_i_logum} sé lokaúttakið en ekki tilviljunarkenndur texti?

Lausn við æfingu 5
  • QR-gögnin segja skýrt að raða hlutum tölulega og tengja aðeins data.
  • Allir fjórir hlutar eru til nákvæmlega einu sinni.
  • Samsetta runan er gilt Base64 með réttri fyllingu.
  • Base64-afkóðunin er gildur ASCII-texti.
  • Textinn passar nákvæmlega við skilgreint fánasnið gg{...}.
  • Ferlið er endurtakanlegt frá QR-úttakinu með stuttu forriti.

Við staðfestum einnig handvirkt:

printf '%s' 'Z2d7Z29nbl9pX2xvZ3VtfQ==' | base64 -d
gg{gogn_i_logum}

Lausnadagbókin í heild

Stutt en endurtakanleg dagbók gæti verið:

Skref Athugun Tilgáta Prófun Niðurstaða
1 .jpg, en file segir ZIP Ending er blekking xxd -l 16 ZIP-haus staðfestur
2 Tvær litlar, eðlilegar slóðir Öruggt að draga í tóma möppu unzip -t, unzip -d Texti og PNG
3 Texti nefnir lýsingu, blátt og síðast Lýsigögn velja LSB-rás exiftool b1,b,lsb,xy
4 zsteg sér PNG í þeirri rás Falda skráin er næsta lag zsteg -E, file, pngcheck Gild QR-mynd
5 QR inniheldur fjóra ruglaða hluta Raða og tengja gögn Staðfest Python-forrit Gilt Base64
6 Afkóðun passar fánasniði Lokafáni fundinn Sjálfstæð base64 -d prófun gg{gogn_i_logum}

Þessi tafla sýnir rauða þráðinn. Hvert tól svarar spurningu sem fyrri athugun vakti.

Hvað hefði getað farið úrskeiðis?

Við treystum endingunni

Þá hefðum við reynt myndskoðara og talið skrána skemmda. file var ódýrara og nákvæmara fyrsta próf.

Við drógum safnið út án skoðunar

Þá hefðum við ekki vitað hvort það innihéldi hættulegar slóðir eða gríðarlegar skrár.

Við keyrðum zsteg -a og völdum fyrsta orðið

Þá hefði q!A getað sent okkur í kanínuholu. Lýsigögnin gáfu nákvæma rás.

Við skönnuðum QR með síma

Síminn hefði mögulega boðið að opna slóð eða framkvæma aðgerð. zbarimg --raw gaf okkur textann án sjálfvirkrar aðgerðar.

Við límdum línur með augunum

Þá hefðum við getað ruglað röð, tekið note með eða misst Base64-fyllingu. Forritið staðfesti uppbygginguna.

Við skrifuðum aðeins niður fánann

Þá væri ómögulegt að sjá hvort lausnin kom úr gögnunum eða ágiskun. Lausnadagbókin varðveitir röksemdakeðjuna.

Viðbótaræfingar

Þegar grunnlausnin er skýr getum við breytt afriti af gervigögnunum og athugað hvort lausnin hafni villum:

  1. Fjarlægja part=3/4 — forritið á að kvarta yfir vöntun.
  2. Tvírita part=2/4 — forritið á að hafna tvítekningu.
  3. Breyta einum Base64-staf í ! — reglulega segðin eða afkóðun á að hafna.
  4. Breyta 3/4 í 3/5 — heildarfjöldi á að verða ósamræmdur.
  5. Setja ../ut.txt inn í tilbúinn ZIP-lista — útdráttur á að stöðvast fyrir skoðun.

Þetta eru ekki aðeins „neikvæð próf“. Þau sýna hvaða forsendur lausnin okkar verndar.

Samantekt

Í lokaverkefninu notuðum við:

  • sha256sum til að auðkenna vinnuafrit,
  • file og xxd til að finna raunverulegt skráarsnið,
  • unzip -l og unzip -t fyrir örugga safnskoðun,
  • exiftool til að finna markvissa vísbendingu,
  • rásir og gildislægsta bita til að finna falda PNG-mynd,
  • zbarimg --raw til að afkóða QR án sjálfvirkrar aðgerðar,
  • reglulega segð og Python til að staðfesta, raða og tengja gögn,
  • Base64-afkóðun og fánasnið til lokastaðfestingar,
  • lausnadagbók til að tengja athuganir, tilgátur og prófanir.

Mikilvægasti lærdómurinn er ekki hvaða skipun fann fánann. Hann er að við gátum útskýrt af hverju við keyrðum hana, hvað úttakið sýndi og hvernig næsta skref fylgdi af því.

Í síðasta kaflanum veljum við vettvanga og verkefni til að æfa áfram án þess að týnast í endalausum verkfæralistum.