Skip to main content
Glama

MCP Pentest

burpsuite-integration.ts•15.7 kB
import { exec, spawn, ChildProcess } from 'child_process'; import { promisify } from 'util'; import { ScanResult } from './recon.js'; import axios from 'axios'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; const execAsync = promisify(exec); export interface BurpSuiteConfig { jar_path?: string; project_file?: string; api_port?: number; proxy_port?: number; headless?: boolean; user_options?: string; memory?: string; } export interface BurpScanResult { scan_id: string; status: string; issue_count: number; issues: BurpIssue[]; scan_metrics: { requests_made: number; responses_received: number; scan_duration: number; }; } export interface BurpIssue { serial_number: string; type: number; name: string; host: string; path: string; location: string; severity: string; confidence: string; issue_background: string; remediation_background: string; issue_detail: string; evidence: BurpEvidence[]; } export interface BurpEvidence { request_response: { request: string; response: string; was_redirect_followed: boolean; }; } export interface ProxyHistoryEntry { host: string; port: number; protocol: string; method: string; url: string; path: string; extension: string; request: string; response: string; status: number; length: number; mime_type: string; comment: string; } export class BurpSuiteIntegration { private burpProcess: ChildProcess | null = null; private config: BurpSuiteConfig; private apiBaseUrl: string; constructor(config: Partial<BurpSuiteConfig> = {}) { this.config = { jar_path: config.jar_path || this.findBurpJar(), project_file: config.project_file, api_port: config.api_port || 1337, proxy_port: config.proxy_port || 8080, headless: config.headless !== false, // Default to headless user_options: config.user_options || '', memory: config.memory || '2g', ...config }; this.apiBaseUrl = `http://127.0.0.1:${this.config.api_port}`; } // Start Burp Suite with API enabled async startBurpSuite(): Promise<ScanResult> { try { console.error('šŸš€ Starting Burp Suite...'); if (!this.config.jar_path || !fs.existsSync(this.config.jar_path)) { throw new Error('Burp Suite JAR file not found. Please install Burp Suite Professional and set jar_path'); } // Prepare user options file for headless mode let userOptionsFile = ''; if (this.config.headless) { userOptionsFile = await this.createUserOptionsFile(); } // Build command const javaArgs = [ `-Xmx${this.config.memory}`, '-Djava.awt.headless=true', '-jar', this.config.jar_path, '--disable-extensions', `--collaborator-server`, `--collaborator-location-all` ]; if (this.config.headless) { javaArgs.push('--unpause-spider-and-scanner'); javaArgs.push(`--user-config-file=${userOptionsFile}`); } if (this.config.project_file) { javaArgs.push(`--project-file=${this.config.project_file}`); } console.error(`Executing: java ${javaArgs.join(' ')}`); // Spawn Burp Suite process this.burpProcess = spawn('java', javaArgs, { stdio: ['ignore', 'pipe', 'pipe'], detached: false }); // Wait for Burp to start up await this.waitForBurpStartup(); return { target: 'burpsuite', timestamp: new Date().toISOString(), tool: 'burpsuite_startup', results: { status: 'started', pid: this.burpProcess.pid, api_url: this.apiBaseUrl, proxy_port: this.config.proxy_port, config: this.config }, status: 'success' }; } catch (error) { return { target: 'burpsuite', timestamp: new Date().toISOString(), tool: 'burpsuite_startup', results: {}, status: 'error', error: error instanceof Error ? error.message : String(error) }; } } // Stop Burp Suite async stopBurpSuite(): Promise<ScanResult> { try { console.error('šŸ›‘ Stopping Burp Suite...'); if (this.burpProcess) { this.burpProcess.kill('SIGTERM'); this.burpProcess = null; } return { target: 'burpsuite', timestamp: new Date().toISOString(), tool: 'burpsuite_shutdown', results: { status: 'stopped' }, status: 'success' }; } catch (error) { return { target: 'burpsuite', timestamp: new Date().toISOString(), tool: 'burpsuite_shutdown', results: {}, status: 'error', error: error instanceof Error ? error.message : String(error) }; } } // Perform active scan on target async activeScan(target: string, scope?: string[]): Promise<ScanResult> { try { console.error(`šŸ” Starting Burp Suite active scan on ${target}`); // Check if Burp is running await this.checkBurpStatus(); // Send target to scope if specified if (scope) { await this.setScope(scope); } // Start spider first const spiderResult = await this.spiderTarget(target); // Start active scan const scanResponse = await axios.post(`${this.apiBaseUrl}/v0.1/scan`, { urls: [target] }); const scanId = scanResponse.data.task_id; console.error(`Scan started with ID: ${scanId}`); // Wait for scan completion or timeout const scanResult = await this.waitForScanCompletion(scanId, 1800000); // 30 min timeout // Get scan results const issues = await this.getScanIssues(scanId); return { target, timestamp: new Date().toISOString(), tool: 'burpsuite_active_scan', results: { scan_id: scanId, spider_results: spiderResult, scan_status: scanResult.status, issue_count: issues.length, issues: issues, severity_breakdown: this.categorizeBySeverity(issues) }, status: 'success' }; } catch (error) { return { target, timestamp: new Date().toISOString(), tool: 'burpsuite_active_scan', results: {}, status: 'error', error: error instanceof Error ? error.message : String(error) }; } } // Perform passive scan through proxy async proxyScan(target: string, duration: number = 300): Promise<ScanResult> { try { console.error(`šŸ” Starting Burp Suite proxy scan on ${target} for ${duration} seconds`); // Check if Burp is running await this.checkBurpStatus(); // Configure proxy const proxyConfig = { http_proxy: `http://127.0.0.1:${this.config.proxy_port}`, https_proxy: `http://127.0.0.1:${this.config.proxy_port}` }; // Send some requests through proxy to generate traffic await this.generateProxyTraffic(target, duration); // Get proxy history const proxyHistory = await this.getProxyHistory(); // Get passive scan issues const issues = await this.getPassiveIssues(); return { target, timestamp: new Date().toISOString(), tool: 'burpsuite_proxy_scan', results: { proxy_config: proxyConfig, scan_duration: duration, requests_captured: proxyHistory.length, issue_count: issues.length, issues: issues, proxy_history: proxyHistory.slice(0, 50), // Limit output severity_breakdown: this.categorizeBySeverity(issues) }, status: 'success' }; } catch (error) { return { target, timestamp: new Date().toISOString(), tool: 'burpsuite_proxy_scan', results: {}, status: 'error', error: error instanceof Error ? error.message : String(error) }; } } // Perform crawl/spider of target async spiderTarget(target: string): Promise<any> { try { console.error(`šŸ•·ļø Spidering target: ${target}`); const spiderResponse = await axios.post(`${this.apiBaseUrl}/v0.1/spider`, { base_url: target }); const spiderTaskId = spiderResponse.data.task_id; // Wait for spider completion await this.waitForTaskCompletion(spiderTaskId, 600000); // 10 min timeout // Get spider results const spiderResults = await axios.get(`${this.apiBaseUrl}/v0.1/spider/${spiderTaskId}`); return { task_id: spiderTaskId, status: spiderResults.data.status, urls_found: spiderResults.data.urls || [] }; } catch (error) { console.error('Spider failed:', error); return { error: error instanceof Error ? error.message : String(error) }; } } // Export scan results async exportResults(format: 'xml' | 'html' | 'json' = 'xml', outputPath?: string): Promise<ScanResult> { try { console.error(`šŸ“„ Exporting Burp results in ${format} format`); const exportResponse = await axios.get(`${this.apiBaseUrl}/v0.1/scan/report`, { params: { format } }); const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const filename = outputPath || `burp-report-${timestamp}.${format}`; fs.writeFileSync(filename, exportResponse.data); return { target: 'export', timestamp: new Date().toISOString(), tool: 'burpsuite_export', results: { export_format: format, output_file: filename, file_size: fs.statSync(filename).size }, status: 'success' }; } catch (error) { return { target: 'export', timestamp: new Date().toISOString(), tool: 'burpsuite_export', results: {}, status: 'error', error: error instanceof Error ? error.message : String(error) }; } } // Private helper methods private findBurpJar(): string { const commonPaths = [ '/opt/burpsuite_pro/burpsuite_pro.jar', '/Applications/Burp Suite Professional.app/Contents/java/app/burpsuite_pro.jar', path.join(os.homedir(), 'BurpSuitePro', 'burpsuite_pro.jar'), path.join(os.homedir(), 'Downloads', 'burpsuite_pro.jar'), './burpsuite_pro.jar' ]; for (const jarPath of commonPaths) { if (fs.existsSync(jarPath)) { return jarPath; } } return ''; } private async createUserOptionsFile(): Promise<string> { const userOptions = { "suite": { "extensions": { "extensions": [] } }, "proxy": { "intercept_requests": false, "intercept_responses": false }, "scanner": { "live_scanning": { "live_audit": true, "live_passive_crawl": true } } }; const tempFile = path.join(os.tmpdir(), `burp-user-options-${Date.now()}.json`); fs.writeFileSync(tempFile, JSON.stringify(userOptions, null, 2)); return tempFile; } private async waitForBurpStartup(): Promise<void> { const maxAttempts = 60; // 5 minutes let attempts = 0; while (attempts < maxAttempts) { try { await axios.get(`${this.apiBaseUrl}/v0.1/`, { timeout: 5000 }); console.error('āœ… Burp Suite API is ready'); return; } catch (error) { attempts++; console.error(`Waiting for Burp startup... (${attempts}/${maxAttempts})`); await new Promise(resolve => setTimeout(resolve, 5000)); } } throw new Error('Burp Suite failed to start within timeout period'); } private async checkBurpStatus(): Promise<void> { try { await axios.get(`${this.apiBaseUrl}/v0.1/`, { timeout: 5000 }); } catch (error) { throw new Error('Burp Suite is not running or API is not accessible'); } } private async setScope(scope: string[]): Promise<void> { try { await axios.put(`${this.apiBaseUrl}/v0.1/scope`, { include: scope.map(url => ({ url, enabled: true })), exclude: [] }); } catch (error) { console.error('Failed to set scope:', error); } } private async waitForScanCompletion(scanId: string, timeout: number): Promise<any> { const startTime = Date.now(); while (Date.now() - startTime < timeout) { try { const response = await axios.get(`${this.apiBaseUrl}/v0.1/scan/${scanId}`); const status = response.data.status; if (status === 'finished' || status === 'failed') { return response.data; } console.error(`Scan ${scanId} status: ${status}`); await new Promise(resolve => setTimeout(resolve, 30000)); // Check every 30 seconds } catch (error) { console.error('Error checking scan status:', error); await new Promise(resolve => setTimeout(resolve, 30000)); } } throw new Error('Scan timeout exceeded'); } private async waitForTaskCompletion(taskId: string, timeout: number): Promise<any> { const startTime = Date.now(); while (Date.now() - startTime < timeout) { try { const response = await axios.get(`${this.apiBaseUrl}/v0.1/task/${taskId}`); const status = response.data.status; if (status === 'finished' || status === 'failed') { return response.data; } await new Promise(resolve => setTimeout(resolve, 10000)); // Check every 10 seconds } catch (error) { console.error('Error checking task status:', error); await new Promise(resolve => setTimeout(resolve, 10000)); } } throw new Error('Task timeout exceeded'); } private async getScanIssues(scanId?: string): Promise<BurpIssue[]> { try { const endpoint = scanId ? `/v0.1/scan/${scanId}/issues` : '/v0.1/issues'; const response = await axios.get(`${this.apiBaseUrl}${endpoint}`); return response.data.issues || []; } catch (error) { console.error('Failed to get scan issues:', error); return []; } } private async getPassiveIssues(): Promise<BurpIssue[]> { try { const response = await axios.get(`${this.apiBaseUrl}/v0.1/issues`); return response.data.issues || []; } catch (error) { console.error('Failed to get passive issues:', error); return []; } } private async getProxyHistory(): Promise<ProxyHistoryEntry[]> { try { const response = await axios.get(`${this.apiBaseUrl}/v0.1/proxy/history`); return response.data.history || []; } catch (error) { console.error('Failed to get proxy history:', error); return []; } } private async generateProxyTraffic(target: string, duration: number): Promise<void> { // Use curl or similar tool to generate traffic through Burp proxy const proxyUrl = `http://127.0.0.1:${this.config.proxy_port}`; try { // Basic crawling through proxy const command = `curl -x ${proxyUrl} -k -s "${target}" > /dev/null`; await execAsync(command, { timeout: duration * 1000 }); } catch (error) { console.error('Error generating proxy traffic:', error); } } private categorizeBySeverity(issues: BurpIssue[]): Record<string, number> { const categories = { high: 0, medium: 0, low: 0, info: 0 }; issues.forEach(issue => { const severity = issue.severity.toLowerCase(); if (severity in categories) { categories[severity as keyof typeof categories]++; } }); return categories; } }

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/adriyansyah-mf/mcp-pentest'

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