{"id":849,"date":"2019-09-20T15:38:52","date_gmt":"2019-09-20T19:38:52","guid":{"rendered":"https:\/\/blog.lamarranet.com\/?p=849"},"modified":"2019-09-21T10:07:20","modified_gmt":"2019-09-21T14:07:20","slug":"exploit-education-phoenix-final-two-solution","status":"publish","type":"post","link":"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-final-two-solution\/","title":{"rendered":"Exploit Education | Phoenix | Final Two Solution"},"content":{"rendered":"<p>Remote heap overflow.<\/p>\n<p>The description and source code can be found here:<br \/>\n<a href=\"http:\/\/exploit.education\/phoenix\/final-two\/\">http:\/\/exploit.education\/phoenix\/final-two\/<\/a><\/p>\n<p>Ok, so the title here is a little misleading as I don&#8217;t actually have a solution. What I <em>will<\/em> be doing, is explaining why this isn&#8217;t exploitable.<\/p>\n<p>The predecessor to <strong>Phoenix<\/strong> is <strong><a href=\"http:\/\/exploit.education\/protostar\/\">Protostar<\/a><\/strong>. This level is the same as <strong>Protostar&#8217;s <a href=\"http:\/\/exploit.education\/protostar\/final-two\/\">Final Two<\/a><\/strong> level, yet that one IS exploitable despite the code being almost the same. I&#8217;ll discuss what makes Protostar different at the binary level.<\/p>\n<h1>Source Code Analysis<\/h1>\n<p>Let&#8217;s have a look at the source code to see what the program does (spoiler alert: Nothing useful).<\/p>\n<p>There&#8217;s not much in<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> main()<\/span>. It just prints the banner, flushes anything in the input buffer (preventing you from piping anything to netcat), and calls<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> get_requests()<\/span>.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nint main(int argc, char **argv, char **envp) {\r\n    printf(&quot;%s\\n&quot;, BANNER);\r\n    fflush(stdout);\r\n\r\n    get_requests(0, 1);\r\n    return 0;\r\n}\r\n<\/pre>\n<p>The<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> get_requests() <\/span>function is where it gets interesting. It sets up a while loop that will break after 256 iterations in order to accept &#8220;requests&#8221; from a user (up to 256 of them). That loop does a few things:<\/p>\n<ul>\n<li>Allocates 128 bytes of memory on the heap.\n<li>Reads from user input to save to the heap.\n<ul>\n<li>To continue making requests, the input has to be exactly 128 bytes long.\n<li>Anything more and the rest is used for the next iteration of the loop. Anything less, and the loop breaks.\n\t<\/ul>\n<li>Checks to make sure the first 4 characters are &#8220;FSRD&#8221; (and breaks out of the loop if it&#8217;s not).\n<li>Calls<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> check_path()<\/span>, supplying the user-provided input after &#8220;FSRD&#8221; as a parameter.\n<li>Increments the <strong>dll<\/strong>, the counter variable.\n<\/ul>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid get_requests(int in_fd, int out_fd) {\r\n    char *buf;\r\n    char *destroylist&#x5B;256];\r\n    int dll;\r\n    int i;\r\n\r\n    dll = 0;\r\n    while (1) {\r\n        if (dll &gt;= 255) break;\r\n\r\n        buf = calloc(REQSZ, 1);\r\n        if (read(in_fd, buf, REQSZ) != REQSZ) break;\r\n\r\n        if (strncmp(buf, &quot;FSRD&quot;, 4) != 0) break;\r\n\r\n        check_path(buf + 4);\r\n\r\n        dll++;\r\n    }\r\n    ...\r\n<\/pre>\n<p>At this point, the<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> get_requests() <\/span>function isn&#8217;t over, but let&#8217;s jump to<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> check_path() <\/span>and come back to this later.<\/p>\n<p><span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> check_path() <\/span>will do several things:<\/p>\n<ul>\n<li>Looks for the last occurrence of the &#8220;\/&#8221; character &#038; saves a pointer to it called &#8220;p&#8221;\n<li>Saves the length of the string starting there\n<li>If the &#8220;\/&#8221; character exists:\n<ul>\n<li>Look for the &#8220;ROOT&#8221; string and save a pointer to it called &#8220;start&#8221;\n<li>If the &#8220;ROOT&#8221; string exists:\n<ul>\n<li>Decrement the &#8220;start&#8221; pointer to the &#8220;ROOT&#8221; string until a &#8220;\/&#8221; character is found\n<li>Copies the string starting at the &#8220;p&#8221; pointer to where the &#8220;start&#8221; pointer ends up\n\t\t<\/ul>\n<\/ul>\n<\/ul>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid check_path(char *buf) {\r\n    char *start;\r\n    char *p;\r\n    int l;\r\n\r\n    \/*\r\n    * Work out old software bug\r\n    *\/\r\n\r\n    p = rindex(buf, '\/');\r\n    l = strlen(p);\r\n    if (p) {\r\n        start = strstr(buf, &quot;ROOT&quot;);\r\n        if (start) {\r\n            while (*start != '\/') start--;\r\n            memmove(start, p, l);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Finally, back at the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> get_requests() <\/span>function, there&#8217;s a for loop that iterates for the number of 128 byte requests that were supplied by the user. The string &#8220;Process OK&#8221; is printed and<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> free() <\/span>is called on each pointer in the<span style=\"font-family:Courier New\"> destroylist[] <\/span>character pointer array.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n    ...\r\n    for (i = 0; i &lt; dll; i++) {\r\n        write(out_fd, &quot;Process OK\\n&quot;, strlen(&quot;Process OK\\n&quot;));\r\n        free(destroylist&#x5B;i]);\r\n    }\r\n}\r\n<\/pre>\n<p>If, at this point, you&#8217;re wondering, &#8220;when did we save any pointers to the<span style=\"font-family:Courier New\"> destroylist[] <\/span>character pointer array?&#8221; Then you&#8217;re on the right track. This whole &#8220;heap overflow&#8221; attack relies on the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> free() <\/span>function. We would need to add an extra line of code to<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> get_requests()<\/span>, like so:<\/p>\n<pre class=\"brush: cpp; highlight: [12]; title: ; notranslate\" title=\"\">\r\nvoid get_requests(int in_fd, int out_fd) {\r\n    char *buf;\r\n    char *destroylist&#x5B;256];\r\n    int dll;\r\n    int i;\r\n\r\n    dll = 0;\r\n    while (1) {\r\n        if (dll &gt;= 255) break;\r\n\r\n        buf = calloc(REQSZ, 1);\r\n        destroylist&#x5B;dll] = buf;\r\n        if (read(in_fd, buf, REQSZ) != REQSZ) break;\r\n\r\n        if (strncmp(buf, &quot;FSRD&quot;, 4) != 0) break;\r\n\r\n        check_path(buf + 4);\r\n\r\n        dll++;\r\n    }\r\n    ...\r\n<\/pre>\n<h1>Running the Program<\/h1>\n<p>There&#8217;s not much to it, but I&#8217;ll show an example of what &#8220;valid&#8221; input looks like:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ nc 127.1 64015\r\nWelcome to phoenix\/final-two, brought to you by https:\/\/exploit.education\r\nFSRD\/ROOT\/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nFSRD\/ROOT\/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nFSRD\/ROOT\/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n\r\nProcess OK\r\nProcess OK\r\nProcess OK\r\n<\/pre>\n<p>To show what invalid input looks like, I&#8217;ll run the binary in GDB so we can see that it segfaults and at which instruction:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ gdb -q \/opt\/phoenix\/i486\/final-two\r\nGEF for linux ready, type `gef' to start, `gef config' to configure\r\n71 commands loaded for GDB 8.2.1 using Python engine 3.5\r\n&#x5B;*] 2 commands could not be loaded, run `gef missing` to know why.\r\nReading symbols from \/opt\/phoenix\/i486\/final-two...(no debugging symbols found)...done.\r\n\r\ngef&gt; run\r\nStarting program: \/opt\/phoenix\/i486\/final-two\r\nWelcome to phoenix\/final-two, brought to you by https:\/\/exploit.education\r\nFSRDROOT\/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n0x08048959 in check_path ()\r\n&#x5B;... GEF output snipped ...]\r\n\r\ngef&gt; x\/i $eip\r\n=&gt; 0x8048959 &lt;check_path+84&gt;:   mov    al,BYTE PTR &#x5B;eax]\r\n\r\ngef&gt; x $eax\r\n   0xf7e68fff:  Cannot access memory at address 0xf7e68fff\r\n<\/pre>\n<p>This happens because of the following line of code in the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> check_path() <\/span>function.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">while (*start != '\/') start--;<\/pre>\n<p>Since there is no &#8220;\/&#8221; character before the &#8220;ROOT&#8221; string, it keeps decrementing the point until it reaches a memory location it can&#8217;t read from. In this case, that&#8217;s at 0xf7e68fff, which is one byte before the start of the heap.<\/p>\n<p>Now, if the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> free() <\/span>function was being called on our allocated heap chunks, we could take advantage of this bug and overwrite the chunk metadata for one of the requests. For more details on how to exploit a heap overflow with this, see my solution to the <strong><a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-heap-three-solution\/\">Heap Three<\/a><\/strong> level.<\/p>\n<h1>Binary Analysis<\/h1>\n<p>If you look at the source code from the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> get_requests() <\/span>function from <strong>Protostar&#8217;s<\/strong> Final Two level, it&#8217;s almost exactly the same. However, that one IS exploitable. There seems to be a difference between the source code and the binary. Let&#8217;s take a look at the binary on <strong>Protostar<\/strong>:<\/p>\n<pre class=\"brush: plain; highlight: [13]; title: ; notranslate\" title=\"\">\r\nuser@protostar:\/opt\/protostar\/bin$ gdb -q final2\r\nReading symbols from \/opt\/protostar\/bin\/final2...done.\r\n\r\n(gdb) set disassembly-flavor intel\r\n\r\n(gdb) disas get_requests\r\nDump of assembler code for function get_requests:\r\n...\r\n0x0804bd6f &lt;get_requests+40&gt;:   call   0x804b4ee &lt;calloc&gt;\r\n0x0804bd74 &lt;get_requests+45&gt;:   mov    DWORD PTR &#x5B;ebp-0x14],eax\r\n0x0804bd77 &lt;get_requests+48&gt;:   mov    eax,DWORD PTR &#x5B;ebp-0x10]\r\n0x0804bd7a &lt;get_requests+51&gt;:   mov    edx,DWORD PTR &#x5B;ebp-0x14]\r\n0x0804bd7d &lt;get_requests+54&gt;:   mov    DWORD PTR &#x5B;ebp+eax*4-0x414],edx\r\n0x0804bd84 &lt;get_requests+61&gt;:   add    DWORD PTR &#x5B;ebp-0x10],0x1\r\n0x0804bd88 &lt;get_requests+65&gt;:   mov    DWORD PTR &#x5B;esp+0x8],0x80\r\n0x0804bd90 &lt;get_requests+73&gt;:   mov    eax,DWORD PTR &#x5B;ebp-0x14]\r\n0x0804bd93 &lt;get_requests+76&gt;:   mov    DWORD PTR &#x5B;esp+0x4],eax\r\n0x0804bd97 &lt;get_requests+80&gt;:   mov    eax,DWORD PTR &#x5B;ebp+0x8]\r\n0x0804bd9a &lt;get_requests+83&gt;:   mov    DWORD PTR &#x5B;esp],eax\r\n0x0804bd9d &lt;get_requests+86&gt;:   call   0x8048e5c &lt;read@plt&gt;\r\n...\r\n0x0804be09 &lt;get_requests+194&gt;:  mov    eax,DWORD PTR &#x5B;ebp+eax*4-0x414]\r\n0x0804be10 &lt;get_requests+201&gt;:  mov    DWORD PTR &#x5B;esp],eax\r\n0x0804be13 &lt;get_requests+204&gt;:  call   0x804a9c2 &lt;free&gt;\r\n...\r\n<\/pre>\n<p>When the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> calloc() <\/span>function returns, it saves the pointer to the allocated heap space in EAX (get_requests+40). That pointer is saved to the stack at &#8220;ebp-0x14&#8221; (get_requests+45), which is where the <strong>buf<\/strong> variable is saved. This is then saved to EDX (get_requests+51). Finally, that pointer to the heap is stored in the character pointer array, with EAX containing the index number (get_requests+54). Each pointer in the array is 4 bytes in length, so the &#8220;eax*4&#8221; is a giveaway that it&#8217;s accessing the only array,<span style=\"font-family:Courier New\"> destroylist[]<\/span>. That value is later used as an argument to the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> free() <\/span>function when it&#8217;s put onto the top of the stack (get_requests+194 &#038; get_requests+201).<\/p>\n<p>What this tells me, is that there <em>is<\/em> a line in the source code that looks something like<span style=\"font-family:Courier New;font-weight:bold\"> destroylist[dll] = buf; <\/span>My guess is that level was originally created with the source code you see, then updated when the author realized the level wasn&#8217;t exploitable and forgot to update the source code on the website. Now that <strong>Protostar<\/strong> has turned into <strong>Phoenix<\/strong>, the author of Phoenix used the non-exploitable version of the Final Two level.<\/p>\n<p>I included all of the instructions up until the call to<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> read() <\/span>(get_requests+86) in that last disassembly because that&#8217;s what I&#8217;ll show you in the <strong>final-two<\/strong> binary from <strong>Phoenix<\/strong>.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:\/opt\/phoenix\/i486$ gdb -q final-two\r\nGEF for linux ready, type `gef' to start, `gef config' to configure\r\n71 commands loaded for GDB 8.2.1 using Python engine 3.5\r\n&#x5B;*] 2 commands could not be loaded, run `gef missing` to know why.\r\nReading symbols from final-two...(no debugging symbols found)...done.\r\n\r\ngef&gt; disas get_requests\r\nDump of assembler code for function get_requests:\r\n   ...\r\n   0x0804899a &lt;+35&gt;:    call   0x804a53a &lt;calloc&gt;\r\n   0x0804899f &lt;+40&gt;:    add    esp,0x10\r\n   0x080489a2 &lt;+43&gt;:    mov    DWORD PTR &#x5B;ebp-0x14],eax\r\n   0x080489a5 &lt;+46&gt;:    sub    esp,0x4\r\n   0x080489a8 &lt;+49&gt;:    push   0x80\r\n   0x080489ad &lt;+54&gt;:    push   DWORD PTR &#x5B;ebp-0x14]\r\n   0x080489b0 &lt;+57&gt;:    push   DWORD PTR &#x5B;ebp+0x8]\r\n   0x080489b3 &lt;+60&gt;:    call   0x8048700 &lt;read@plt&gt;\r\n   ...\r\n   0x08048a1a &lt;+163&gt;:   mov    eax,DWORD PTR &#x5B;ebp+eax*4-0x414]\r\n   0x08048a21 &lt;+170&gt;:   sub    esp,0xc\r\n   0x08048a24 &lt;+173&gt;:   push   eax\r\n   0x08048a25 &lt;+174&gt;:   call   0x8049a12 &lt;free&gt;\r\n   ...\r\n<\/pre>\n<p>As you can see, the pointer that&#8217;s returned by the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> calloc() <\/span>function (stored in EAX) is saved to the <strong>buf<\/strong> variable, which is stored on the stack at &#8220;ebp-0x14&#8221; (get_requests+43). However, nothing else is done with that value until it&#8217;s pushed onto the stack (get_requests+54) as an argument for the call to<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> read() <\/span>(get_requests+60). Later in the function during the for loop, the values in the<span style=\"font-family:Courier New\"> destroylist[] <\/span>array are pushed onto the stack to be passed to<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> free() <\/span>as parameters (get_requests+163 &#038; get_requests+173). However, nothing was ever stored there.<\/p>\n<h1>Conclusion<\/h1>\n<p>Maybe it&#8217;s just my lack of experience, but it doesn&#8217;t seem this level is exploitable. I believe the intended method is for the attacker to send 2 requests, the first one being a valid request while the second one is missing a &#8220;\/&#8221; character before the &#8220;ROOT&#8221; string. After the &#8220;ROOT&#8221; string, you would have a &#8220;\/&#8221; character followed by values to overwrite the <strong>prev_size<\/strong> and <strong>size<\/strong> metadata for the second chunk. After that, you could include pointer values to be able to arbitrarily overwrite (almost) any location with (almost) any value, 4 bytes long, of course. Everything after that last &#8220;\/&#8221; character in the second request would get copied to the first request after the last &#8220;\/&#8221; character.<\/p>\n<p>Again, for more details on how this is done and why it works, see my solution to the <strong><a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-heap-three-solution\/\">Heap Three<\/a><\/strong> level.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Remote heap overflow &hellip; <a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-final-two-solution\/\" class=\"more-link\"><span class=\"readmore\">Continue reading<span class=\"screen-reader-text\">Exploit Education | Phoenix | Final Two Solution<\/span><\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-849","post","type-post","status-publish","format-standard","hentry","category-solutions"],"_links":{"self":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/849","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/comments?post=849"}],"version-history":[{"count":38,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/849\/revisions"}],"predecessor-version":[{"id":856,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/849\/revisions\/856"}],"wp:attachment":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/media?parent=849"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/categories?post=849"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/tags?post=849"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}