Spomnil sem se, da sem pred leti užival v “blowfish” “wargame”-u na smashthestack.org. Nažalost takrat nisem imel dovolj znanja in vztrajnosti, da bi se kam prebil. Prevrtimo čas nekaj let naprej, nekaj stvari sem se vmes naučil in “io” bo idealen test kako daleč sem prišel. Napredek bom vmes popisoval v materinem jeziku :)
Povezava na strežnik je klasična:
$ ssh -l level1 io.smashthestack.org -p2224
Geslo: level1
V domači mapi najdemo navodila za igro. Preberite jih.
V kolikor sledimo navodilom, naredimo tole:
level1@io:~$ cd /levels/
level1@io:/levels$ ./level01
Enter the 3 digit passcode to enter: 123
Zagon “level1” programa nas vpraša za geslo, ki je v obliki treh cifer. Kombinacija “123” ni delovala, če smo pogumni lahko na roke preizkusimo še preostalih 999 možnosti. Verjetno pa to ni smisel igre…
Prefinjen pristop bi bil, da preverimo če obstaja izvorna koda programa, katere na našo žalost ni pri roki.
Naslednja stopnja je obratni inženiring.
V sklopu paketa GNU binutils najdemo med drugim objdump
, ki ga lahko izkoristimo za prikaz programa v zbirnem jeziku.
level1@io:/levels$ objdump -d level01
level01: file format elf32-i386
Disassembly of section .text:
08048080 :
8048080: 68 28 91 04 08 push $0x8049128
8048085: e8 85 00 00 00 call 804810f
804808a: e8 10 00 00 00 call 804809f
804808f: 3d 0f 01 00 00 cmp $0x10f,%eax
8048094: 0f 84 42 00 00 00 je 80480dc
804809a: e8 64 00 00 00 call 8048103
Hiter pregled izpisa nam razjasni delovanje programa. Za nas zanimiva vrstica je ta, ki vsebuje ukaz cmp
. cmp
(compare) je ukaz za primerjavo v zbirnem jeziku, v primeru ko sta obe podani vrednosti enaki, postavi Z
zastavico na 1
, sicer pa na 0
. Ukaz je
(jump if equal), kakor neposredni prevod pove, skoči na določeno mesto v pomnilniku.
eax
je en izmed registrov (ang. accumulator register) v katerega lahko shranimo vrednosti, tja shrani naš program vrednost, ki smo jo vpisali, ko je program od nas zahteval geslo. Uporablja se za dostop do vhodno/izhodnih vrat, aritmetiko, prekinitve in podobno. eax
poznamo, ugotoviti moramo kaj se skriva pod vrednostjo 0x10f
, to lahko izvedemo s pomočjo lupine:
level1@io:/levels$ echo "ibase=16; 10F"| bc
271
Privzeto objdump
izpisuje ukaze zbirnika v AT&T sintaksi, ki jo prepoznamo po množici % in $ znakov, omogoča pa tudi izpis v Intel sintaksi, ki je vsaj zame berljivejša kakor AT&T. Naš primer je sicer prekratek, da bi bile razlike res opazne, vendar ga vseeno prilagam.
level1@io:/levels$ objdump -M intel -d level01
level01: file format elf32-i386
Disassembly of section .text:
08048080 :
8048080: 68 28 91 04 08 push 0x8049128
8048085: e8 85 00 00 00 call 804810f
804808a: e8 10 00 00 00 call 804809f
804808f: 3d 0f 01 00 00 cmp eax,0x10f
8048094: 0f 84 42 00 00 00 je 80480dc
804809a: e8 64 00 00 00 call 8048103
Dodaten način za razbijanje prve stopnje je uporaba GNU razhroščevalnika (gdb
, GNU debugger).
level1@io:/levels$ gdb level01
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /levels/level01...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
0x08048080 <+0>: push $0x8049128
0x08048085 <+5>: call 0x804810f
0x0804808a <+10>: call 0x804809f
0x0804808f <+15>: cmp $0x10f,%eax
0x08048094 <+20>: je 0x80480dc
0x0804809a <+26>: call 0x8048103
End of assembler dump.
(gdb) p 0x10F
$1 = 271
Intel sintakso lahko uporabljamo tudi v GNU razhroščevalniku z ukazom:
(gdb) set dis intel
Navedeni ukaz, nam bo nastavil gdb samo za trenutno sejo, če želimo, da je Intel sintaksa privzeta pri vsakem zagonu razhroščevalnika lahko v .gdbinit dodamo vrstico “set dis intel”:
$ echo "set dis intel" > ~/.gdbinit
Ob pridobitvi gesla nam preostane samo še vpis v program in pridobili smo dostop do naslednje stopnje.
level1@io:/levels$ ./level01
Enter the 3 digit passcode to enter: 271
Congrats you found it, now read the password for level2 from /home/level2/.pass
sh-4.2$