Skip to main content
Glama

runJohnTheRipper

Crack password hashes using John the Ripper on Pentest MCP. Input hash data and specify command-line options to perform brute-force or dictionary attacks for penetration testing.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
hashDataYesString containing the password hashes, one per line.
optionsNoArray of command-line options for JtR.

Implementation Reference

  • Core handler function for executing John the Ripper: sanitizes options, writes hashes to /tmp file, spawns 'john' for cracking and '--show' to retrieve cracked passwords, parses output, logs if professional mode, handles errors and cleanup.
    async function runJtR(hashData: string, rawOptions: string[] = []): Promise<{ fullOutput: string; cracked: string[] }> { let options: string[]; try { options = sanitizeOptions(rawOptions); } catch (error: any) { throw error; } if (!hashData) { throw new Error("Error: Hash data is required."); } // Use /tmp directory for temp files to avoid read-only directory issues const tempHashFile = path.join('/tmp', `jtr_hashes_${Date.now()}.txt`); let fullOutput = ""; let crackedPasswords: string[] = []; try { await fs.writeFile(tempHashFile, hashData); const crackingArgs = [...options, tempHashFile]; fullOutput += `--- Cracking Attempt ---\nExecuting: john ${crackingArgs.join(' ')}\n`; try { const crackResult = await runSpawnCommand('john', crackingArgs); fullOutput += `Exit Code: ${crackResult.code}\nStdout:\n${crackResult.stdout}\nStderr:\n${crackResult.stderr}\n`; } catch (error: any) { fullOutput += `Cracking command failed to execute: ${error.message}\n`; } const showArgs = ['--show', tempHashFile]; fullOutput += `--- Show Attempt ---\nExecuting: john ${showArgs.join(' ')}\n`; try { const showResult = await runSpawnCommand('john', showArgs); fullOutput += `Exit Code: ${showResult.code}\nStdout:\n${showResult.stdout}\nStderr:\n${showResult.stderr}\n`; crackedPasswords = showResult.stdout.split('\n').map(line => line.trim()).filter(line => line && !line.startsWith('0 passwords cracked') && !line.includes('guesses remaining')); } catch (error: any) { fullOutput += `Show command failed to execute: ${error.message}\n`; } await fs.unlink(tempHashFile); if (currentUserSession.mode === UserMode.PROFESSIONAL) { await logMessage(`Ran John the Ripper.\nOptions: ${options.join(' ')}\nCracked: ${crackedPasswords.length}.`); } return { fullOutput, cracked: crackedPasswords }; } catch (error: any) { console.error("Fatal error setting up John the Ripper execution:", error); try { await fs.unlink(tempHashFile); } catch { /* ignore */ } if (currentUserSession.mode === UserMode.PROFESSIONAL) { await logMessage(`John the Ripper FAILED fatally before execution.\nOptions: ${options.join(' ')}\nError: ${error.message}`); } throw new Error(`John the Ripper setup failed fatally: ${error.message}`); } }
  • Zod schema defining the input parameters for the runJohnTheRipper tool: hashData (required string of hashes) and options (optional array of JtR flags). Includes description with usage example.
    const jtrToolSchema = z.object({ hashData: z.string().describe("String containing the password hashes, one per line."), options: z.array(z.string()).optional().describe("Array of command-line options for JtR.") }).describe( "Crack password hashes using John the Ripper. Provide hashes and any JtR options." + " Run this after generating a wordlist. Example: `{\"hashData\":\"user:$1$hash\", \"options\":[\"--wordlist=/tmp/list.txt\"]}`" );
  • src/index.ts:839-849 (registration)
    MCP server.tool registration for 'runJohnTheRipper': binds the schema, extracts args, calls runJtR, formats response with cracked passwords and full output based on user mode, handles errors.
    server.tool("runJohnTheRipper", jtrToolSchema.shape, async ({ hashData, options } /*, extra */) => { console.error(`Received JtR:`, { hashData: `len=${hashData.length}`, options }); if (currentUserSession.mode === UserMode.STUDENT) console.warn("[Student Mode] Executing JtR."); try { const { fullOutput, cracked } = await runJtR(hashData, options || []); const responseContent: any[] = [ { type: "text", text: `JtR finished. Found ${cracked.length} cracked.` } ]; if (cracked.length > 0) responseContent.push({ type: "text", text: "\n**Cracked:**\n" + cracked.join("\n") }); responseContent.push({ type: "text", text: "\n--- Full JtR Output ---\n" + fullOutput }); // Keep full output return { content: responseContent }; } catch (error: any) { return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true }; } });
  • Helper function to safely spawn external commands using child_process.spawn, captures stdout/stderr, handles errors like command not found, used by runJtR to execute 'john'.
    async function runSpawnCommand(command: string, args: string[]): Promise<{ stdout: string; stderr: string; code: number | null }> { return new Promise((resolve, reject) => { console.error(`Attempting to spawn: ${command} ${args.join(' ')}`); // Added for debugging const process = spawn(command, args); let stdout = ''; let stderr = ''; process.stdout.on('data', (data) => { stdout += data.toString(); }); process.stderr.on('data', (data) => { stderr += data.toString(); }); process.on('error', (error) => { // Explicitly catch spawn errors (e.g., command not found) console.error(`Spawn error for command "${command}": ${error.message}`); reject(new Error(`Failed to start command "${command}": ${error.message}`)); }); process.on('close', (code) => { console.error(`Command "${command}" exited with code ${code}`); // Added for debugging resolve({ stdout, stderr, code }); }); }); }
  • Helper to sanitize input options against SAFE_OPTION_REGEX to prevent command injection, used in runJtR to validate rawOptions.
    const SAFE_OPTION_REGEX = /^(?:-[a-zA-Z0-9]+|--[a-zA-Z0-9\-]+(?:=[^;&|`$\s\(\)\<\>\\]+)?|[^;&|`$\s\(\)\<\>\\]+)$/; function sanitizeOptions(options: string[]): string[] { const sanitized: string[] = []; for (const opt of options) { if (SAFE_OPTION_REGEX.test(opt)) { sanitized.push(opt); } else { throw new Error(`Invalid or potentially unsafe option detected: "${opt}". Only standard flags and simple arguments are allowed.`); } } return sanitized; }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DMontgomery40/pentest-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server