index.ts•13.9 kB
#!/usr/bin/env node
/**
* Cobalt Strike MCP Server
* Model Context Protocol server for managing Cobalt Strike operations
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from '@modelcontextprotocol/sdk/types.js';
import { CobaltStrikeClient } from './api/client.js';
import { ConfigManager } from './config/index.js';
import { createBeaconTools, handleBeaconTool } from './tools/beacon.js';
import { createListenerTools, handleListenerTool } from './tools/listener.js';
import { createServerTools, handleServerTool } from './tools/server.js';
import { createCredentialsTools, handleCredentialsTool } from './tools/credentials.js';
import { createTaskTools, handleTaskTool } from './tools/tasks.js';
import { createFileTools, handleFileTool } from './tools/files.js';
import { createSpawnTools, handleSpawnTool } from './tools/spawn.js';
import { createBOFTools, handleBOFTool } from './tools/bof.js';
import { createPayloadTools, handlePayloadTool } from './tools/payloads.js';
import { createDataTools, handleDataTool } from './tools/data.js';
import { createStateTools, handleStateTool } from './tools/state.js';
import { createInjectTools, handleInjectTool } from './tools/inject.js';
import { createTokenTools, handleTokenTool } from './tools/tokens.js';
import { createExecuteTools, handleExecuteTool } from './tools/execute.js';
import { createPivotingTools, handlePivotingTool } from './tools/pivoting.js';
import { createConfigTools, handleConfigTool } from './tools/config.js';
import { createElevateTools, handleElevateTool } from './tools/elevate.js';
import { createRemoteExecTools, handleRemoteExecTool } from './tools/remoteexec.js';
import { createListenerSpecificTools, handleListenerSpecificTool } from './tools/listeners-specific.js';
import { createUtilityTools, handleUtilityTool } from './tools/utilities.js';
import * as readline from 'readline';
let client: CobaltStrikeClient | null = null;
/**
* Initialize the Cobalt Strike client
*/
async function initializeClient(): Promise<void> {
const config = await ConfigManager.loadConfig();
if (!config) {
throw new Error(
'Configuration not found. Please set up the configuration first.\n' +
'Run: cobaltstrike-mcp --setup'
);
}
client = new CobaltStrikeClient(config);
// Test connection (non-fatal - server will start even if connection fails)
// Tools will handle connection errors when they're called
try {
const connected = await client.testConnection();
if (!connected) {
console.error('Warning: Failed to connect to Cobalt Strike REST API. Server will start but tools may fail.');
console.error('Please check your configuration or ensure the teamserver is running.');
}
} catch (error) {
console.error('Warning: Could not test connection to Cobalt Strike REST API:', (error as Error).message);
console.error('Server will start but tools may fail until connection is established.');
}
}
/**
* Setup configuration interactively
*/
async function setupConfig(): Promise<void> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const question = (prompt: string): Promise<string> => {
return new Promise((resolve) => {
rl.question(prompt, resolve);
});
};
// Cross-platform password input
// Note: On Windows, password will be visible. On Unix-like systems, it will be hidden.
const questionPassword = async (prompt: string): Promise<string> => {
// Simple approach: use readline but warn on Windows
// For better security, consider using a library like 'readline-sync' or 'inquirer'
if (process.platform === 'win32') {
console.log('⚠️ Warning: Password will be visible as you type on Windows.');
console.log(' Consider running this in a private terminal or use environment variables.\n');
}
return new Promise((resolve) => {
rl.question(prompt, (answer) => {
resolve(answer);
});
});
};
try {
console.log('Cobalt Strike MCP Server Setup\n');
console.log('Enter your Cobalt Strike REST API configuration:\n');
const url = await question('Teamserver URL (e.g., https://teamserver.example.com:50050): ');
const username = await question('Username: ');
// Note: On Windows, password will be visible as you type
if (process.platform === 'win32') {
console.log('Note: On Windows, password input will be visible. Press Enter when done.');
}
const password = await questionPassword('Password: ');
const verifySSLStr = await question('Verify SSL certificates? (yes/no, default: yes): ');
const verifySSL = verifySSLStr.toLowerCase() !== 'no';
await ConfigManager.saveConfig({
url: url.trim(),
username: username.trim(),
password: password.trim(),
verifySSL,
});
console.log('\nConfiguration saved successfully!');
} finally {
rl.close();
}
}
/**
* Main server implementation
*/
async function main() {
// Handle command line arguments
const args = process.argv.slice(2);
if (args.includes('--setup') || args.includes('--setup-keyring')) {
await setupConfig();
process.exit(0);
}
// Initialize client
try {
await initializeClient();
} catch (error) {
// Only exit if configuration is missing - connection failures are non-fatal
const errorMessage = (error as Error).message;
if (errorMessage.includes('Configuration not found')) {
console.error(`Error: ${errorMessage}`);
process.exit(1);
} else {
// For other errors, log but continue - server can start without connection
console.error(`Warning: ${errorMessage}`);
console.error('Server will start but tools may fail until connection is established.');
}
}
if (!client) {
console.error('Error: Client not initialized. Configuration may be missing.');
console.error('Run: cobaltstrike-mcp --setup');
process.exit(1);
}
// Create MCP server
const server = new Server(
{
name: 'cobaltstrike-mcp',
version: '0.1.0',
},
{
capabilities: {
tools: {},
},
}
);
// Register tool handlers
server.setRequestHandler(ListToolsRequestSchema, async () => {
const tools: Tool[] = [
...createServerTools(client!),
...createBeaconTools(client!),
...createListenerTools(client!),
...createCredentialsTools(client!),
...createTaskTools(client!),
...createFileTools(client!),
...createSpawnTools(client!),
...createBOFTools(client!),
...createPayloadTools(client!),
...createDataTools(client!),
...createStateTools(client!),
...createInjectTools(client!),
...createTokenTools(client!),
...createExecuteTools(client!),
...createPivotingTools(client!),
...createConfigTools(client!),
...createElevateTools(client!),
...createRemoteExecTools(client!),
...createListenerSpecificTools(client!),
...createUtilityTools(client!),
];
return { tools };
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
let result: string;
// Route to appropriate tool handler
// Check specific tools first before general patterns
if (name.startsWith('get_teamserver_info') || name.startsWith('test_connection')) {
result = await handleServerTool(name, args, client!);
} else if (name.startsWith('get_beacon_jobs') || name.startsWith('get_beacon_c2_host_profiles') || name.startsWith('get_beacon_tokenStore')) {
result = await handleStateTool(name, args, client!);
} else if (name.startsWith('get_beacon_tasks_summary') || name.startsWith('get_beacon_tasks_detail')) {
result = await handleTaskTool(name, args, client!);
} else if (name.startsWith('list_beacons') || name.startsWith('get_beacon') ||
name.startsWith('execute_beacon') || name.startsWith('kill_beacon') ||
name.startsWith('note_beacon')) {
result = await handleBeaconTool(name, args, client!);
} else if (name.startsWith('list_listeners') || name.startsWith('create_listener') ||
name.startsWith('delete_listener')) {
result = await handleListenerTool(name, args, client!);
} else if (name.startsWith('list_credentials') || name.startsWith('get_credential') ||
name.startsWith('create_credential') || name.startsWith('delete_credential')) {
result = await handleCredentialsTool(name, args, client!);
} else if (name.startsWith('list_tasks') || name.startsWith('get_task')) {
result = await handleTaskTool(name, args, client!);
} else if (name.startsWith('beacon_')) {
result = await handleFileTool(name, args, client!);
} else if (name.startsWith('execute_bof')) {
result = await handleBOFTool(name, args, client!);
} else if (name.startsWith('spawn_')) {
result = await handleSpawnTool(name, args, client!);
} else if (name.startsWith('get_listener') && !name.includes('_http') && !name.includes('_https') && !name.includes('_dns') && !name.includes('_smb') && !name.includes('_tcp') && !name.includes('_externalC2') && !name.includes('_foreign') && !name.includes('_userDefined')) {
result = await handleListenerSpecificTool(name, args, client!);
} else if (name.startsWith('generate_') || name.startsWith('download_payload')) {
result = await handlePayloadTool(name, args, client!);
} else if (name.startsWith('list_') && (name.includes('screenshot') || name.includes('keystroke') || name.includes('download'))) {
result = await handleDataTool(name, args, client!);
} else if (name.startsWith('get_') && (name.includes('screenshot') || name.includes('keystroke') || name.includes('download'))) {
result = await handleDataTool(name, args, client!);
} else if (name.startsWith('set_beacon_')) {
result = await handleStateTool(name, args, client!);
} else if (name.startsWith('inject_')) {
result = await handleInjectTool(name, args, client!);
} else if (name.startsWith('execute_steal_token') || name.startsWith('execute_make_token') ||
name.startsWith('execute_rev2self') || name.startsWith('execute_get_system') ||
name.startsWith('execute_get_privs') || name.startsWith('execute_tokenStore') ||
name.startsWith('execute_make_token_upn')) {
result = await handleTokenTool(name, args, client!);
} else if (name.startsWith('execute_kill_process') || name.startsWith('execute_clipboard') ||
name.startsWith('execute_setenv') || name.startsWith('execute_timestomp') ||
name.startsWith('execute_checkin') || name.startsWith('execute_exit') ||
name.startsWith('execute_reg_') || name.startsWith('execute_beacon_info') ||
name.startsWith('execute_get_uid') || name.startsWith('execute_job_stop') ||
name.startsWith('execute_kerberos_') || name.startsWith('execute_powershell_import') ||
name.startsWith('execute_net_domain') || name.startsWith('execute_browserpivot_stop') ||
name.startsWith('execute_cancel_file_download') || name.startsWith('execute_socks_stop')) {
result = await handleExecuteTool(name, args, client!);
} else if (name.startsWith('execute_socks') || name.startsWith('execute_link') ||
name.startsWith('execute_unlink') || name.startsWith('execute_rportfwd')) {
result = await handlePivotingTool(name, args, client!);
} else if (name.startsWith('get_system_information') || name.startsWith('get_profile') ||
name.startsWith('update_profile') || name.startsWith('get_killdate') ||
name.startsWith('set_killdate') || name.startsWith('get_teamserver_ip') ||
name.startsWith('set_teamserver_ip') || name.startsWith('reset_data')) {
result = await handleConfigTool(name, args, client!);
} else if (name.startsWith('elevate_')) {
result = await handleElevateTool(name, args, client!);
} else if (name.startsWith('remoteExec_')) {
result = await handleRemoteExecTool(name, args, client!);
} else if (name.startsWith('create_listener_') || name.startsWith('get_listener_') ||
name.startsWith('update_listener_') || name.startsWith('delete_listener_')) {
result = await handleListenerSpecificTool(name, args, client!);
} else if (name.startsWith('get_artifacts') || name.startsWith('get_beacon_active_downloads') ||
name.startsWith('clear_beacon_command_queue') || name.startsWith('get_beacon_help') ||
name.startsWith('get_beacon_command_help') || name.startsWith('get_beacon_keystrokes')) {
result = await handleUtilityTool(name, args, client!);
} else {
throw new Error(`Unknown tool: ${name}`);
}
return {
content: [
{
type: 'text',
text: result,
},
],
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error: ${(error as Error).message}`,
},
],
isError: true,
};
}
});
// Connect stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Cobalt Strike MCP server running on stdio');
}
// Run the server
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});