Die Challenge (ppc 200) spricht von einer verdächtigen Nachricht, die uns in Form dieser Datei übersandt wird. “File” meldet, dass die Datei nur aus “Daten” besteht, aber ein erster Blick hinein zeigt uns:
Die Datei beginnt mit den Worten “reverse all” und scheint offenbar von uns zu verlangen, den Inhalt komplett umzudrehen. Dies tun wir auch mit folgendem kleinen Python-Skript:
#!/usr/bin/python import sys revstr = "reverse all\x00\x00" file = open(sys.argv[1]).read() if file[0:len(revstr)] == revstr: file = file[:len(revstr):-1] print file
Nach Anwendung auf die Datei und erneuter Betrachtung im Texteditor, finden wir folgenden neuen Dateianfang vor:
Dieses Mal soll der Inhalt der Datei offensichtlich mit Base16 dekodiert werden. Auch das setzen wir mit einem Skript, diesmal mit Perl, um:
#!/usr/bin/perl open(FILE, $ARGV[0]); @file = <FILE>; close(FILE); for ($i=11; $i<=length($file[0]); $i+=2) { $double = substr($file[0], $i, 2); print chr(hex($double)); }
Erneut werfen wir nach Anwendung des Skriptes einen Blick in die Datei:
Wieder “reverse all” und dahinter bereits erkennbar, eine Base85 (auch ASCII85) Kodierung. In diesem Moment stellte ich mir die Frage, ob ein automatisiertes Skript, dass alles selbst erkennen und umsetzen würde vielleicht angebrachter wäre. Der weitere Verlauf, sowie kleinere Probleme bei der Umsetzung in einer vordefinierten Programmiersprache, führten jedoch dazu, jede Operation in ein separates Skript zu implementieren und diese anschließend manuell nacheinander auszuführen.
Nach zweifachem Umdrehen des Textes, war es demnach an der Zeit die Base85 / ASCII85 Dekodierung umzusetzen, was in diesem Skript realisiert wurde – damit es nicht langweilig wird in PHP 🙂 Der Quellcode ist hierbei dem cryptool von ollej entnommen!
#!/usr/bin/php <?php //ASCII85/Base85 decode <http://en.wikipedia.org/wiki/Ascii85> function ascii85decode($str) { $newstring = ''; $whiteSpace = array("\x00","\x09","\x0A","\x0C","\x0D","\x20"); $str = str_replace('<~','',$str); $str = str_replace($whiteSpace,'',$str); if(substr($str,-2)!='~>') { return ''; } $str = substr($str,0,(strlen($str)-2)); $dataLength = strlen($str); for($i=0; $i<$dataLength; $i+=5) { $b = 0; if(substr($str,$i,1)=="z") { $i -= 4; $newstring .= pack("N",0); continue; } $c = substr($str,$i,5); if(strlen($c)<5) { break; } $c = unpack('C5',$c); $value=0; for($j=1; $j<=5; $j++) { $value += (($c[$j]-33)*pow(85,(5-$j))); } $newstring .= pack("N",$value); } if($i<$dataLength) { $value = 0; $chunk = substr($str,$i); $partialLength = strlen($chunk); for($j=0; $j<(5-$partialLength); $j++){ $chunk .= 'u'; } $c = unpack('C5',$chunk); for($j=1; $j<=5; $j++) { $value += (($c[$j]-33)*pow(85,(5-$j))); } $foo = pack("N",$value); $newstring .= substr($foo,0,($partialLength-1)); } return $newstring; } $data = substr(file_get_contents("$argv[1]"), 11); $res = ascii85decode($data); print $res; ?>
Nachdem auch dieser Schritt gegangen wurde, finden wir folgendes am Anfang der Datei:
Dieses mal müssen also Buchstaben in der Datei mit jeweils anderen ersetzt werden! Auch hierfür schreiben wir ein Perl-Skript:
#!/usr/bin/perl -w open(FILE, $ARGV[0]); @input = <FILE>; close(FILE); # replace G,g,p,h,K,L,o,q,P,S,O,x,Z # ->L,Z,K,o,S,O,G,h,x,q,P,g,p^@^@ foreach $line (@input) { for ($i=0;$i<length($line);$i++) { $char = substr($line, $i, 1); if ($char eq "L") { print "G"; next; } if ($char eq "Z") { print "g"; next; } if ($char eq "K") { print "p"; next; } if ($char eq "o") { print "h"; next; } if ($char eq "S") { print "K"; next; } if ($char eq "O") { print "L"; next; } if ($char eq "G") { print "o"; next; } if ($char eq "h") { print "q"; next; } if ($char eq "x") { print "P"; next; } if ($char eq "q") { print "S"; next; } if ($char eq "P") { print "O"; next; } if ($char eq "g") { print "x"; next; } if ($char eq "p") { print "Z"; next; } print $char; } } close(FILE);
Nach weiteren vier Schritten stoßen wir auf diesen neuen Header:
Demnach ist diese Datei nun mit Base32 kodiert und muss entsprechend mit diesem dafür entwickelten Perl-Skript dekodiert werden:
#!/usr/bin/perl use MIME::Base32 qw( RFC ); open(FILE, $ARGV[0]); @file = <FILE>; close(FILE); $enc = $file[0]; substr($enc, 0, 11) = ""; $decoded = MIME::Base32::decode($enc); print $decoded;
Nach etlichen weiteren Schritten taucht gelegentlich noch eine Base64 Kodierung auf, die aber problemlos mit dem Linux Konsolenwerkzeug “base64” dekodiert werden kann.
Gefühlte 100 Schritte (insgesamt circa 40) später, stoßen wir auf die letzte Kodierung:
rup0rt@lambda:~/VolgaCTF2013/ppc200# cat next40.txt
base64encTDByZW1fbHAkdW1fZDAxMHJfJGkrXy9cbWUr
rup0rt@lambda:~/VolgaCTF2013/ppc200# vi next40.txt
rup0rt@lambda:~/VolgaCTF2013/ppc200# base64 -d next40.txt
L0rem_lp$um_d010r_$i+_/\me+
Die Lösung lautet somit “L0rem_lp$um_d010r_$i+_/\me+“.