bitburner/scripts/rootkit.js
2022-04-20 11:32:10 -04:00

122 lines
4.3 KiB
JavaScript

import {ArgParser} from '/scripts/lib/arg-parser';
import {maxThreads, progressBar, slowPrint} from '/scripts/lib/utils';
import {copyWithDependencies} from '/scripts/copy';
/**
* Check if exploit is available for use.
*
* @param {NS} ns - BitBurner API
* @returns {string[]} - Available exploits
*/
export function availableExploits(ns) {
return ['BruteSSH.exe', 'FTPCrack.exe', 'relaySMTP.exe', 'HTTPWorm.exe', 'SQLInject.exe']
.filter(e => ns.fileExists(e));
}
/**
* Attempt to root a server.
*
* @param {NS} ns - BitBurner API
* @param {string} server - Server to attempt to root
* @returns {[boolean, string[]]} - Tuple of whether the server was successfully rooted & the exploits which where ran
*/
export function root(ns, server) {
function runExploit(name) {
if(name == 'BruteSSH.exe') ns.brutessh(server);
else if(name == 'FTPCrack.exe') ns.ftpcrack(server);
else if(name == 'relaySMTP.exe') ns.relaysmtp(server);
else if(name == 'HTTPWorm.exe') ns.httpworm(server);
else if(name == 'SQLInject.exe') ns.sqlinject(server);
}
const exploits = availableExploits(ns);
exploits.forEach(e => runExploit(e));
try {
ns.nuke(server)
return [true, exploits];
} catch {
return [false, exploits];
}
}
/**
* Automatically gain root access to a server. A file can also be uploaded & executed.
*
* @param {NS} ns - BitBurner API
*/
export async function main(ns) {
// Setup
ns.disableLog('ALL');
const argParser = new ArgParser('rootkit.js', 'Automatically gain root access to a server. A file can also be uploaded & executed.', [
{name: 'server', desc: 'Server to root, defaults to local server', optional: true, default: ns.getHostname()},
{name: 'script', desc: 'Script to copy & execute', optional: true},
{name: 'args', desc: 'Arguments for script. Forward the discovered server with: {{SERVER}}', optional: true, extras: true},
{name: 'cpu', desc: 'Number of CPU threads to start script with, will use maximum if not specified', flags: ['-c', '--cpu'], default: false},
{name: 'quite', desc: 'Suppress program output', flags: ['-q', '--quite'], default: false},
]);
const args = argParser.parse(ns.args);
if(args['script'] && !args['cpu']) args['cpu'] =
~~(ns.getServerMaxRam(args['server']) / ns.getScriptRam(args['script'], 'home')) || 1;
// Help
if(args['help'] || args['_error'].length)
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
// Banner
if(!args['quite']) {
ns.tprint('===================================================');
ns.tprint(`Rooting: ${args['server']}`);
ns.tprint('===================================================');
}
// Root server if access is restricted
if(!ns.hasRootAccess(args['server'])) {
const [rooted, exploits] = root(ns, args['server']);
if(exploits.length >= 1) await slowPrint(ns, 'Exploiting SSH (*:22)...');
if(exploits.length >= 2) await slowPrint(ns, 'Exploiting FTP (*:24)...');
if(exploits.length >= 3) await slowPrint(ns, 'Exploiting SMTP (*:25)...');
if(exploits.length >= 4) await slowPrint(ns, 'Exploiting HTTP (*:80)...');
if(exploits.length >= 5) await slowPrint(ns, 'Exploiting MSQL (*:3306)...');
ns.tprint(`Root: ${rooted ? 'Success!' : 'Failed'}`);
if(!rooted) ns.exit();
} else {
ns.tprint(`Root: Skipped`);
}
ns.tprint('');
// Start script if required
if(args['script']) {
// Copy script & it's dependencies
const files = await copyWithDependencies(ns, args['script'], args['server']);
if(!args['quite']) {
await ns.sleep(500);
ns.tprint('Copying files:');
for(let file of files) await progressBar(ns, file);
}
// Start the script
const threads = args['cpu'] || maxThreads(ns, args['file'], args['server']) || 1;
if(!args['quite']) {
ns.tprint('');
ns.tprint(`Executing with ${threads} thread${threads > 1 ? 's' : ''}...`);
await ns.sleep(500);
}
ns.killall(args['server']);
const pid = ns.exec(args['file'], args['server'], threads, args['args']);
if(!args['quite']) {
ns.tprint(!!pid ? 'Done!' : 'Failed to start');
ns.tprint('');
}
}
}
/**
* BitBurner autocomplete.
*
* @param {{servers: string[], txts: string[], scripts: string[], flags: string[]}} data - Contextual information
* @returns {string[]} - Pool of autocomplete options
*/
export function autocomplete(data) {
return [...data.servers, ...data.scripts];
}