Date: 2025-12-21 Version: 3.0 - Workflow-Centric Optimization Status: Implementation Ready
After analyzing the Lame machine writeup, I've identified key gaps between the current agent workflow and real-world penetration testing methodology. This plan focuses on optimizing the agent's decision-making process, exploitation chain, and vulnerability validation workflow.
The Lame writeup demonstrates a systematic penetration testing workflow:
- Reconnaissance Phase: Port scanning → Service identification → Version detection
- Vulnerability Research Phase: CVE lookup → Exploit database search → PoC validation
- Exploitation Phase: Tool selection → Exploit execution → Fallback strategy
- Verification Phase: Shell access → Privilege confirmation → Flag retrieval
Critical Gap: Current agent lacks the adaptive decision-making and fallback strategy demonstrated in the writeup (FTP exploit failed → moved to SMB).
1. nmap_port_scan
2. nmap_service_detection
3. directory_bruteforce
4. searchsploit
5. metasploit_check
6. generate_report
Problems:
- ❌ No adaptive branching based on findings
- ❌ No prioritization of high-value targets
- ❌ No fallback when exploits fail
- ❌ No interactive verification
- ❌ Fixed tool sequence regardless of target
1. Reconnaissance
├─ Port scan (nmap -p-)
├─ Service detection (nmap -sV -sC)
└─ Initial profiling
2. Target Analysis
├─ Identify high-value services (FTP, SMB, SSH)
├─ Prioritize by exploit availability
└─ Build attack plan
3. Vulnerability Research (Per Service)
├─ CVE lookup for exact version
├─ searchsploit query
├─ Check PoC database
└─ Verify exploit compatibility
4. Exploitation (Iterative)
├─ Attempt exploit #1 (e.g., vsftpd 2.3.4 backdoor)
├─ Verify success/failure
├─ If failed → Attempt exploit #2 (e.g., Samba usermap_script)
├─ If failed → Try alternative approach
└─ Continue until successful or exhausted
5. Post-Exploitation
├─ Verify shell access
├─ Check privileges (uid=0?)
├─ Capture flags
└─ Document proof
Problem: Agent cannot adapt to findings or handle exploit failures.
Solution: Implement a state-based workflow orchestrator that makes decisions based on reconnaissance results.
// File: src/workflow/adaptive-orchestrator.ts
interface WorkflowState {
phase: 'reconnaissance' | 'research' | 'exploitation' | 'post_exploit' | 'completed'
target: string
findings: {
ports: Array<{ port: number; service: string; version: string }>
vulnerabilities: Array<{ cve: string; service: string; severity: string }>
}
attemptedExploits: string[]
exploitResults: Array<{ exploit: string; success: boolean; notes: string }>
shellObtained: boolean
privilegeLevel: 'root' | 'user' | 'none'
}
export class AdaptiveWorkflowOrchestrator {
private state: WorkflowState
async execute(target: string, scanType: string): Promise<void> {
this.state = this.initializeState(target)
// Phase 1: Reconnaissance
await this.runReconnaissancePhase()
// Phase 2: Vulnerability Research (per service)
const attackPlan = await this.buildAttackPlan()
// Phase 3: Exploitation (iterative with fallback)
await this.runExploitationPhase(attackPlan)
// Phase 4: Post-Exploitation
if (this.state.shellObtained) {
await this.runPostExploitationPhase()
}
// Phase 5: Report Generation
await this.generateReport()
}
private async runReconnaissancePhase(): Promise<void> {
console.log('[+] Phase 1: Reconnaissance')
// Step 1: Port discovery
const portScan = await this.executeTool('nmap_port_scan', {
target: this.state.target,
scan_type: 'all_ports'
})
this.state.findings.ports = portScan.open_ports
// Step 2: Service detection (parallel for each port)
const serviceScans = await this.executeToolsParallel(
this.state.findings.ports.map(port => ({
tool: 'nmap_service_detection',
input: { target: this.state.target, port: port.port }
}))
)
// Update findings with service details
serviceScans.forEach((result, idx) => {
this.state.findings.ports[idx].service = result.service
this.state.findings.ports[idx].version = result.version
})
console.log(`[+] Found ${this.state.findings.ports.length} open ports`)
this.state.phase = 'research'
}
private async buildAttackPlan(): Promise<AttackPlan[]> {
console.log('[+] Phase 2: Building Attack Plan')
const attackPlans: AttackPlan[] = []
// For each service, research vulnerabilities
for (const port of this.state.findings.ports) {
const { service, version } = port
// Skip if no version detected
if (!version || version === 'unknown') continue
// Search for CVEs
const cveResults = await this.searchVulnerabilities(service, version)
// Search exploit-db
const exploitDbResults = await this.executeTool('search_exploitdb', {
query: `${service} ${version}`
})
// Search PoC database (NEW)
const pocResults = await this.executeTool('search_poc_by_software', {
software: service,
version: version
})
// Combine and prioritize
const exploits = this.prioritizeExploits([
...cveResults,
...exploitDbResults.results,
...pocResults.pocs
])
attackPlans.push({
port: port.port,
service: service,
version: version,
exploits: exploits,
priority: this.calculatePriority(service, exploits)
})
}
// Sort by priority (highest first)
return attackPlans.sort((a, b) => b.priority - a.priority)
}
private async runExploitationPhase(attackPlans: AttackPlan[]): Promise<void> {
console.log('[+] Phase 3: Exploitation')
// Iterate through attack plans in priority order
for (const plan of attackPlans) {
console.log(`[*] Targeting ${plan.service} ${plan.version} on port ${plan.port}`)
// Try each exploit until one succeeds
for (const exploit of plan.exploits) {
console.log(`[*] Attempting exploit: ${exploit.name} (${exploit.cve || 'N/A'})`)
// Track attempt
this.state.attemptedExploits.push(exploit.name)
// Execute exploit
const result = await this.attemptExploit(exploit, plan)
// Record result
this.state.exploitResults.push({
exploit: exploit.name,
success: result.success,
notes: result.notes
})
// Check if shell obtained
if (result.success && result.shellObtained) {
console.log('[+] Exploit successful! Shell obtained.')
this.state.shellObtained = true
this.state.privilegeLevel = result.privilegeLevel || 'user'
return // Exit exploitation phase
} else {
console.log(`[-] Exploit failed: ${result.notes}`)
console.log('[*] Moving to next exploit...')
}
}
}
console.log('[-] All exploits exhausted. No shell obtained.')
}
private async attemptExploit(exploit: Exploit, plan: AttackPlan): Promise<ExploitResult> {
// Determine exploit method
if (exploit.metasploit_module) {
return await this.attemptMetasploitExploit(exploit, plan)
} else if (exploit.poc_code) {
return await this.attemptPoCExploit(exploit, plan)
} else if (exploit.manual_steps) {
return await this.attemptManualExploit(exploit, plan)
} else {
return {
success: false,
notes: 'No exploit method available'
}
}
}
private async attemptMetasploitExploit(exploit: Exploit, plan: AttackPlan): Promise<ExploitResult> {
const result = await this.executeTool('metasploit_check_exploit', {
module: exploit.metasploit_module,
target: this.state.target,
port: plan.port,
lhost: await this.getLocalIP()
})
// Parse Metasploit output to determine success
const success = this.parseMetasploitResult(result.output)
return {
success: success,
shellObtained: success && result.output.includes('session'),
privilegeLevel: this.extractPrivilegeLevel(result.output),
notes: result.output
}
}
private async runPostExploitationPhase(): Promise<void> {
console.log('[+] Phase 4: Post-Exploitation')
// Verify shell access
const idResult = await this.executeShellCommand('id')
console.log(`[+] Current user: ${idResult}`)
// Extract privilege level
if (idResult.includes('uid=0(root)')) {
this.state.privilegeLevel = 'root'
console.log('[+] Root access obtained!')
} else {
this.state.privilegeLevel = 'user'
console.log('[*] User-level access obtained')
}
// Attempt privilege escalation if not root
if (this.state.privilegeLevel !== 'root') {
await this.attemptPrivilegeEscalation()
}
// Capture flags
await this.captureFlags()
}
private calculatePriority(service: string, exploits: Exploit[]): number {
let priority = 0
// High-value services
const highValueServices = ['ftp', 'ssh', 'smb', 'samba', 'mysql', 'postgresql']
if (highValueServices.some(s => service.toLowerCase().includes(s))) {
priority += 50
}
// Exploit availability
priority += exploits.length * 10
// CVSS score (if available)
const maxCvss = Math.max(...exploits.map(e => e.cvss_score || 0))
priority += maxCvss * 5
// Known RCE exploits
if (exploits.some(e => e.exploit_type === 'RCE')) {
priority += 30
}
return priority
}
private prioritizeExploits(exploits: any[]): Exploit[] {
return exploits
.map(e => this.normalizeExploit(e))
.sort((a, b) => {
// Sort by: RCE > privilege > CVSS > date
if (a.exploit_type === 'RCE' && b.exploit_type !== 'RCE') return -1
if (b.exploit_type === 'RCE' && a.exploit_type !== 'RCE') return 1
return (b.cvss_score || 0) - (a.cvss_score || 0)
})
}
}
interface AttackPlan {
port: number
service: string
version: string
exploits: Exploit[]
priority: number
}
interface Exploit {
name: string
cve?: string
cvss_score?: number
exploit_type: string
metasploit_module?: string
poc_code?: string
manual_steps?: string
}
interface ExploitResult {
success: boolean
shellObtained?: boolean
privilegeLevel?: 'root' | 'user' | 'none'
notes: string
}Problem: Agent uses same workflow for all targets, ignoring service-specific attack vectors.
Solution: Create pre-defined workflow templates for common services.
// File: src/workflow/service-templates.ts
export const SERVICE_WORKFLOWS = {
// FTP Workflow (as seen in Lame)
ftp: {
name: 'FTP Service Assessment',
steps: [
{
name: 'Anonymous Login Check',
tool: 'ftp_anonymous_check',
critical: true
},
{
name: 'FTP Version CVE Lookup',
tool: 'search_cve_by_service',
input: (context: any) => ({
service: 'ftp',
version: context.ftp_version
})
},
{
name: 'Known Backdoor Check',
condition: (context: any) => context.ftp_version === '2.3.4',
tool: 'metasploit_check_exploit',
input: {
module: 'exploit/unix/ftp/vsftpd_234_backdoor'
}
},
{
name: 'FTP Bounce Attack',
tool: 'ftp_bounce_test'
}
]
},
// SMB/Samba Workflow (as seen in Lame)
smb: {
name: 'SMB/Samba Assessment',
steps: [
{
name: 'SMB Enumeration',
tool: 'smb_enum',
critical: true
},
{
name: 'Share Access Check',
tool: 'smb_share_enum',
critical: true
},
{
name: 'Samba Version CVE Lookup',
tool: 'search_cve_by_service',
input: (context: any) => ({
service: 'samba',
version: context.samba_version
})
},
{
name: 'Username Map Script Exploit',
condition: (context: any) => {
const version = context.samba_version
return version >= '3.0.20' && version <= '3.0.25'
},
tool: 'metasploit_check_exploit',
input: {
module: 'exploit/multi/samba/usermap_script'
}
},
{
name: 'SMB Relay Attack',
tool: 'smb_relay_test'
},
{
name: 'EternalBlue Check',
condition: (context: any) => context.os_version?.includes('Windows'),
tool: 'metasploit_check_exploit',
input: {
module: 'exploit/windows/smb/ms17_010_eternalblue'
}
}
]
},
// SSH Workflow
ssh: {
name: 'SSH Service Assessment',
steps: [
{
name: 'SSH Version Detection',
tool: 'ssh_version_detect',
critical: true
},
{
name: 'SSH Configuration Audit',
tool: 'ssh_config_check'
},
{
name: 'Known Vulnerabilities',
tool: 'search_cve_by_service',
input: (context: any) => ({
service: 'openssh',
version: context.ssh_version
})
},
{
name: 'Weak Cipher Check',
tool: 'ssh_cipher_audit'
},
{
name: 'User Enumeration',
tool: 'ssh_user_enum'
}
]
},
// HTTP/HTTPS Workflow
http: {
name: 'Web Application Assessment',
steps: [
{
name: 'Technology Detection',
tool: 'web_tech_detect',
critical: true
},
{
name: 'Directory Enumeration',
tool: 'directory_bruteforce',
critical: true
},
{
name: 'CMS Detection',
tool: 'cms_detect'
},
{
name: 'CMS Version Exploit Search',
condition: (context: any) => context.cms_detected,
tool: 'search_exploitdb',
input: (context: any) => ({
query: `${context.cms_name} ${context.cms_version}`
})
},
{
name: 'SQL Injection Test',
tool: 'sql_injection_test',
input: (context: any) => ({
url: context.base_url,
parameters: context.detected_parameters
})
},
{
name: 'XSS Test',
tool: 'xss_test'
}
]
}
}
export function getWorkflowForService(service: string): ServiceWorkflow | null {
const normalized = service.toLowerCase()
if (normalized.includes('ftp')) return SERVICE_WORKFLOWS.ftp
if (normalized.includes('smb') || normalized.includes('samba')) return SERVICE_WORKFLOWS.smb
if (normalized.includes('ssh')) return SERVICE_WORKFLOWS.ssh
if (normalized.includes('http')) return SERVICE_WORKFLOWS.http
return null
}Problem: Agent doesn't verify exploit success or implement fallback strategies.
Solution: Add exploit verification logic and automatic fallback chain.
// File: src/workflow/exploit-verifier.ts
export class ExploitVerifier {
async verifyExploit(
exploitResult: any,
expectedOutcome: 'shell' | 'file_access' | 'info_disclosure'
): Promise<VerificationResult> {
switch (expectedOutcome) {
case 'shell':
return await this.verifyShellAccess(exploitResult)
case 'file_access':
return await this.verifyFileAccess(exploitResult)
case 'info_disclosure':
return await this.verifyInfoDisclosure(exploitResult)
default:
return { verified: false, reason: 'Unknown outcome type' }
}
}
private async verifyShellAccess(exploitResult: any): Promise<VerificationResult> {
// Check for Metasploit session indicators
if (exploitResult.output?.includes('session')) {
// Attempt to execute 'id' command
const idResult = await this.executeCommand('id')
if (idResult.includes('uid=')) {
return {
verified: true,
privilegeLevel: idResult.includes('uid=0(root)') ? 'root' : 'user',
evidence: idResult
}
}
}
// Check for reverse shell connection
if (exploitResult.output?.includes('command shell session')) {
return {
verified: true,
privilegeLevel: 'unknown',
evidence: exploitResult.output
}
}
return {
verified: false,
reason: 'No shell session established',
evidence: exploitResult.output
}
}
private async executeCommand(command: string): Promise<string> {
// Execute command via established session
// Implementation depends on shell type
return ''
}
}
interface VerificationResult {
verified: boolean
privilegeLevel?: 'root' | 'user' | 'unknown'
evidence?: string
reason?: string
}// File: src/workflow/fallback-strategy.ts
export class FallbackStrategy {
async buildFallbackChain(primaryExploit: Exploit, context: any): Promise<Exploit[]> {
const fallbacks: Exploit[] = []
// Fallback 1: Try alternative exploit for same vulnerability
const alternatives = await this.findAlternativeExploits(primaryExploit.cve)
fallbacks.push(...alternatives)
// Fallback 2: Try different vulnerability for same service
const otherVulns = await this.findOtherServiceVulnerabilities(
context.service,
context.version
)
fallbacks.push(...otherVulns)
// Fallback 3: Try configuration weaknesses
fallbacks.push({
name: 'Default Credentials',
exploit_type: 'auth_bypass',
manual_steps: 'Try common default credentials'
})
// Fallback 4: Try brute force (last resort)
if (context.service.includes('ssh') || context.service.includes('ftp')) {
fallbacks.push({
name: 'Brute Force Attack',
exploit_type: 'brute_force',
manual_steps: 'Limited brute force with common passwords'
})
}
return fallbacks
}
private async findAlternativeExploits(cve: string): Promise<Exploit[]> {
// Search for different PoCs for the same CVE
const pocs = await searchPoCDatabase({ cve_id: cve })
return pocs.filter(poc => poc.verified && poc.success_rate > 0.5)
}
private async findOtherServiceVulnerabilities(service: string, version: string): Promise<Exploit[]> {
// Search for other known vulnerabilities for the service
return await searchExploitDB({
service: service,
version: version,
exclude_tested: true
})
}
}Based on the Lame writeup, we need better integration with:
- searchsploit - Already implemented, but needs version matching
- smbmap - NEW tool needed for SMB enumeration
- smbclient - NEW tool for SMB share access
- FTP client - NEW tool for FTP enumeration
// File: src/mcp/smb-tools-server.ts
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk/mcp-server'
import { z } from 'zod'
import { exec } from 'child_process'
import { promisify } from 'util'
const execAsync = promisify(exec)
export const smbToolsServer = createSdkMcpServer({
name: 'smb-tools',
tools: [
tool({
name: 'smbmap_enum',
description: 'Enumerate SMB shares and permissions using smbmap',
input: z.object({
target: z.string().describe('Target IP address'),
username: z.string().optional().describe('Username for authentication'),
password: z.string().optional().describe('Password for authentication')
}),
execute: async ({ target, username, password }) => {
const authArgs = username
? `-u "${username}" ${password ? `-p "${password}"` : ''}`
: ''
const command = `smbmap -H ${target} ${authArgs}`
try {
const { stdout, stderr } = await execAsync(command, { timeout: 30000 })
return {
success: true,
shares: parseSmbMapOutput(stdout),
raw_output: stdout
}
} catch (error: any) {
return {
success: false,
error: error.message,
raw_output: error.stdout || ''
}
}
}
}),
tool({
name: 'smbclient_connect',
description: 'Connect to SMB share and list contents',
input: z.object({
target: z.string(),
share: z.string(),
anonymous: z.boolean().default(true),
username: z.string().optional(),
password: z.string().optional()
}),
execute: async ({ target, share, anonymous, username, password }) => {
const authFlag = anonymous ? '-N' : `-U "${username}%${password}"`
const command = `smbclient ${authFlag} //${target}/${share} -c "ls"`
try {
const { stdout } = await execAsync(command, { timeout: 30000 })
return {
success: true,
files: parseSmbClientOutput(stdout),
raw_output: stdout
}
} catch (error: any) {
return {
success: false,
error: error.message
}
}
}
})
]
})
function parseSmbMapOutput(output: string): Share[] {
const shares: Share[] = []
const lines = output.split('\n')
for (const line of lines) {
const match = line.match(/^\s+(\S+)\s+(READ|WRITE|NO ACCESS|READ, WRITE)/)
if (match) {
shares.push({
name: match[1],
permissions: match[2],
accessible: !match[2].includes('NO ACCESS')
})
}
}
return shares
}
interface Share {
name: string
permissions: string
accessible: boolean
}// File: src/mcp/ftp-tools-server.ts
export const ftpToolsServer = createSdkMcpServer({
name: 'ftp-tools',
tools: [
tool({
name: 'ftp_anonymous_check',
description: 'Test if FTP allows anonymous login',
input: z.object({
target: z.string()
}),
execute: async ({ target }) => {
// Use ftp client to test anonymous access
const command = `ftp -n ${target} <<EOF
user anonymous anonymous
ls
quit
EOF`
try {
const { stdout } = await execAsync(command, { timeout: 30000 })
const anonymousAllowed = stdout.includes('Login successful') ||
stdout.includes('230')
return {
anonymous_allowed: anonymousAllowed,
files_listed: anonymousAllowed ? parseFtpListing(stdout) : [],
raw_output: stdout
}
} catch (error: any) {
return {
anonymous_allowed: false,
error: error.message
}
}
}
})
]
})Update the main agent prompt to follow the real-world workflow demonstrated in Lame.
// File: src/prompts/pentest-methodology.ts
export const PENTEST_METHODOLOGY_PROMPT = `
You are an expert penetration tester performing an authorized security audit.
METHODOLOGY (follow this exact workflow):
PHASE 1: RECONNAISSANCE
1. Perform comprehensive port scan (all ports)
2. Detect services and versions on open ports
3. Identify target OS and platform
4. Build initial target profile
PHASE 2: VULNERABILITY RESEARCH (per service)
For EACH discovered service:
1. Research known CVEs for the EXACT version
2. Search exploit-db for available exploits
3. Check PoC database for verified exploits
4. Prioritize by: RCE > Privilege Escalation > Info Disclosure
PHASE 3: EXPLOITATION (iterative with fallback)
For EACH vulnerability (in priority order):
1. Select most reliable exploit (PoC success rate > 70%)
2. Attempt exploitation
3. VERIFY success (check for shell, command execution, etc.)
4. If FAILED:
- Log failure reason
- Move to next exploit in fallback chain
- Continue until successful OR all exploits exhausted
CRITICAL RULES:
- NEVER assume exploit worked - ALWAYS verify
- If exploit fails, move to fallback immediately
- Track all attempted exploits to avoid repetition
- Prioritize services by exploitability (FTP, SMB > SSH)
- Use Metasploit modules when available
PHASE 4: POST-EXPLOITATION (if shell obtained)
1. Execute 'id' command to verify privileges
2. If not root, attempt privilege escalation
3. Capture flags (/home/*/user.txt, /root/root.txt)
4. Document proof of exploitation
EXAMPLE WORKFLOW (from Lame machine):
1. nmap scan → Found FTP (vsftpd 2.3.4), SSH, SMB (Samba 3.0.20)
2. Research vsftpd 2.3.4 → Found CVE-2011-2523 (backdoor)
3. Attempted exploit/unix/ftp/vsftpd_234_backdoor → FAILED
4. Moved to SMB → Research Samba 3.0.20 → Found CVE-2007-2447
5. Attempted exploit/multi/samba/usermap_script → SUCCESS
6. Verified: uid=0(root) → Root shell obtained
7. Captured flags
Apply this methodology to the target: {target}
`- Implement
AdaptiveWorkflowOrchestratorclass - Create state management system
- Add exploit verification logic
- Implement fallback strategy builder
- Update main agent to use new orchestrator
- Create service workflow templates (FTP, SMB, SSH, HTTP)
- Implement template engine
- Add conditional execution logic
- Test with Lame machine scenario
- Implement SMB tools MCP server (smbmap, smbclient)
- Implement FTP tools MCP server
- Add exploit result parsers
- Update existing tools with better output parsing
- Create PoC database schema (from original plan)
- Implement PoC database MCP server
- Seed database with common exploits (vsftpd, Samba, etc.)
- Integrate PoC lookup into workflow
- Create adaptive prompt templates
- Implement context-aware prompt generation
- Add exploit guidance prompts
- Test prompt effectiveness
- Test against Lame machine (validation)
- Test against 10 HTB easy machines
- Benchmark performance improvements
- Optimize based on results
- ✅ Agent successfully exploits Lame machine (vsftpd → Samba fallback)
- ✅ Exploit verification catches false positives
- ✅ Fallback chain activates when primary exploit fails
- ✅ Service-specific workflows applied correctly
| Metric | Current | Target | Notes |
|---|---|---|---|
| Exploit Success Rate | ~40% | >80% | With fallback chains |
| False Positive Rate | ~30% | <5% | With verification |
| Avg. Time to Exploit | 20 min | 10 min | With parallel execution |
| Services Covered | 4 | 10+ | FTP, SMB, SSH, HTTP, etc. |
- Report accuracy: >95%
- Exploit verification: 100% (never assume success)
- Fallback activation: Automatic when exploit fails
- Documentation completeness: All steps logged
- ✅ Parallel execution
- ✅ ML-powered predictions
- ✅ Extensive tool coverage
- 🎯 Adaptive decision-making (higher priority)
- 🎯 Exploit verification (critical gap)
- 🎯 Fallback strategies (essential for real pentesting)
- 🎯 Service-specific workflows (better targeting)
The Lame writeup shows that workflow intelligence matters more than tool quantity:
- Human pentester tried FTP exploit → failed → moved to SMB
- This requires decision-making, not just parallel execution
- Current agent would stop after first failure
- New agent will implement systematic fallback chain
- Review this plan - Validate approach aligns with goals
- Prioritize features - Which phase to implement first?
- Setup testing environment - Deploy Lame machine for validation
- Begin Phase 1 - Implement adaptive workflow orchestrator
Recommendation: Start with Phase 1 (Core Workflow Engine) as it provides the biggest impact with lowest complexity.