HTB: Query Challenge

Query - HackTheBox Challenge Writeup

Challenge Information

FieldValue
NameQuery
CategoryMisc
DifficultyMedium
Authord3vn0mi

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:

  1. jjencode wrapper — JavaScript encoding format
  2. Dean Edwards packer — Code compression and obfuscation
  3. 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:

Terminal window
wc -l htb.js
wc -c htb.js
head -c 3000 htb.js

The 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 quote
const body = s.substring(s.indexOf('return"') + 7, s.lastIndexOf('"'));
// Base64 decode the packed content
const 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 rotations
for (let i = 0; i < 361; i++) {
_0x576b.push(_0x576b.shift());
}
// Now the array is in the correct state for RC4 decryption
console.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 properly
const encryptedDomain = _0x576b[0]; // The RC4-encrypted exfil domain
const 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:

Terminal window
echo "SFRCe2ZPdU5kX2NMNHIxdHlfaU5fMGJmVXNjYVQhb059" | base64 -d

Result: HTB{REDACTED}

Red Herrings

The challenge includes a decoy base64-encoded string that decodes to:

Terminal window
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

  1. Layered Obfuscation — Security through obscurity often requires peeling back multiple encoding formats. Understand jjencode, Dean Edwards packer, and obfuscator.io techniques.

  2. 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.

  3. Payload Analysis — The payload itself is a phishing/DNS exfiltration script. The “domain” field is actually RC4-encrypted data, not a real domain.

  4. Decoy Detection — Malicious scripts may contain intentional decoys (fake flags) to waste time. Cross-reference findings and verify the context.

  5. VM Context Limitations — Using Node.js vm module with custom contexts allows safe execution and capture of obfuscated payloads without triggering dangerous behavior.

Flag

HTB{REDACTED}