A collection of challenges I made for CTF competitions
| Name | Category | TL;DR | Solves |
|---|---|---|---|
| Unrealistic Client-Side Challenge - Flag 2 | Web | Intended solution: Achieving XSS by abusing the bfcache → disk cache fallback + bypassing Chrome's double-keyed cache partitioning. Cookie jar overflow to overwrite an HTTP-only cookie that is rendered serverside. DOM clobbering + ISO-2022-JP encoding to exfiltrate a flag otherwise unconsumeable by dom clobbering. Unintended solution: DNS rebinding shenanigans :( | 7/1736 |
| Vulnerability Research | Web | Exploiting a 0-day vulnerability in a full-stack Python web framework | 11/1736 |
| Unrealistic Client-Side Challenge - Flag 1 | Web | Achieving XSS by abusing the bfcache → disk cache fallback + bypassing Chrome's double-keyed cache partitioning. Cookie jar overflow to overwrite an HTTP-only cookie that is rendered serverside. Cookie sandwich attack + DOM clobbering to exfiltrate a flag embedded inside an HTTP-only JWT. Unintended solution: DNS rebinding shenanigans :( | 12/1736 |
| Pasteboard | Web | XSS on localhost → Chromedriver RCE | 33/1736 |
| Nothing Ever Changes | Misc | Generating adversarial images from a reference MNIST sample under a tight L_0 perturbation budget, forcing a target misclassification while preserving the same MD5 hash. Intended solution: Jacobian-based Saliency Map Attack (JSMA) combined with an MD5 collision on PNGs | 36/1736 |
| ML Connoisseur | Rev | A heavily obfuscated neural-network VM with bytecode embedded in the model weights. The model includes a trojan classifier using hardcoded reference logits and an invertible side branch. Intended solve: reverse the VM architecture, invert transformations in the disassembly for exact recovery of the reference image. Unintended solve: optimize the input image toward class 10 (everyone did this, sad) | 112/1736 |
| No Quotes 3 | Web | Fragmented SQL injection + string encoding to bypass a firewall blocking quotes and periods. The injection payload must be constructed as a SHA-256 hash quine to bypass SQL-side and python-side verification. RCE via SSTI in rendered username | 129/1736 |
| Lottery | Misc | Achieving code execution by abusing unsafe use of Bash's let keyword to inject commands into arithmetic expressions |
130/1736 |
| Orca | Crypto | Pick-a-block ECB oracle with a secret fixed block permutation + fixed-length prefix (bytes randomized per query) | 189/1736 |
| No Quotes 2 | Web | Fragmented SQL injection + string encoding to bypass a firewall blocking quotes. The injection payload must be constructed as an SQL quine to bypass SQL-side and python-side verification. RCE via SSTI in rendered username | 209/1736 |
| Symbol of Hope | Rev | A flag checker composed of many chained functions and operations, intended as an introductory challenge to symbolic execution | 225/1736 |
| Bring Your Own Program | Rev | Exploiting a stale inline cache bug in an JavaScript bytecode VM to confuse property slot lookups after optimizations, gaining access to an otherwise inaccessible internal function for reading arbitrary files | 242/1736 |
| Baby (Obfuscated) Flag Checker | Rev | Obfuscated python flag checker | 369/1736 |
| No Quotes | Web | Fragmented SQL injection + string encoding to bypass a firewall blocking quotes. RCE via SSTI in rendered username | 410/1736 |
| Name | Category | TL;DR | Solves |
|---|---|---|---|
| Quantam Exfil | Rev | Analyzing an obfuscated program implementating a custom steganography algorithm. The cipher algorithm is hidden inside a stack-based VM, then further obfuscated using transformations such as: control-flow flattening, proxy functions, string splitting/concealing, and constant unfolding. Includes NodeJS C++ addon reverse engineering. Co-authored with ben-sb | 0/2243 |
| Math as a Service | Misc | Exploiting a fully-patched version of the expr-eval library. By downgrading the library to use CommonJS modules (and without modifying any of the core logic), a "simulated 0-day" vulnerability is introduced | 3/2243 |
| I Did a Thing | Rev | A deep dive into reverse engineering an advanced Javascript virtualization obfuscation. The VM has many features: control-flow aware instruction decryption, opcode shuffling, multiple anti-debug and anti-temper checks. The encryption algorithm implemented in the original program relies on current timestamp and the exact source of the VM interpreter running it. A small love letter from me to JS Obfuscation ❤️ | 4/2243 |
| Useless VM | Rev | Recovering source code from a program first obfuscated with JSFuck and then compiled into the same VM as I Did a Thing. A demonstration of how layered obfuscation does not necessarily increase reverse engineering difficulty | 12/2243 |
| Name | Category | TL;DR | Solve Count |
|---|---|---|---|
| JS Blacklist V2 | Jail | Using @babel/parser'screateImportExpressions, NodeJS dynamic import quirk, smuggling a data URI into the toString of a class via LabeledStatement |
0/1510 |
| Model Assembly Line | Misc | Exploiting typing.get_type_hints gadget in spacy-llm |
2/1510 |
| Simple File Storage | Misc | Bypassing file upload validation via parsing differential between php's ZipArchive and 7z when extracting a zip/tar polyglot |
2/1510 |
| Don't Sandbox Python 2: simple | Jail | 0-day in asteval, hardened to use no numpy imports | 3/1510 |
| Don't Sandbox Python 3: barebones | Jail | 0-day in asteval, hardened to use no numpy imports and an empty symtable | 3/1510 |
| My Second App | Web | Hash-length extension + hard(est?) Jinja2 SSTI filter | 5/1510 |
| Prepared: Flag 2 | Web | SQLi filter bypass via python double format string + RCE via writing a malicious shared object using INTO DUMPFILE and executing it using double format string attack + ctypes.cdll.__getitem__ gadget |
6/1510 |
| Timeless | Web | Cracking UUIDv1-based Flask SECRET_KEY, arbitrary file write, exploiting pickle deserialization in flask-session |
6/1510 |
| Smol JS | Jail | Smuggling code into comments, referencing variable storing unsanitized code | 7/1510 |
| Don't Sandbox Python 1: n-day? | Jail | n-day in asteval | 11/1510 |
| 1337 v4ul7 | Web | JWT public+private key recovery, LFI to read source code of a node module | 13/1510 |
| Bloatware | Rev | Flag-checker obfuscated with Mixed Boolean-Arithmetic (MBA) | 14/1510 |
| Prepared: Flag 1 | Web | SQLi filter bypass via python double format string | 33/1510 |
| CodeDB | Web | ReDoS in search feature to leak contents of a hidden file | 55/1510 |
| Decrypt Me | Forensics | Cracking RAR archive with rockyou.txt, extracting an alternate data stream, and recovering AES keys generated by time-based PRNG | 86/1510 |
| Scavenger Hunt | Web | Classic CTF scavanger hunt with a flag split into several parts | 501/1510 |
| Name | Category | TL;DR | Solves |
|---|---|---|---|
| Refactor as a Service 2 | Misc | Blocking previously found #execute gadget, auditing src to find insecure use of eval, escaping double quotation context by injecting a backslash -- Based on CVE-2024-36120 |
3/497 |
| Refactor as a Service 1 | Misc | Error-based information disclosure to leak used npm package, reading documentation to find and leverage the #execute function evaluation feature |
7/497 |
| Name | Category | TL;DR | Solves |
|---|---|---|---|
| JS Evaluator | Jail | Simulated 0-day in custom patched version of Babel's path.evaluate() | 2 / 1225 |
| JS Blacklist | Jail | AST-based Javascript jail with a long, restrictive blacklist | 4 / 1225 |
| Secret Message 2 | Forensics | Recovering plaintext from a pixelated image | 10 / 1225 |
| Jay's Bank | Web | JSON Injection + SQL truncation via overflow using "İ".toLowerCase() | 17 / 1225 |
| My First App | Web | Jinja2 SSTI with very restrictive blacklist | 32 / 1225 |
| Zero | Jail | Pyjail with no builtins, letters, numbers, or double underscores | 34 / 1225 |
| Baby JS Blacklist | Jail | AST-based Javascript jail with no CallExpressions | 74 / 1225 |
| No Code | Web | Bypassing DOTALL-lacking regex with newline | 148 / 1225 |
| Enable Me | Forensics | Reversing VBA macro in docx file | 150 / 1225 |
| The Varsity | Web | parseInt() shenanigans | 181 / 1225 |
| Baby's First Pyjail | Jail | Beginner sourceless pyjail, breakpoint() | 295 / 1225 |
| repeat | Crypto | Deriving repeated XOR key with known plaintext | 317 / 1225 |
| Secret Message 1 | Forensics | Retrieving redacted data from PDF with pdftotext | 730 / 1225 |
| Name | Category | TL;DR | Solves |
|---|---|---|---|
| Library | Web | LFI with non-recursive stripping, enumerating package.json to discover hidden files + nodejs version | 4 / 57 |
| Secret Password | Reverse Engineering | Obfuscated Javascript flag-checker | 7 / 57 |