Skip to main content
Glama

runJohnTheRipper

Crack password hashes using John the Ripper to test security and recover credentials during 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 that implements the 'runJohnTheRipper' tool logic: sanitizes options, writes hashes to temp file, spawns 'john' for cracking and '--show' to retrieve results, parses cracked passwords, handles cleanup and logging.
    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) and options (optional array). Includes description and 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 schema, thin async handler wrapper that calls runJtR and formats MCP response content with results or error.
    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 spawn external commands (like 'john'), capture stdout/stderr/code, with error handling. Used by runJtR for executing john and john --show.
    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/validate command-line options against SAFE_OPTION_REGEX to prevent injection. Used by runJtR to secure options passed to john.
    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; }

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