HTB: Query Challenge
Query - HackTheBox Challenge Writeup
Challenge Information
| Field | Value |
|---|---|
| Name | Query |
| Category | Misc |
| Difficulty | Medium |
| Author | d3vn0mi |
Description
While investigating a phishing attempt, you came across a suspicious JavaScript file. Can you find out more about it?
This challenge presents a heavily obfuscated JavaScript file (htb.js) that serves as a phishing/DNS exfiltration payload. The flag is hidden within multiple layers of obfuscation, requiring reverse engineering and careful analysis to extract.
Solution Overview
The challenge involves peeling back three distinct layers of obfuscation:
- jjencode wrapper — JavaScript encoding format
- Dean Edwards packer — Code compression and obfuscation
- obfuscator.io RC4 string-array defense — String array rotation with per-call RC4 decryption
The actual flag is encoded as an RC4-encrypted string within the obfuscated payload, requiring replay of 361 array rotation operations to decode correctly.
Key Steps
Step 1: Initial Analysis
First, examine the suspicious JavaScript file to understand its structure:
wc -l htb.jswc -c htb.jshead -c 3000 htb.jsThe file contains multiple layers of obfuscation wrapped within jjencode and Dean Edwards packer formats.
Step 2: Extract from jjencode Wrapper
Create a Node.js script to capture the first unpacked layer:
const fs = require('fs');const vm = require('vm');const src = fs.readFileSync('htb.js', 'utf8');
const capture = {};capture.console = { log: (x) => console.log('LOG:', x) };capture.document = { write: (x) => console.log('WRITE:', x) };capture.eval = eval;
const ctx = vm.createContext(capture);try { vm.runInContext(src, ctx, { timeout: 2000 });} catch (e) { console.error('Error:', e.message);}Step 3: Dean Edwards Unpacker
The captured output reveals a Dean Edwards packed structure. Decode it:
const fs = require('fs');let s = fs.readFileSync('/tmp/captured.txt', 'utf8').trim();
// Extract the packed content between 'return"' and the closing quoteconst body = s.substring(s.indexOf('return"') + 7, s.lastIndexOf('"'));
// Base64 decode the packed contentconst decoded = Buffer.from(body, 'base64').toString('utf8');fs.writeFileSync('/tmp/decoded1.js', decoded);Step 4: Identify the String Array Rotation Defense
The unpacked code reveals obfuscator.io RC4 protection with a rotating string array:
const _0x576b=['ir1cba==','W7ddKZVcOCo7','gJ4sWQ8aESk3yb3cJG==', /* ... 358 more strings ... */];
function _0x2559d6(a, b) { const c = _0x576b.slice(); while(true) { c.push(c.shift()); // Rotation happens here // ... RC4 decryption using rotated array ... }}Step 5: Replay the Array Rotation (361 iterations)
The critical insight: the string array undergoes 361 shift/push rotations. To decode strings correctly, replay these rotations:
const _0x576b = ['ir1cba==','W7ddKZVcOCo7','gJ4sWQ8aESk3yb3cJG==', /* ... full array ... */];
// Perform 361 rotationsfor (let i = 0; i < 361; i++) { _0x576b.push(_0x576b.shift());}
// Now the array is in the correct state for RC4 decryptionconsole.log('Array rotated 361 times');Step 6: RC4 Decryption
With the array properly rotated, the RC4 decryption keys align correctly:
// After rotation, the per-call RC4 keys decode properlyconst encryptedDomain = _0x576b[0]; // The RC4-encrypted exfil domainconst decrypted = rc4Decrypt(key, encryptedDomain);const flagBase64 = decrypted;const flag = Buffer.from(flagBase64, 'base64').toString('utf8');console.log('Flag:', flag);Step 7: Extract the Flag
The decrypted output reveals:
echo "SFRCe2ZPdU5kX2NMNHIxdHlfaU5fMGJmVXNjYVQhb059" | base64 -dResult: HTB{REDACTED}
Red Herrings
The challenge includes a decoy base64-encoded string that decodes to:
echo "SFRCe3NvcnJ5X2J1dF90aGlzX2lzX25vdF95b3VyX2ZsYWd9" | base64 -d# Output: HTB{REDACTED}This is a false flag intentionally placed to mislead. The actual flag is hidden in the RC4-encrypted “domain” string within the rotated string array.
Tools Used
- Node.js — Unpacking jjencode and executing obfuscated code
- Bash/Echo — Base64 decoding and command execution
- Python — String manipulation and analysis
- Text processing — grep, head, wc for analyzing file structure
Key Learnings
-
Layered Obfuscation — Security through obscurity often requires peeling back multiple encoding formats. Understand jjencode, Dean Edwards packer, and obfuscator.io techniques.
-
String Array Rotation Defense — obfuscator.io uses rotating string arrays to prevent static string extraction. The rotation counter must be replayed exactly to decode RC4-encrypted strings.
-
Payload Analysis — The payload itself is a phishing/DNS exfiltration script. The “domain” field is actually RC4-encrypted data, not a real domain.
-
Decoy Detection — Malicious scripts may contain intentional decoys (fake flags) to waste time. Cross-reference findings and verify the context.
-
VM Context Limitations — Using Node.js
vmmodule with custom contexts allows safe execution and capture of obfuscated payloads without triggering dangerous behavior.
Flag
HTB{REDACTED}