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;
    }
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Tool has no description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Tool has no description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Tool has no description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Tool has no description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

Tool has no description.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Tool has no description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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