126 lines
4.4 KiB
JavaScript
126 lines
4.4 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']) {
|
|
const threads = args['cpu'] || maxThreads(ns, args['script'], args['server']);
|
|
if(!threads) {
|
|
ns.tprint(`Server does not have enough RAM to start script.`);
|
|
ns.exit();
|
|
}
|
|
// 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
|
|
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['script'], 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];
|
|
}
|