feladványok főoldal

Ez az összes közül a legösszetettebb feladat, viszont ebből lehet a legtöbbet tanulni

FIGYELEM! Míg a többi feladatnál igyekeztem felhívni a figyelmet a különféle platformok közötti különbségre, itt kizárólag a 64 bites Intel-architektúrán futó Linux alkalmazásról írok!

Analízis

A feladat ismét egy változó (admin) átállítása lenne - viszont a korábbi feladványokban szereplő módszerek egyike sem használható.

A program lefordításakor a következő figyelmeztetést kapjuk (GCC esetén):

pwnme.c: In function ‘main’:
pwnme.c:14:12: warning: format not a string literal and no format arguments [-Wformat-security]
   14 |     printf(name);
      |

Azaz a cursed heap / “dinamikus”-hez hasonlóan ismét egy formátumot kellhet majd írnunk.

Áttekintés

  • megtudunk egy memóriacímet amely egy lokális változóhoz tartozik, de nem az admin-ét
  • megtudjuk hogy hány bájtosak a programban a memóriacímek és a long típusú változók (8-8 bájt)
  • beírhatunk egy 100 karakteres szöveget és egy long számot
  • a 100 karakteres szöveget printf()-eli a program

Ezekből a darabokból lehet tehát építkeznünk.

Printf

Úgy tűnik, hogy a változó felülírására nincs más módunk, mint valahogy a printf-et használni.

Beleolvasva a printf format string wikipédia-szócikkébe, megtudhatjuk hogy a %n formátummal írni lehet - mégpedig az eddig kiírt karakterek számát egy int* pointerrel átadott címre.

A probléma csak az, hogy a printf hívás nem kap semmilyen paramétert - tehát úgy tűnik hogy csak vaktában tudunk lövöldözni, és így nem sok esélye van annak hogy eltaláljuk az admin változót.

A változó címe egyébként viszonylag könnyen kitalálható, hiszen a közvetlen szomszédja az ismert című s változónak, így a címeik különbsége 8 lesz - maximum két próbálkozás elég ehhez, de le is tesztelhetjük a program apró módosításával - 8-at kell hozzáadni a címhez.

Paraméter

A probléma viszont most az, hogy ezt a címet át kéne adni paraméterként a printf-nek, de a kódban nincs ilyesmi.

Felidézhetjük viszont, hogy mit tudunk C-ben a lokális változók tárolásáról - a verem-memóriában kapnak ezek helyet - és ugyanezt használjuk paraméterek átadására is! Tehát az adat valahol ott van, csak ki kell találni hogy pontosan hol, és megmondani a printf-nek is.

(tapasztalatom szerint 6-7. paraméter lesz)

A könnyebb eléréshez használhatjuk a printf egy (nem platformfüggetlen, linuxra jellemző) formátumát, a paraméter-indexelést: %6$d a 6. paramétert írja ki %d formátummal. Ezzel már elég gyorsan megkereshetjük az általunk beírt számot, elég pár esetet végigpróbálni.

Megoldás

Tehát a megoldás:

  • kapott címet átírni decimálisba, hozzáadni 8-at
  • névnek beírni A%6$n-t (vagy éppen hányas számú nálunk, az A azért kell hogy kiírjunk egy karaktert és a %n így ne 0-t írjon)
  • beírni a számított címet
  • you won

Ezt a feladványt sajnos senki sem oldotta meg, amit igazán sajnálok, de ez nagyságrendekkel nehezebb is volt mint az többi.

Bárkinek, akit érdekel az ilyesmi, ajánlom LiveOverflow videóit, különösen a Binary Exploitation sorozatot, illetve VIK-eseknek a KSZK-s SecuriTeam-be való belépést!