<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Writeups on</title><link>/categories/writeups/</link><description>Recent content in Writeups on</description><generator>Hugo -- gohugo.io</generator><lastBuildDate>Thu, 17 Jul 2025 21:00:16 +0100</lastBuildDate><atom:link href="/categories/writeups/index.xml" rel="self" type="application/rss+xml"/><item><title>Toxicity - SummerRush CTF</title><link>/post/sr25-toxicity/</link><pubDate>Thu, 17 Jul 2025 21:00:16 +0100</pubDate><guid>/post/sr25-toxicity/</guid><description>Click to expand challenge code
from Crypto.Util.number import bytes_to_long from os import urandom from PIL import Image import numpy as np import random class DoubleLCG: def __init__(self, a1,a2, b1,b2, m, seed1, seed2): self.a1 = a1 self.a2 = a2 self.b1 = b1 self.b2 = b2 self.m = m self.state1 = bytes_to_long(urandom(6)) if seed1 is None else seed1 self.state2 = bytes_to_long(urandom(6)) if seed2 is None else seed2 self.counter = 0 def refresh(self): self.</description></item><item><title>Jigsaw Falling into Place - SummerRush CTF</title><link>/post/sr25-jigsaw/</link><pubDate>Thu, 17 Jul 2025 20:06:16 +0100</pubDate><guid>/post/sr25-jigsaw/</guid><description>Click to expand challenge code
from random import Random from Crypto.Util.number import bytes_to_long, long_to_bytes from Crypto.Cipher import AES from Crypto.Util.Padding import pad import os FLAG = os.getenv(&amp;quot;FLAG&amp;quot;, &amp;quot;FL1TZ{dummy_dum_dum}&amp;quot;) COLOR_BLACK = &amp;quot;\x1b[30m&amp;quot; COLOR_RED = &amp;quot;\x1b[31m&amp;quot; COLOR_GREEN = &amp;quot;\x1b[32m&amp;quot; COLOR_YELLOW = &amp;quot;\x1b[33m&amp;quot; COLOR_BLUE = &amp;quot;\x1b[34m&amp;quot; COLOR_MAGENTA = &amp;quot;\x1b[35m&amp;quot; COLOR_CYAN = &amp;quot;\x1b[36m&amp;quot; COLOR_RESET = &amp;quot;\x1b[0m&amp;quot; BOLD = &amp;quot;\x1b[1m&amp;quot; RESET_BOLD = &amp;quot;\x1b[22m&amp;quot; class Jigsaw: def __init__(self): self.dealer = Random() def get_piece(self): return self.</description></item><item><title>Flashing Lights - SummerRush CTF</title><link>/post/sr25-lights/</link><pubDate>Thu, 17 Jul 2025 19:31:16 +0100</pubDate><guid>/post/sr25-lights/</guid><description>Click to expand challenge code
from hashlib import sha256 from Crypto.Util.number import bytes_to_long, long_to_bytes from random import randint from Crypto.Cipher import AES from Crypto.Util.Padding import pad import json FLAG = b&amp;quot;FL1TZ{??????????????????????????}&amp;quot; p = 0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377 a = -3 b = 27 E = EllipticCurve(GF(p), [a,b]) G = E.gens()[0] j = E.j_invariant() def gen_random_number(): while True: P = E.random_point() if P.order() &amp;gt; j: break return bytes_to_long(sha256(long_to_bytes(int(P.xy()[0]))).digest()[:8]) def derive_key_iv(secret): key = sha256(long_to_bytes(secret)).</description></item><item><title>End of a Beginning - SummerRush CTF</title><link>/post/sr25-eob/</link><pubDate>Thu, 17 Jul 2025 18:48:16 +0100</pubDate><guid>/post/sr25-eob/</guid><description>Click to expand challenge code
package main import ( &amp;quot;bufio&amp;quot; &amp;quot;crypto/rand&amp;quot; &amp;quot;encoding/hex&amp;quot; &amp;quot;fmt&amp;quot; &amp;quot;log&amp;quot; &amp;quot;math/big&amp;quot; &amp;quot;net&amp;quot; &amp;quot;strings&amp;quot; ) const LEN = 31 const MASK = (1 &amp;lt;&amp;lt; LEN) - 1 const FLAG = &amp;quot;FL1TZ{?????????????????????????????}&amp;quot; var taps1 = []int{/*?, ?, ?, ?*/} var taps2 = []int{/*?, ?, ?, ?*/} type LFSR struct { state uint64 taps []int count int } func (l *LFSR) rekey(newseed uint64) { l.state = newseed } func newLFSR(taps []int) *LFSR { seed := genRandSeed() return &amp;amp;LFSR{state: seed, taps: taps} } func (l *LFSR)lfsrStep() uint8 { feedback := uint64(0) if l.</description></item><item><title>Give me Novacain - SummerRush CTF</title><link>/post/sr25-novacain/</link><pubDate>Thu, 17 Jul 2025 18:06:16 +0100</pubDate><guid>/post/sr25-novacain/</guid><description>Click to expand challenge code
#!/usr/bin/env python3 &amp;quot;&amp;quot;&amp;quot; Prove you know a satisfying assignment without revealing it—1 take per round, no pain. Protocol (each round): 1) Commit to each bit of your assignment. 2) I&#39;ll challenge you &amp;gt;:) 3) I&#39;ll pen either the full assignment or just the clause bits. 4) Survive all 128 rounds, and I might just give yout the flag. &amp;quot;&amp;quot;&amp;quot; import random import hashlib from Crypto.</description></item><item><title>Puppet - SummerRush CTF</title><link>/post/sr25-puppet/</link><pubDate>Thu, 17 Jul 2025 17:57:16 +0100</pubDate><guid>/post/sr25-puppet/</guid><description>Click to expand challenge code
import os import secrets import sys import time from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad SERVER_KEY = secrets.token_bytes(16) FLAG = os.environ.get(&amp;quot;FLAG&amp;quot;, &amp;quot;FL1TZ{????????????}&amp;quot;) def issue_token(user_id: str) -&amp;gt; bytes: iv = secrets.token_bytes(16) payload = f&amp;quot;uid={user_id}&amp;amp;role=puppet&amp;quot;.encode() cipher = AES.new(SERVER_KEY, AES.MODE_CBC, iv=iv) return iv + cipher.encrypt(pad(payload,16)) def check_token(token: bytes) -&amp;gt; str: iv = token[:16] ct = token[16:] cipher = AES.new(SERVER_KEY, AES.MODE_CBC, iv=iv) pt = cipher.decrypt(ct) print(f&amp;quot;Decrypted token: {pt!</description></item><item><title>OK Computer - SummerRush CTF</title><link>/post/sr25-ok-computer/</link><pubDate>Thu, 17 Jul 2025 17:22:16 +0100</pubDate><guid>/post/sr25-ok-computer/</guid><description>Click to expand challenge code
from Crypto.Util.number import getPrime, bytes_to_long flag = &amp;quot;FL1TZ{*********}&amp;quot; p = getPrime(512) q = getPrime(512) n = p * q e = 5 m = bytes_to_long(flag.encode()) c = pow(m, e, n) data = { &amp;quot;n&amp;quot;: n, &amp;quot;e&amp;quot;: e, &amp;quot;c&amp;quot;: c } with open(&amp;quot;computer.json&amp;quot;, &amp;quot;w&amp;quot;) as f: import json json.dump(data, f, indent=4)
Since this CTF was destined to be pretty advanced, I didn&amp;rsquo;t want beginner players to leave with 0 solves.</description></item><item><title>Magical Oracle - L3akCTF 2025</title><link>/post/l3ak-oracle/</link><pubDate>Mon, 14 Jul 2025 19:47:16 +0100</pubDate><guid>/post/l3ak-oracle/</guid><description>This challenge was a standard Hidden Number Problem dressed up in fantasy cosplay. The objective was clear: uncover a hidden value $\alpha$ using Babai&#39;s CVP algorithm
Challenge Overview The challenge spins up a remote service that hands out:
p: A 256-bit prime modulus. n: The bit length of p, which is 256. k: The number of bits to be leaked, calculated as int(n**0.5) + n.bit_length() + 1, which comes out to 26.</description></item><item><title>Puzzle 4 - L3akCTF 2025</title><link>/post/l3ak-puzzle4/</link><pubDate>Mon, 14 Jul 2025 18:27:16 +0100</pubDate><guid>/post/l3ak-puzzle4/</guid><description>Just when we thought we had the system figured out, the authors straight up yeeted the crutch from underneath us: the reference image. The url field in the API response was some nonesense that led nowhere. We were essentially flying blind.
This challenge was a two-act play. First, solve a jigsaw puzzle with no picture on the box, that would award us with the source code for the platform. Second, use that source code to scout for a vulnerability that would yield us the flag.</description></item><item><title>Puzzle 3 - L3akCTF 2025</title><link>/post/l3ak-puzzle3/</link><pubDate>Mon, 14 Jul 2025 17:55:16 +0100</pubDate><guid>/post/l3ak-puzzle3/</guid><description>So, you saw how we handled the last puzzle. It was flashy, watching the browser solve itself was a neat party trick, but it&amp;rsquo;s hella inefficient. Relying on Selenium to brute-force the DOM with clicks felt like using a sledgehammer for brain surgery. For this next stage, the puzzles got harder and the timer got drastically shorter. It was time to evolve.
As hinted before, we knew there was a backend API.</description></item><item><title>Puzzle 2 - L3akCTF 2025</title><link>/post/l3ak-puzzle2/</link><pubDate>Mon, 14 Jul 2025 17:17:16 +0100</pubDate><guid>/post/l3ak-puzzle2/</guid><description>This is the second challenge in a 5-part series involving solving a scrablmed image puzzles (10 of them in this case) in record time, for the most part.
The first part is solvable manually, but this level increases the number of pieces and reduces the time limit for each puzzle, making atomation the clear path forward.
Hint Discovery Initial analysis of the web page revealed hint. The &amp;lt;h1&amp;gt; element containing the puzzle&amp;rsquo;s title was also an &amp;lt;a&amp;gt; tag, linking to an external site (which is X, but not always).</description></item><item><title>R3coin - R3CTF 2025</title><link>/post/r3coin/</link><pubDate>Tue, 08 Jul 2025 18:02:16 +0100</pubDate><guid>/post/r3coin/</guid><description>This challenge involves a blockchain-like system that uses a chameleon hash function for transaction integrity. The goal is to exploit the chameleon hash properties to forge a transaction &amp;ldquo;Selling|flag|x&amp;rdquo; that allows us to buy the flag.
Mechanics The app lets up perform a set of actions to interact with the chain:
Work: Gives us some money Buy Gift: Appends a &amp;ldquo;Buy&amp;rdquo; entry followed by a &amp;ldquo;Selling|gift|100&amp;rdquo; onto the chain Refund oldest: Turns the oldest &amp;ldquo;Buy&amp;rdquo; transaction into a &amp;ldquo;Work|x&amp;rdquo; entry by internally forging a satisfying hash.</description></item></channel></rss>