🌐 Some Assembly Required 1
A detailed write-up of the Web challenge 'Some Assembly Required 1' from PicoCTF - 2021
📊 Challenge Overview
Category Details Additional Info 🏆 Event PicoGym Event Link 🔰 Category Web 🌐 💎 Points 500 Out of 500 total ⭐ Difficulty 🟡 Medium Personal Rating: 2/10 👤 Author Sears Schulz Profile 🎮 Solves (At the time of flag submission) 32.470 solve rate 📅 Date 18-02-2025 PicoGym 🦾 Solved By mH4ck3r0n3 Team:
📝 Challenge Information
🎯 Challenge Files & Infrastructure
Provided Files
1
Files: None
🔍 Initial Analysis
First Steps
Initially, the website appears as follows:
As a first step, I immediately thought of
Web Assembly
due to the challenge title, so I inspected the page source and found a JavaScript file:The JavaScript code is quite obfuscated, and after searching online, I found a tool to help deobfuscate it a bit (https://unminify.com/):
This gave the following output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
const _0x402c = [ "value", "2wfTpTR", "instantiate", "275341bEPcme", "innerHTML", "1195047NznhZg", "1qfevql", "input", "1699808QuoWhA", "Correct!", "check_flag", "Incorrect!", "./JIFxzHyW8W", "23SMpAuA", "802698XOMSrr", "charCodeAt", "474547vVoGDO", "getElementById", "instance", "copy_char", "43591XxcWUl", "504454llVtzW", "arrayBuffer", "2NIQmVj", "result", ]; const _0x4e0e = function (_0x553839, _0x53c021) { _0x553839 = _0x553839 - 0x1d6; let _0x402c6f = _0x402c\[_0x553839]; return _0x402c6f; }; (function (_0x76dd13, _0x3dfcae) { const _0x371ac6 = _0x4e0e; while (!![]) { try { const _0x478583 = -parseInt(_0x371ac6(0x1eb)) + parseInt(_0x371ac6(0x1ed)) + -parseInt(_0x371ac6(0x1db)) * -parseInt(_0x371ac6(0x1d9)) + -parseInt(_0x371ac6(0x1e2)) * -parseInt(_0x371ac6(0x1e3)) + -parseInt(_0x371ac6(0x1de)) * parseInt(_0x371ac6(0x1e0)) + parseInt(_0x371ac6(0x1d8)) * parseInt(_0x371ac6(0x1ea)) + -parseInt(_0x371ac6(0x1e5)); if (_0x478583 === _0x3dfcae) break; else _0x76dd13\["push"](_0x76dd13\["shift"]()); } catch (_0x41d31a) { _0x76dd13\["push"](_0x76dd13\["shift"]()); } } })(_0x402c, 0x994c3); let exports; (async () => { const _0x48c3be = _0x4e0e; let _0x5f0229 = await fetch(_0x48c3be(0x1e9)), _0x1d99e9 = await WebAssembly\[_0x48c3be(0x1df)](await _0x5f0229\[_0x48c3be(0x1da)]()), _0x1f8628 = _0x1d99e9\[_0x48c3be(0x1d6)]; exports = _0x1f8628\["exports"]; })(); function onButtonPress() { const _0xa80748 = _0x4e0e; let _0x3761f8 = document\["getElementById"](_0xa80748(0x1e4))\[_0xa80748(0x1dd)]; for (let _0x16c626 = 0x0; _0x16c626 < _0x3761f8\["length"]; _0x16c626++) { exports\[_0xa80748(0x1d7)](_0x3761f8\[_0xa80748(0x1ec)](_0x16c626), _0x16c626); } exports\["copy_char"](0x0, _0x3761f8\["length"]), exports\[_0xa80748(0x1e7)]() == 0x1 ? (document\[_0xa80748(0x1ee)](_0xa80748(0x1dc))\[_0xa80748(0x1e1)] = _0xa80748(0x1e6)) : (document\[_0xa80748(0x1ee)](_0xa80748(0x1dc))\[_0xa80748(0x1e1)] = _0xa80748(0x1e8)); }
Renaming the variables and doing some “reverse engineering,” I arrived at the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
const dictionary = [ "value", "2wfTpTR", "instantiate", "275341bEPcme", "innerHTML", "1195047NznhZg", "1qfevql", "input", "1699808QuoWhA", "Correct!", "check_flag", "Incorrect!", "./JIFxzHyW8W", "23SMpAuA", "802698XOMSrr", "charCodeAt", "474547vVoGDO", "getElementById", "instance", "copy_char", "43591XxcWUl", "504454llVtzW", "arrayBuffer", "2NIQmVj", "result", ]; const getKey = function (index) { index = index - 470; return dictionary\[index]; }; let exports; (async () => { let wasmFile = await fetch(getKey(489)), wasmModule = await WebAssembly\[getKey(471)](await wasmFile\[getKey(482)]()), wasmInstance = wasmModule\[getKey(470)]; exports = wasmInstance\["exports"]; })(); function onButtonPress() { let inputText = document\[getKey(480)]("input")\[getKey(472)]; for (let i = 0; i < inputText.length; i++) { exports\[getKey(474)](inputText\[getKey(479)](i), i); } exports\["copy_char"](0, inputText.length); if (exports\[getKey(475)]() == 1) { document\[getKey(480)]("result")\[getKey(473)] = getKey(476); } else { document\[getKey(480)]("result")\[getKey(473)] = getKey(478); } }
From the last cleaning of the code, we can see that a file
./JIFxzHyW8W
(the twelfth element of thedictionary
array, since the functiongetKey(482)
is called, where482-470=12
) is being loaded, which will be inwasm
(Web Assembly) format. The first thing I did was visit the routehttp://mercury.picoctf.net:1896/JIFxzHyW8W
to download the file and analyze it. This can also be done directly withcurl
by specifying the flag--output filename
:
1
curl http://mercury.picoctf.net:1896/JIFxzHyW8W --output JIFxzHyW8W
(You can also rename the file in the
--output
flag, but I preferred to leave it as is). To verify the file, I also used thefile
command to begin a preliminary analysis of it:Now that we have everything we need, we can move on to the exploitation phase.
🎯 Solution Path
Exploitation Steps
Exploitation
The exploitation could be done in several ways, but a simple static analysis of the file using commands like
strings
,xxd
,wasm2wat
, etc., is enough to extract the flag text from thewasm
file. Personally, I started the analysis withstrings
and quickly and clearly found the flag:
1
strings JIFxzHyW8W
Flag capture
🛠️ Exploitation Process
Approach
The automatic exploit downloads the
.wasm
file from the server and usessubprocess
to executestrings
on the.wasm
file. Then, it extracts the flag from the output using a regex.
🚩 Flag Capture
Flag
Proof of Execution
🔧 Tools Used
Tool Purpose Python Exploit Strings WASM Analysis
💡 Key Learnings
Skills Improved
- Binary Exploitation
- Reverse Engineering
- Web Exploitation
- Cryptography
- Forensics
- OSINT
- Miscellaneous
📊 Final Statistics
Metric | Value | Notes |
---|---|---|
Time to Solve | 00:10 | From start to flag |
Global Ranking (At the time of flag submission) | Challenge ranking | |
Points Earned | 500 | Team contribution |
Created: 18-02-2025 • Last Modified: 18-02-2025 *Author: mH4ck3r0n3 • Team: *