Post

CWES Cheatsheet — JavaScript Deobfuscation

CWES Cheatsheet — JavaScript Deobfuscation

obfuscated JavaScript is common in CTFs and real-world recon. learning to read and deobfuscate it helps you find hidden endpoints, credentials, and logic that devs didn’t want you to see.


Code Obfuscation Basics

Obfuscation makes code harder to read without changing its behavior.

Common Obfuscation Techniques

TechniqueDescription
Variable renamingusername_0x3a1f
String encodingStrings split, hex/base64 encoded
Dead code injectionIrrelevant code added to confuse
Control flow flatteningif/else replaced with switch/state machine
PackerCode compressed + wrapped in eval/decoding stub
Array shufflingStrings stored in shuffled array, referenced by index
eval() wrappersEntire code passed to eval() at runtime

Spotting Obfuscated JS

1
2
3
4
5
// Signs to look for:
eval(function(p,a,c,k,e,d){...})   // packer pattern
var _0xabc1=['\x68\x65\x6c\x6c\x6f'];  // hex-encoded strings
String.fromCharCode(72,101,108,108,111)  // charcode array
atob('aGVsbG8=')                    // base64 inline

Deobfuscation Techniques

Tools: beautifier.io, de4js, browser devtools

Step 1: Beautify first

1
2
3
4
5
6
7
8
# Online tools
# https://beautifier.io
# https://de4js.kshift.me
# https://prettier.io/playground

# Local with Node.js
npm install -g js-beautify
js-beautify obfuscated.js -o clean.js

Step 2: Identify the encoding scheme

1
2
3
4
5
6
7
8
9
10
11
// Hex strings
'\x68\x65\x6c\x6c\x6f'   // decode in console: "\x68\x65\x6c\x6c\x6f"

// Unicode escapes
'\u0068\u0065\u006c\u006c\u006f'

// Base64
atob('aGVsbG8=')           // → "hello"

// Char codes
String.fromCharCode(72,101,108)  // run in console

Step 3: Use browser DevTools

1
2
3
4
1. Open DevTools → Sources tab
2. Paste obfuscated code in console (read-only, don't execute untrusted code)
3. Use "Pretty print" button ({}) to format minified code
4. Set breakpoints to inspect variable values at runtime

Minified vs Obfuscated

 MinifiedObfuscated
GoalReduce file sizeHide logic
ReversibleYes — beautifyPartially — depends on technique
Variable namesShortened but readableReplaced with _0x... junk
StringsReadableEncoded (hex, base64, charcode)
Toolbeautifier.iode4js, manual analysis

Decoding Encoded Strings

Tools: CyberChef, atob(), manual

1
2
3
4
5
6
7
8
9
10
11
12
// Base64 — decode in browser console
atob('aGVsbG8gd29ybGQ=')         // → "hello world"
btoa('hello world')               // encode

// Hex string
'\x68\x65\x6c\x6c\x6f'          // paste in console → "hello"

// Char code array
String.fromCharCode(104,101,108,108,111)  // → "hello"

// URL-encoded
decodeURIComponent('%68%65%6c%6c%6f')    // → "hello"

CyberChef Recipes

1
2
3
4
5
From Base64 → output
From Hex → output
From Charcode → output
URL Decode → output
Magic (auto-detect) → often works for simple encoding

Analysing Deobfuscated Code

After cleaning up the code, look for:

1
2
3
4
5
6
7
8
9
10
11
12
13
// API endpoints hidden in strings
fetch('/api/v1/secret-endpoint')
XMLHttpRequest.open('POST', '/internal/admin')

// Hardcoded credentials or tokens
var apiKey = 'sk-xxxxxxxxxxxxxxxx'
var password = 'sup3r_s3cr3t'

// Hidden parameters
var hiddenParam = 'debug=true&admin=1'

// Conditional logic that reveals bypass paths
if (user.role === 'admin') { /* skip auth */ }

← Back to CWES Cheatsheet Index

This post is licensed under CC BY 4.0 by the author.