Git og útgáfustjórnun
CTF-verkefni og öryggistól eru oft birt sem Git-hirslur. Git hjálpar okkur að sækja kóða, sjá hvað breyttist milli útgáfa og vinna án þess að glata eigin breytingum. Í sumum verkefnum er útgáfusagan sjálf hluti af þrautinni: skrá sem var eytt úr nýjustu útgáfu getur enn verið varðveitt í eldri staðfestingu.
Git er hins vegar ekki það sama og GitHub. Git er dreift útgáfustjórnunarkerfi (e. version control system) sem keyrir staðbundið. GitHub, GitLab og sambærilegar þjónustur hýsa Git-hirslur og bæta við vefviðmóti, aðgangsstýringu og samstarfsverkfærum.
Að sækja kóða er ekki það sama og að treysta honum
git clone sækir skrár og sögu. Keyrum ekki sjálfkrafa install.sh, make, Python-pakka, Dockerfile eða annað úr óþekktri hirslu. Lesum fyrst skrárnar, notum uppfært Git og vinnum með ótraustan kóða í einangruðu umhverfi.
Hvað geymir Git?
Git-hirsla (e. Git repository) er mappa með verkefnisskrám og falinni .git/-möppu. .git/ geymir meðal annars staðfestingar, tilvísanir í greinar og stillingar hirslunnar.
verkefni/
├── .git/ ← Git-gagnagrunnurinn
├── README.md
├── app.py
└── tests/
Venjulegu skrárnar sem við breytum mynda vinnutréð (e. working tree). Git greinir þrjú mikilvæg ástand:
vinnutré ──git add──► sviðsetning ──git commit──► saga hirslunnar
- Vinnutré: núverandi skrár á diskinum.
- Sviðsetningarsvæði (e. staging area eða index): nákvæmlega þær breytingar sem eiga að fara í næstu staðfestingu.
- Git-staðfesting (e. commit): varðveitt mynd af sviðsettum breytingum ásamt höfundi, tíma, lýsingu og tilvísun í fyrri staðfestingu.
Vissir þú?
Linus Torvalds hóf þróun Git árið 2005 þegar Linux-kjarnaverkefnið þurfti nýtt útgáfustjórnunarkerfi. Hönnunin miðaðist frá byrjun við mjög stórt og dreift verkefni.
Stofnum örugga æfingahirslu
Búum til hirslu sem við megum breyta og eyða:
mkdir -p ~/ctf/git-aefing
cd ~/ctf/git-aefing
git init -b main
git init býr til .git/ en staðfestir engar skrár. Skoðum stöðuna:
git status
ls -la
Ný Git-uppsetning þarf nafn og netfang fyrir höfund staðfestinga. Fyrir kennslu getum við stillt þau aðeins í þessari hirslu:
git config user.name 'CTF nemandi'
git config user.email 'nemandi@example.invalid'
Án --global gilda stillingarnar aðeins hér. Skoðum hvaðan stillingar koma:
git config --list --show-origin
Höfundarreitur er ekki sannvottun
Nafn og netfang í venjulegri Git-staðfestingu eru textagildi sem notandi getur stillt. Þau sanna ekki hver framkvæmdi breytinguna. Undirritaðar staðfestingar og aðgangsskrár hýsingarþjónustu geta veitt frekari staðfestingu, en eru sérstakt viðfangsefni.
Frá skrá að staðfestingu
Búum til tvær skrár:
printf '# Git-æfing\n' > README.md
printf 'status=byrjun\n' > settings.txt
git status sýnir þær sem óraktar (e. untracked):
git status --short
?? README.md
?? settings.txt
Sviðsetjum og staðfestum:
git add README.md settings.txt
git status --short
git commit -m 'Bæti við fyrstu æfingaskrám'
Eftir git add merkir A að skrárnar séu sviðsettar. git commit varðveitir aðeins sviðsetta ástandið, ekki allar handahófskenndar breytingar í vinnutrénu.
Hvað breyttist?
Bætum við línu:
printf 'mode=training\n' >> settings.txt
Ósviðsettar breytingar:
git diff
Sviðsetjum skrána:
git add settings.txt
Nú sýnir venjulegt git diff ekkert, því breytingin er komin á sviðsetningarsvæðið. Berum sviðsetninguna saman við síðustu staðfestingu:
git diff --staged
Þessi aðgreining er lykilatriði:
git diff vinnutré ↔ sviðsetning
git diff --staged sviðsetning ↔ síðasta staðfesting
Staðfestum:
git commit -m 'Set æfingaham'
Æfing 1: tvær breytingar, ein staðfesting
Veldu nákvæmlega hvað fer í söguna
Breyttu bæði README.md og settings.txt. Sviðsettu aðeins README.md, staðfestu og sýndu síðan að breytingin í settings.txt sé enn í vinnutrénu.
Lausn
printf 'Þetta er örugg æfing.\n' >> README.md
printf 'color=blue\n' >> settings.txt
git add README.md
git diff --staged
git commit -m 'Útskýri æfinguna'
git status --short
git diff settings.txt
Eftir staðfestinguna á settings.txt enn að birtast sem breytt skrá. Þetta sýnir að git commit tók aðeins sviðsettu breytinguna.
Lesum söguna
Stutt yfirlit:
git log --oneline --decorate --graph --all
Nákvæm staðfesting:
git show HEAD
git show --stat HEAD
HEAD vísar venjulega á staðfestinguna sem núverandi grein stendur á. HEAD~1 er foreldri hennar:
git show HEAD~1
git diff HEAD~1 HEAD
Sýnum skrá eins og hún var, án þess að breyta vinnutrénu:
git show HEAD~1:settings.txt
Almenna sniðið er:
git show STAÐFESTING:SLÓÐ
Þetta er sérstaklega gagnlegt í CTF þegar við viljum lesa gamla skrá en ekki skipta allri hirslunni yfir í eldri útgáfu.
Tætigildi staðfestinga
Hver staðfesting hefur auðkenni sem lítur út eins og langt tætigildi. Auðkennið byggist meðal annars á verkefnistrénu, foreldri, höfundi, tíma og skilaboðum. Ef innihaldið breytist verður auðkennið annað.
Stutt auðkenni eins og a1b2c3d er þægileg framsetning svo lengi sem það er einkvæmt í hirslunni:
git rev-parse HEAD
git rev-parse --short HEAD
Auðkennið er ekki leyndarmál og staðfesting er ekki dulkóðun.
Endurheimtum skrá úr sögunni
Búum til og staðfestum tilbúna vísbendingu:
printf 'gg{git_geymir_soguna}\n' > clue.txt
git add clue.txt
git commit -m 'Bæti við tímabundinni vísbendingu'
Eyðum henni og staðfestum eyðinguna:
git rm clue.txt
git commit -m 'Fjarlægi vísbendingu úr nýjustu útgáfu'
ls finnur ekki skrána, en sagan geymir hana:
git log --all -- clue.txt
git log --diff-filter=D --summary --all
git show HEAD~1:clue.txt
Við getum endurheimt hana í vinnutréð úr tiltekinni staðfestingu:
git restore --source=HEAD~1 -- clue.txt
Síðan er hún óstaðfest breyting; git status segir nákvæmlega stöðuna.
Æfing 2: finndu eydda fánann
Leitaðu í sögu, ekki aðeins nýjustu útgáfu
Notaðu skipanirnar að ofan til að finna staðfestinguna þar sem clue.txt var eytt og prenta innihald skrárinnar úr foreldrinu án þess að skipta um grein.
Lausn
git log --diff-filter=D --summary --all
git show HEAD~1:clue.txt
Í flóknari sögu notum við auðkennið úr git log í stað HEAD~1:
git show <auðkenni-fyrri-staðfestingar>:clue.txt
Greinar
Git-grein (e. branch) er hreyfanleg tilvísun á staðfestingu. Grein gerir okkur kleift að vinna að breytingu án þess að færa aðalgreinina strax.
Skoðum greinar og búum til nýja:
git branch
git switch -c tilraun
Breyting og staðfesting á tilraun:
printf 'experiment=true\n' >> settings.txt
git add settings.txt
git commit -m 'Prófa tilraunastillingu'
Förum aftur á aðalgrein. Nýjar Git-hirslur geta kallað hana main eða master; git branch sýnir nafnið:
git switch main
Sameinum síðan ef við viljum halda breytingunni:
git merge tilraun
Ef báðar greinar breyta sömu línum getur Git ekki valið sjálft. Þá merkir það árekstur (e. merge conflict) í skránni:
<<<<<<< HEAD
texti á núverandi grein
=======
texti á hinni greininni
>>>>>>> tilraun
Við breytum skránni í rétta lokaútgáfu, fjarlægjum merkin, sviðsetjum og staðfestum tvinnunina.
Ekki keyra kóða bara vegna þess að hann er á annarri grein
Greinar úr ótraustri hirslu eru enn ótraustur kóði. git switch getur skipt út vinnuskrám og því skoðum við stöðu og varðveitum eigin breytingar áður en við skiptum.
Afturkallanir án glundroða
Git býður margar skipanir sem hljóma svipað. Byrjum á þeim afmörkuðu:
Hendum ósviðsettri breytingu
git diff -- settings.txt
git restore -- settings.txt
Þetta skrifar síðasta sviðsetta eða staðfesta ástand yfir breytinguna í vinnutrénu. Óstaðfesta breytingin getur glatast.
Tökum skrá af sviðsetningarsvæðinu
git restore --staged settings.txt
Skráin helst breytt í vinnutrénu en fer ekki í næstu staðfestingu.
Búum til nýja staðfestingu sem snýr annarri við
git revert <auðkenni>
revert varðveitir söguna og bætir við andhverfri breytingu. Það hentar betur en að endurskrifa sameiginlega sögu.
reset --hard getur eytt vinnu
git reset --hard færir tilvísun og skrifar yfir vinnutré og sviðsetningu. git clean -fd eyðir óröktuðum skrám og möppum. Notum þessar skipanir ekki sem almenna „laga Git“-lausn. Lesum git status, búum til afrit eða notum afmarkað restore.
Geymum breytingar tímabundið
Ef við þurfum hreint vinnutré án þess að staðfesta hálfkláraða vinnu getum við notað stash:
git stash push -m 'hálfkláruð CTF-greining'
git stash list
git stash show -p stash@{0}
git stash pop
Stash er staðbundið hjálpartæki, ekki langtímageymsla eða öryggisafrit. Óraktar skrár fylgja ekki sjálfkrafa nema við notum sérstaka stillingu.
Fjartengd hirsla
Fjarhirsla (e. remote repository) er annað eintak hirslunnar sem við tengjum við með nafni, oft origin.
Sækjum opinbera æfingahirslu:
git clone https://example.invalid/ctf/verkefni.git
cd verkefni
git remote -v
Slóðin er gervidæmi og virkar ekki. Raunverulegt clone býr til möppu, sækir sögu og stillir origin.
Mikilvægar skipanir:
git fetch origin
git log --oneline --all --graph --decorate
git pull --ff-only
git push origin main
fetchsækir nýja hluti og fjarvísanir en tvinnar ekki vinnutréð.puller í grófum dráttumfetchog síðan tvinnun.pull --ff-onlyhafnar ef staðbundin og fjarlæg saga hafa kvíslast.pushsendir staðfestingar okkar; það krefst skrifheimildar.
Í CTF þurfum við oft aðeins clone, fetch, log og show. Við ýtum ekki breytingum í hirslu annarra nema samstarfsflæðið segi það.
Undireiningar
Git-hirsla getur vísað á aðrar hirslur sem undireiningar (e. submodules). Þær eru ekki sjálfkrafa venjulegar möppur úr aðalhirslunni.
git submodule status
git clone --recurse-submodules sækir viðbótarhirslur og eykur því það magn ótrausts inntaks sem við tökum við. Skoðum .gitmodules og slóðir áður en við sækjum þær.
.gitignore og leyndarmál
.gitignore segir Git hvaða óraktar skrár það eigi almennt að hunsa:
.venv/
__pycache__/
*.pyc
.env
*.key
Ef .env var þegar staðfest hættir Git ekki að rekja hana aðeins vegna þess að við bætum henni í .gitignore. Við getum hætt að rekja nýjustu útgáfuna með:
git rm --cached .env
En leyndarmálið er enn í eldri sögu. Rétt viðbragð við birtum lykli er fyrst að ógilda eða snúa lyklinum. Að endurskrifa Git-sögu getur minnkað áframhaldandi dreifingu en gerir ekki þegar afrituð gögn leynd aftur.
Git er ekki leyndarmálageymsla
Ekki staðfesta lykilorð, einkalykla, VPN-stillingar, raunfána eða framleiðslutákn. Notum gervigildi í dæmum og örugga leyndarmálastjórnun í rekstri.
CTF-vinnulag með ótraustri hirslu
Eftir clone keyrum við ekki forritið strax. Skoðum fyrst:
cd verkefni
pwd
git status
git remote -v
git log --oneline --decorate --graph --all | head -n 30
find . -maxdepth 2 -type f -print
Síðan leitum við að byggingar- og keyrsluskrám:
find . -maxdepth 2 -type f \
\( -name 'Dockerfile*' -o -name 'Makefile' -o \
-name 'pyproject.toml' -o -name 'package.json' -o \
-name '*.sh' \) -print
Skoðum breytingar og eyddar skrár:
git log --all --stat
git log --all -p -- README.md
git log --all --diff-filter=D --summary
git grep -n 'TODO' $(git rev-list --all)
Síðasta skipunin getur skilað miklu úttaki. Í stærri hirslu leitum við markvisst að vísbendingu úr verkefnalýsingunni.
Æfing 3: búðu til söguþraut
Fáni í eldri staðfestingu
Búðu til nýja æfingahirslu með þremur staðfestingum: README, skrá með gervifána og eyðingu þeirrar skrár. Skiptu síðan í hlutverk lausnara og finndu fánann aðeins með log og show.
Lausn
mkdir -p ~/ctf/git-sogu-thraut
cd ~/ctf/git-sogu-thraut
git init -b main
git config user.name 'CTF nemandi'
git config user.email 'nemandi@example.invalid'
echo '# Söguþraut' > README.md
git add README.md
git commit -m 'Stofna verkefni'
echo 'gg{fortidin_geymir_svarid}' > secret.txt
git add secret.txt
git commit -m 'Bæti við tímabundinni skrá'
git rm secret.txt
git commit -m 'Hreinsa nýjustu útgáfu'
Finnum eyðinguna og lesum foreldrið:
git log --diff-filter=D --summary --all
git show HEAD~1:secret.txt
Merki og útgáfur
Git-merki (e. tag) gefur tiltekinni staðfestingu stöðugt nafn, oft útgáfunúmer:
git tag -a v1.0 -m 'Fyrsta æfingaútgáfa'
git tag
git show v1.0
Grein færist þegar ný staðfesting bætist við; merki helst venjulega á sömu staðfestingu. Þegar við sækjum CTF-tól er skýr útgáfa eða merki endurtakanlegra en ótilgreind nýjasta aðalgrein.
Flytjum hreint verkefnisafrit
.git/ getur verið stórt og innihaldið sögu sem við viljum ekki hafa í afhendingu. git archive býr til safn úr staðfestri útgáfu án .git/:
git archive --format=tar.gz --output=verkefni-v1.0.tar.gz v1.0
Þetta tekur aðeins staðfestar skrár. Óstaðfestar breytingar og óraktar skrár fylgja ekki.
Æfing 4: berðu saman útgáfur
Hvað breyttist frá merki að HEAD?
Merktu núverandi staðfestingu v1, gerðu og staðfestu tvær breytingar og notaðu síðan Git til að sýna bæði skráalista og nákvæman mun frá v1 að HEAD.
Lausn
git tag v1
echo 'ný lína' >> README.md
echo 'feature=true' >> settings.txt
git add README.md settings.txt
git commit -m 'Undirbý v2'
git diff --stat v1 HEAD
git diff v1 HEAD
--stat gefur stutt yfirlit en seinni skipunin sýnir línubreytingarnar.
Lokaverkefni: greinum óþekkta hirslu
Frá clone að skýrslu
Þú færð slóð á heimilaða CTF-hirslu. Lýstu og framkvæmdu vinnuferli sem:
- sækir hirsluna án þess að keyra kóða,
- skráir fjarhirslur og greinar,
- sýnir þétta sögu,
- finnur eyddar skrár,
- les eina gamla skrá án þess að skipta um grein,
- varðveitir skipanir og niðurstöður í lausnadagbók.
Möguleg lausn
git clone <heimil-slod> verkefni
cd verkefni
git remote -v
git branch --all
git log --oneline --decorate --graph --all
git log --diff-filter=D --summary --all
Þegar við höfum fundið staðfestingu og slóð lesum við skrána án keyrslu:
git show <stadfesting>:<slod/i/skra>
Við skoðum einnig Dockerfile, skeljaskriftur og pakkaskrár áður en við ákveðum hvort eitthvað verði keyrt í einangruðu umhverfi. Við notum ekki reset --hard eða clean -fd á vinnu sem við viljum varðveita.
Samantekt
Í þessum kafla lærðum við að:
- greina Git frá hýsingarþjónustum eins og GitHub,
- skilja vinnutré, sviðsetningu og staðfestingar,
- velja breytingar með
git add, - bera saman vinnutré, sviðsetningu og sögu,
- lesa staðfestingar með
log,showogdiff, - endurheimta eyddar skrár úr eldri sögu,
- vinna með greinar og tvinnun,
- afturkalla afmarkaðar breytingar án
reset --hard, - sækja fjarhirslu án þess að keyra ótraustan kóða,
- skilja að
.gitignorefjarlægir ekki leyndarmál úr sögu, - merkja útgáfur og búa til hreint safn með
git archive.
Næst skoðum við tmux: hvernig við höldum skipanalínulotum lifandi, skiptum skjánum og snúum aftur eftir rofna SSH-tengingu.