Depth jóvoltából itt van az idei Defcon CTF selejtező RR300-as pályájának megoldása és egy kis ráhangolás Hacktivity-re :)
+++
Az RR200 feladatot megoldva fellelkesülve mentem neki a következő feladványnak:
root@BackTrack4:/home/retro300# file /root/defcon/rr3001d8bcd25d1849ac5a
/root/defcon/rr3001d8bcd25d1849ac5a.tar: POSIX tar archive (GNU)
Jól látszik,hogy egy tömörített fájl az alábbi tartalommal:
root@BackTrack4:/home/retro300# file retro300
retro300: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.32, dynamically linked (uses shared libs), stripped
Tartalmazott egy adatbázis fájlt is a csomagolt archívum:
root@BackTrack4:/home/retro300# file auth.db
auth.db: SQLite 3.x database
Egyszerűen meg lehet szerezni a fontosabb információkat a fájlból:
root@BackTrack4:/home/retro300# strings auth.db
SQLite format 3
tableusersusers
CREATE TABLE users (id INTEGER PRIMARY KEY, user TEXT, pin TEXT)
jeff1315
jupi1234
mars3473
merc2345
vulcan2945
joe8305
bob8367
dave3245
aaron7345
A binárist elindítva látható, hogy ismét egy hálózati kiszolgáló programmal szembesülünk:
root@BackTrack4:~# netstat -an | grep LISTEN
tcp 0 0 0.0.0.0:5500 0.0.0.0:* LISTEN // itt fut a jószág
A bináris vizsgálatához a legkézenfekvőbb megoldás az ltrace parancs. Mivel az előző feladatnál bemutatott fork() megoldást alkalmazza, így az alábbi scriptet használjuk ismét:
root@BackTrack4:/home/retro300# PID=`ps a | grep retro | grep -v grep | tail -1 | awk '{print $1}'` ; ltrace -p $PID
--- SIGSTOP (Stopped (signal)) ---
--- SIGSTOP (Stopped (signal)) ---
read(4, "a", 1) = 1
read(4, "n", 1) = 1
read(4, "i", 1) = 1
read(4, "t", 1) = 1
read(4, "t", 1) = 1
read(4, "v", 1) = 1
read(4, "a", 1) = 1
read(4, "l", 1) = 1
read(4, "a", 1) = 1
read(4, "k", 1) = 1
read(4, "i", 1) = 1
read(4, "?", 1) = 1
read(4, "\r", 1) = 1
read(4, "\n", 1) = 1
strcmp("vanittvalaki?\r", "letmeinpls") = 1
exit(0 <unfinished ...>
+++ exited (status 0) +++
Természetesen egy másik konzolon hozzá csatlakozunk a szolgáltatáshoz:
Computer:~ depth$ telnet 192.168.1.102 5500
Trying 192.168.1.102...
Connected to 192.168.1.102.
Escape character is '^]'.
vanittvalaki?
Connection closed by foreign host.
Amint látható a beírt karaktersorozatunkat hasonlítja össze a 'letmeinpls' szöveggel, amennyiben egyezik mehet tovább a feladvány megoldása felé a vándor egyébként kimarad egy dobásból.
Megismételve a vizsgálatot érdekes látvány tárul a szemünk elé (részlet az ltrace kimenetéből):
strcmp("letmeinpls", "letmeinpls") = 0
ptrace(0, 0, 1, 0, 0xbf926640) = -1 // ez itt a szivattyú!
exit(1 <unfinished ...>
+++ exited (status 1) +++
Szóval, a bináris meghívja a ptrace függvényt, amely segítségével az összes debugger alkalmazást ledobja magáról (mivel ha érzékeli, hogy valaki ptrace megoldással próbálja vizsgálni, megszakítja a további működést).
Nem nagy probléma több megoldás is létezik a tovább menetelésre:
- átírjuk a binárist (béna, mi van ha crc checksum vagy egyéb védelem van? Defcon selejtezőn nem lehet tudni...)
- alkalmazzuk az LD_PRELOAD technikát amely segítvégével szépen eltéríthetük a ptrace függvényt.
A következő fájlt kell megalkotni:
#include <stdio.h>
#include <string.h>long ptrace(char request, int pid, void *addr, void *data){
return 0;
}
Látható,hogy lényeges funkciót nem végez viszont az én szempontomból igen, mivel mindig nullával tér vissza és ezáltal a program úgy érzékeli minden ok, senki nem próbál debuggolni.
Lefordítjuk:
root@BackTrack4:/home/retro300# gcc -fPIC -c ld.c -o ld.o
root@BackTrack4:/home/retro300# gcc -shared -o ld.so ld.o
Bínárist a következő módon kell indítani,hogy a változás életbe lépjen:
root@BackTrack4:/home/retro300# LD_PRELOAD=/home/retro300/ld.so ./retro300
Ismételt támadási kísérlet után látható,hogy sikerrel jártunk:
Computer:~ depth$ nc -v 192.168.1.102 5500
Connection to 192.168.1.102 5500 port [tcp/fcp-addr-srvr1] succeeded!
letmeinpls
_____ ______ _____ _ _
__ ____ __ / ____| ____/ ____(_) | |
____/ /___/ / /____ / /__ | (___ | |__ | | _ __| |
/ __ / __ / __/ _ \/ //_/ \___ \| __|| | | |/ _` |
/ /_/ / /_/ / /_/ __/ ,< ____) | |___| |____| | (_| |
\__,_/\__,_/\__/\___/_/|_| |_____/|______\_____|_|\__,_| (beta)
( cause everyone is looking for a new provider right?!)
Username:jupi
Passcode:1234
Bad Username or Pin
Itt lehet próbálkozni az auth.db-ben szereplő információkkal ahogy látjuk, sikertelenül.
Az ltrace kimenetén sem látunk olyan információt amivel okosabbak lennénk:
strcmp("letmeinpls", "letmeinpls") = 0
ptrace(0, 0, 1, 0, 0xbfe6b360) = 0
strlen(" "...) = 499
send(4, 0xbfe6b13c, 499, 0, 0xbfe6b118) = 499
strlen("Username:") = 9
send(4, 0x804a795, 9, 0, 0x6f797265) = 9
read(4, "j", 1) = 1
read(4, "u", 1) = 1
read(4, "p", 1) = 1
read(4, "i", 1) = 1
read(4, "\n", 1) = 1
strdup("jupi") = 0x8908878
strlen("Passcode:") = 9
send(4, 0x804a895, 9, 0, 0xb7ec23c0) = 9
read(4, "1", 1) = 1
read(4, "2", 1) = 1
read(4, "3", 1) = 1
read(4, "4", 1) = 1
read(4, "\n", 1) = 1
strlen("Bad Username or Pin\n") = 20
send(4, 0x804a89f, 20, 0, 0xbfe6b33b) = 20
free(0x8908878) = <void>
close(4) = 0
exit(1 <unfinished ...>
+++ exited (status 1) +++
Ezen a ponton jött ez a várva várt lehetőség és beizzíthatjuk kedvenc debuggerünket majd a jelszó bekérés funkcióra vagy környékére töréspontot tenni és közelebbről megvizsgálni mi is történik:
(gdb) set disassembly-flavor intel
Az alábbi információkat találtam meg a jegyzeteimben:
- 0x8049de7 (username beolvasás utáni RET)
- 0x8049e73 (username és pin beolvasás utáni RET)
Az alábbi kódrészlet árulkodik egy kis turpisságról (egy strlen() után):
MOV DWORD PTR [EBP-24], EAX
CMP DWORD PTR [EBP-24], 14
JZ 0x08049EAC
Ha a PIN-ként beadott érték hossza nem 14 akkor automatikusan kiléptet a program. Próbáljunk meg 14-et beadni és nézzük meg mi történik. A következő a felállás:
- szerver LD_PRELOAD techikával indítva.
- Gyermek folyamatra ltrace segítségével rácsatlakozunk.
- egy másik terminálon beküldjük a megfelelő adatokat.
Kapcsolódási kísérlet a szoftverhez:
Computer:~ depth$ nc -v 192.168.1.102 5500
Connection to 192.168.1.102 5500 port [tcp/fcp-addr-srvr1] succeeded!
letmeinpls
_____ ______ _____ _ _
__ ____ __ / ____| ____/ ____(_) | |
____/ /___/ / /____ / /__ | (___ | |__ | | _ __| |
/ __ / __ / __/ _ \/ //_/ \___ \| __|| | | |/ _` |
/ /_/ / /_/ / /_/ __/ ,< ____) | |___| |____| | (_| |
\__,_/\__,_/\__/\___/_/|_| |_____/|______\_____|_|\__,_| (beta)
( cause everyone is looking for a new provider right?!)
Username:jupi
Passcode:12341234567890
Bad Username or Passcode
Nézzük meg mit sikerült megfogni, ltrace kimenete elég sokmindent elárul:
--- SIGSTOP (Stopped (signal)) ---
--- SIGSTOP (Stopped (signal)) ---
read(4, "e", 1) = 1
read(4, "t", 1) = 1
read(4, "m", 1) = 1
read(4, "e", 1) = 1
read(4, "i", 1) = 1
read(4, "n", 1) = 1
read(4, "p", 1) = 1
read(4, "l", 1) = 1
read(4, "s", 1) = 1
read(4, "\n", 1) = 1
strcmp("letmeinpls", "letmeinpls") = 0
ptrace(0, 0, 1, 0, 0xbfe6b360) = 0
strlen(" "...) = 499
send(4, 0xbfe6b13c, 499, 0, 0xbfe6b118) = 499
strlen("Username:") = 9
send(4, 0x804a795, 9, 0, 0x6f797265) = 9
read(4, "j", 1) = 1
read(4, "u", 1) = 1
read(4, "p", 1) = 1
read(4, "i", 1) = 1
read(4, "\n", 1) = 1
strdup("jupi") = 0x8908878
strlen("Passcode:") = 9
send(4, 0x804a895, 9, 0, 0xb7ec23c0) = 9
read(4, "1", 1) = 1
read(4, "2", 1) = 1
read(4, "3", 1) = 1
read(4, "4", 1) = 1
read(4, "1", 1) = 1
read(4, "2", 1) = 1
read(4, "3", 1) = 1
read(4, "4", 1) = 1
read(4, "5", 1) = 1
read(4, "6", 1) = 1
read(4, "7", 1) = 1
read(4, "8", 1) = 1
read(4, "9", 1) = 1
read(4, "0", 1) = 1
read(4, "\n", 1) = 1
strncpy(0xbfe6b46f, "1234", 4) = 0xbfe6b46f
sqlite3_open(0x804a7d2, 0xbfe6b334, 2, 5, 0xb7e9daf3) = 0
sprintf("select id,pin from users where u"..., "select id,pin from users where u"...) = 42
sqlite3_exec(0x8908ad0, 0xbfe6b2e4, 0x80497f5, 0, 0xbfe6b2e0 <unfinished ...>
strncpy(0xbfe6b238, "8", 20) = 0xbfe6b238
strncpy(0x804bbbb, "1234", 4) = 0x804bbbb
atoi(0xbfe6b238, 0x890bb38, 4, 1, 0xb7f34ff4) = 8
<... sqlite3_exec resumed> ) = 0
sqlite3_close(0x8908ad0, 0xbfe6b30e, 0x80497f5, 0, 0xbfe6b2e0) = 0
strlen("1234") = 4
strdup("1234") = 0x89098c8
memcpy(0x804bbbb, " ", 5) = 0x804bbbb
strncmp("1234", "1234", 4) = 0
strncpy(0xbfe6b464, "1234567890", 10) = 0xbfe6b464
printf("sending %s out of buf: %s\n", "1234567890", "12341234567890") = 46
time(NULL) = 1308660361
htonl(0x33d655e0, 0xb7ec0ff4, 0, 0, 0x655eb348) = 0xe055d633
sprintf("1253239787", "%0.10u", 1253239787) = 10
strncmp("1253239787", "1234567890", 10) = 1 // Itt a lényeg, itt történik az összehasonlítás a beküldött PIN változó 10 karakteres részével (PASSCODE)
strlen("Bad Username or Passcode\n") = 25
send(4, 0x804a8cf, 25, 0, 0xb7ec5910) = 25
free(0x8908878) = <void>
free(0x89098c8) = <void>
close(4) = 0
exit(1 <unfinished ...>
+++ exited (status 1) +++
Újra próbálkozva és a fenti kódot megadva a szerver meghatározott ideig (kb 10perc) beengedi a felhasználót:
Computer:~ depth$ nc -v 192.168.1.102 5500
Connection to 192.168.1.102 5500 port [tcp/fcp-addr-srvr1] succeeded!
letmeinpls
_____ ______ _____ _ _
__ ____ __ / ____| ____/ ____(_) | |
____/ /___/ / /____ / /__ | (___ | |__ | | _ __| |
/ __ / __ / __/ _ \/ //_/ \___ \| __|| | | |/ _` |
/ /_/ / /_/ / /_/ __/ ,< ____) | |___| |____| | (_| |
\__,_/\__,_/\__/\___/_/|_| |_____/|______\_____|_|\__,_| (beta)( cause everyone is looking for a new provider right?!)
Username:jupi
Passcode:12341253239787 //PIN+PASSCODEDDTEK VPN console
Choose an option:
1: change pin
2: re-sync sec token
3: add user
4: change username
5: exit
Egyik menüpont sem működik, viszont a 8-as gombot megnyomva megjelenik a szükséges kulcs és pár másodperccel később +300 pont az eredménykijelzőn.
(Én bruteforcoltam kézzel, de további debuggolás is segít ;) - de ilyenkor alap,hogy végignyomkodod 0-9-ig :) )
Remélem érthető volt a leírás, triviális dolgokba próbáltam nem belemenni és csak a lényegre koncentrálni. Tévutakat nem mutattam be pl: SQL injection és egyebek még a debuggolás megkezdése előtt :)
Tanulni lehet belőle az tuti! A lényeg, hogy sokat tanultunk és reszkessetek Hacktivity CTF-en mert izgalmas feladványokat találtunk ki :)
zota 2011.06.22. 14:06:03
NamelessOne 2011.06.22. 14:13:37
Tyra3l 2011.06.23. 20:27:11
Tyrael